:p
atchew
Login
Hi; here's hopefully the last pullreq for arm before softfreeze. There's a mix here of bug fixes of various kinds plus support for emulation of a few new CPU features. thanks -- PMM The following changes since commit 4ee536fac748b70e6f3d8568ddd20cfbaa9cf7bf: Merge tag 'firmware-20260704-pull-request' of https://gitlab.com/kraxel/qemu into staging (2026-07-05 08:42:47 +0200) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260706 for you to fetch changes up to 3455eac92d3e4b70bc222d98268f092efd4f1934: target/arm: Define fields for NSACR (2026-07-06 11:32:01 +0100) ---------------------------------------------------------------- target-arm queue: * hw/net/fsl_etsec: validate FCB offsets in process_tx_fcb() * hw/arm/smmuv3-accel: Fix veventq read returning true on EAGAIN/EINTR * target/arm: Only evaluate SCR_EL3.PIEN if ARM_FEATURE_EL3 is present * hw/arm: use cortex-a9 mpcore base for CBAR on npcm7xx machines * docs/specs/fw_cfg: Document all architecture register layouts * hw/nvram/fw_cfg: Simplify functions so board models don't have the opportunity to create non-standard fw_cfg register layouts * hw/misc: use tracepoints rather than DPRINTF in imx ccm models * hw/arm: add support for shim loading * docs/system/arm: Document Zynq Buildroot boot * target/arm: Report correct syndrome to AArch32 EL2 for trapped Neon/VFP insns * target/arm: implement WFET to not be a NOP * target/arm: Emulate FEAT_SME_MOP4 * target/arm: Emulate FEAT_FPRCVT * target/arm: Emulate FEAT_SSVE_FEXPA ---------------------------------------------------------------- Alex Bennée (7): hw/arm: use cortex-a9 mpcore base for CBAR on npcm7xx machines tests/functional: update anacapa-bmc image target/arm: do not clear halting reason in has_work helper target/arm: ensure we create the wxft_timer for all modes target/arm: implements SEV/SEVL for all modes target/arm: enable WFE sleeping for A-profile target/arm: implement WFET Bin Meng (1): docs/system/arm: Document Zynq Buildroot boot Feifan Qian (1): hw/net/fsl_etsec: validate FCB offsets in process_tx_fcb() Gerd Hoffmann (3): hw/nvram: add load_image_to_fw_cfg_file() hw/i386: switch shim loading to load_image_to_fw_cfg_file hw/arm: add support for shim loading Jason Wright (1): target/arm/hvf: seed NO_RAW ID registers from isar.idregs[] on vCPU init Jim MacArthur (6): target/arm/tcg: Implement new instructions for FPRCVT target/arm/tcg: Allow vector FP conversions with FPRCVT target/arm/tcg/cpu64.c: Add FEAT_FPRCVT to cpu_max linux-user/aarch64/elfload.c: Add FPRCVT docs/system/arm: Add FEAT_FPRCVT to A-profile support tests/tcg/arm: Tests for new FPRCVT instructions Oliver Upton (1): target/arm: Only evaluate SCR_EL3.PIEN if ARM_FEATURE_EL3 is present Peter Maydell (10): docs/specs/fw_cfg: Document all architecture register layouts hw/nvram/fw_cfg: Enforce standard layout for fw_cfg_init_mem_dma() hw/nvram/fw_cfg: Enforce standard layout for x86 fw_cfg I/O ports hw/nvram/fw_cfg: Remove support for I/O port fw_cfg without DMA hw/nvram/fw_cfg: Document fw_cfg_init_mem_nodma() hw/misc/imx31_ccm: Replace DPRINTF with trace events target/arm: Separate out Neon from VFP access checks target/arm: Separate syndrome functions for A32 and A64 target/arm: Report correct syndrome to AArch32 EL2 for trapped Neon/VFP insns target/arm: Define fields for NSACR Richard Henderson (16): target/arm: Implement and enable FEAT_SSVE_FEXPA for -cpu max target/arm: Implement FMOP4 (non-widening) for float32 target/arm: Implement FMOP4 (non-widening) for float16 target/arm: Implement FMOP4 (non-widening) for float64 target/arm: Implement BFMOP4 (non-widening) target/arm: Implement BFMOP4 (widening) target/arm: Implement FMOP4 (widening, 2-way fp16 to fp32) target/arm: Implement FMOP4 (widening, 4-way fp8 to fp32) target/arm: Implement FMOP4A (widening, 2-way, FP8 to FP16) target/arm: Implement SMOP4[AS] (2-way) target/arm: Implement SMOP4[AS] (4-way) target/arm: Implement SUMOP4[AS] target/arm: Implement UMOP4[AS] (2-way) target/arm: Implement UMOP4[AS] (4-way) target/arm: Implement USMOP4[AS] target/arm: Enable FEAT_SME_MOP4 for -cpu max Shameer Kolothum (1): hw/arm/smmuv3-accel: Fix veventq read returning true on EAGAIN/EINTR jack wang (2): hw/misc/imx_ccm: Replace DPRINTF with trace events hw/misc/imx25_ccm: Replace DPRINTF with trace events docs/specs/fw_cfg.rst | 28 +- docs/system/arm/emulation.rst | 3 + docs/system/arm/xlnx-zynq.rst | 54 +++- hw/arm/boot.c | 6 + hw/arm/npcm7xx.c | 2 +- hw/arm/smmuv3-accel-stubs.c | 6 +- hw/arm/smmuv3-accel.c | 30 ++- hw/arm/smmuv3-accel.h | 4 +- hw/arm/tegra241-cmdqv.c | 11 +- hw/arm/virt.c | 2 +- hw/i386/fw_cfg.c | 3 +- hw/i386/microvm.c | 3 +- hw/i386/pc.c | 3 +- hw/i386/x86-common.c | 15 +- hw/loongarch/fw_cfg.c | 3 +- hw/misc/imx25_ccm.c | 32 +-- hw/misc/imx31_ccm.c | 33 +-- hw/misc/imx_ccm.c | 18 +- hw/misc/trace-events | 23 ++ hw/net/fsl_etsec/rings.c | 27 +- hw/nvram/fw_cfg.c | 44 +++- hw/riscv/virt.c | 3 +- include/hw/arm/boot.h | 1 + include/hw/core/sysemu-cpu-ops.h | 3 + include/hw/nvram/fw_cfg.h | 73 +++++- linux-user/aarch64/elfload.c | 3 + target/arm/cpu-features.h | 45 ++++ target/arm/cpu.c | 25 +- target/arm/cpu.h | 2 +- target/arm/helper.c | 10 +- target/arm/hvf/hvf.c | 10 +- target/arm/hvf/sysreg.c.inc | 2 +- target/arm/internals.h | 8 + target/arm/ptw.c | 9 +- target/arm/syndrome.h | 28 +- target/arm/tcg/a32.decode | 5 +- target/arm/tcg/a64.decode | 20 +- target/arm/tcg/cpu64.c | 3 + target/arm/tcg/fp8_helper.c | 32 +++ target/arm/tcg/helper-defs.h | 3 +- target/arm/tcg/helper-fp8-defs.h | 3 + target/arm/tcg/helper-sme-defs.h | 49 ++++ target/arm/tcg/op_helper.c | 258 ++++++++++++++++-- target/arm/tcg/sme.decode | 45 ++++ target/arm/tcg/sme_helper.c | 390 ++++++++++++++++++++++++++++ target/arm/tcg/t16.decode | 4 +- target/arm/tcg/t32.decode | 4 +- target/arm/tcg/translate-a32.h | 1 + target/arm/tcg/translate-a64.c | 139 +++++++--- target/arm/tcg/translate-neon.c | 74 +++--- target/arm/tcg/translate-sme.c | 130 ++++++++++ target/arm/tcg/translate-sve.c | 21 +- target/arm/tcg/translate-vfp.c | 60 +++-- target/arm/tcg/translate.c | 34 +-- target/arm/tcg/translate.h | 23 ++ target/arm/tcg/vec_internal.h | 8 + tests/functional/arm/test_aspeed_anacapa.py | 4 +- tests/tcg/aarch64/Makefile.target | 14 +- tests/tcg/arm/fcvt.c | 7 + 59 files changed, 1576 insertions(+), 327 deletions(-)
From: Feifan Qian <bea1e@proton.me> The TX Frame Control Block (FCB) is prepended to a TX frame when BD_TX_TOEUN is set. It contains two guest-controlled u8 offset fields that process_tx_fcb() uses to locate L3/L4 headers within the frame buffer: l3_header_offset = FCB byte 3 (0..255) l4_header_offset = FCB byte 2 (0..255) These offsets are applied without any bounds check. When the UDP-no-CTU branch is taken, the function writes zero to l4_header[6] and l4_header[7]. With both offsets set to 0xFF the write target is: tx_buffer + 8 + 255 + 255 + 6/7 = tx_buffer + 525 A malicious guest can therefore corrupt up to 509 bytes of heap memory beyond a minimally-sized (16 B) TX frame. Fix: reject the frame and log a guest error when the minimum required buffer length 8 (FCB) + l3_header_offset + l4_header_offset + 8 exceeds tx_buffer_len. Move the l3_header and l4_header pointer declarations past the new guard so that out-of-bounds pointers are never materialised. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3517 Signed-off-by: Feifan Qian <bea1e@proton.me> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/net/fsl_etsec/rings.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index XXXXXXX..XXXXXXX 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -XXX,XX +XXX,XX @@ static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len) static void process_tx_fcb(eTSEC *etsec) { uint8_t flags = (uint8_t)(*etsec->tx_buffer); - /* L3 header offset from start of frame */ + /* L3 header offset from start of frame (FCB byte 3) */ uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3); - /* L4 header offset from start of L3 header */ + /* L4 header offset from start of L3 header (FCB byte 2) */ uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2); - /* L3 header */ - uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset; - /* L4 header */ - uint8_t *l4_header = l3_header + l4_header_offset; + uint8_t *l3_header; + uint8_t *l4_header; int csum = 0; + /* + * Validate FCB header offsets before pointer arithmetic. The highest + * byte accessed is l4_header[7], at offset + * 8 (FCB size) + l3_header_offset + l4_header_offset + 7 + * from tx_buffer. Drop the frame if this exceeds the buffer length. + */ + if (etsec->tx_buffer_len < 8u + l3_header_offset + l4_header_offset + 8u) { + qemu_log_mask(LOG_GUEST_ERROR, + "eTSEC: FCB offsets exceed frame length, dropping\n"); + return; + } + + /* L3 header */ + l3_header = etsec->tx_buffer + 8 + l3_header_offset; + /* L4 header */ + l4_header = l3_header + l4_header_offset; + /* if packet is IP4 and IP checksum is requested */ if (flags & FCB_TX_IP && flags & FCB_TX_CIP) { csum |= CSUM_IP; -- 2.43.0
From: Shameer Kolothum <skolothumtho@nvidia.com> smmuv3_accel_event_read_validate() returns true for EAGAIN/EINTR, but no data has been read into the buffer. Callers treat true as success and proceed to use the uninitialized buffer. Change the return type to int with three distinct states: 0 — success, buf is populated and valid 1 — EAGAIN/EINTR, no data available -1 — error, @errp set Resolves: Coverity CID 1660057 Fixes: d4aea0f75b ("hw/arm/smmuv3-accel: Introduce common helper for veventq read") Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260625122843.107584-1-skolothumtho@nvidia.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/smmuv3-accel-stubs.c | 6 +++--- hw/arm/smmuv3-accel.c | 30 ++++++++++++++++++++---------- hw/arm/smmuv3-accel.h | 4 ++-- hw/arm/tegra241-cmdqv.c | 11 ++++++++--- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/hw/arm/smmuv3-accel-stubs.c b/hw/arm/smmuv3-accel-stubs.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/smmuv3-accel-stubs.c +++ b/hw/arm/smmuv3-accel-stubs.c @@ -XXX,XX +XXX,XX @@ bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp) return true; } -bool smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, - void *buf, size_t size, Error **errp) +int smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, + void *buf, size_t size, Error **errp) { - return true; + return 0; } diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/smmuv3-accel.c +++ b/hw/arm/smmuv3-accel.c @@ -XXX,XX +XXX,XX @@ bool smmuv3_accel_issue_inv_cmd(SMMUv3State *bs, void *cmd, SMMUDevice *sdev, sizeof(Cmd), &entry_num, cmd, errp); } -bool smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, - void *buf, size_t size, Error **errp) +/* + * Returns 0 on success (buf is populated and valid). + * Returns 1 if the read should be retried (EAGAIN/EINTR). + * Returns -1 on error with @errp set. + */ +int smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, + void *buf, size_t size, Error **errp) { uint32_t last_seq = veventq->last_event_seq; uint32_t id = veventq->veventq_id; @@ -XXX,XX +XXX,XX @@ bool smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, bytes = read(veventq->veventq_fd, buf, size); if (bytes <= 0) { if (errno == EAGAIN || errno == EINTR) { - return true; + return 1; } error_setg(errp, "vEVENTQ(type %u id %u): read failed (%m)", type, id); - return false; + return -1; } hdr = (struct iommufd_vevent_header *)buf; if (bytes == sizeof(*hdr) && (hdr->flags & IOMMU_VEVENTQ_FLAG_LOST_EVENTS)) { error_setg(errp, "vEVENTQ(type %u id %u): overflowed", type, id); veventq->event_start = false; - return false; + return -1; } if (bytes < size) { error_setg(errp, "vEVENTQ(type %u id %u): short read(%zd/%zd bytes)", type, id, bytes, size); - return false; + return -1; } /* Check sequence in hdr for lost events if any */ if (veventq->event_start && (hdr->sequence - last_seq != 1)) { @@ -XXX,XX +XXX,XX @@ bool smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, } veventq->last_event_seq = hdr->sequence; veventq->event_start = true; - return true; + return 0; } static void smmuv3_accel_event_read(void *opaque) @@ -XXX,XX +XXX,XX @@ static void smmuv3_accel_event_read(void *opaque) struct iommu_vevent_arm_smmuv3 vevent; } buf; Error *local_err = NULL; + int ret; - if (!smmuv3_accel_event_read_validate(veventq, - IOMMU_VEVENTQ_TYPE_ARM_SMMUV3, &buf, - sizeof(buf), &local_err)) { + ret = smmuv3_accel_event_read_validate(veventq, + IOMMU_VEVENTQ_TYPE_ARM_SMMUV3, &buf, + sizeof(buf), &local_err); + if (ret < 0) { warn_report_err_once(local_err); return; } + if (ret > 0) { + return; /* EAGAIN/EINTR */ + } smmuv3_propagate_event(s, (Evt *)&buf.vevent); } diff --git a/hw/arm/smmuv3-accel.h b/hw/arm/smmuv3-accel.h index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/smmuv3-accel.h +++ b/hw/arm/smmuv3-accel.h @@ -XXX,XX +XXX,XX @@ bool smmuv3_accel_issue_inv_cmd(SMMUv3State *s, void *cmd, SMMUDevice *sdev, Error **errp); void smmuv3_accel_idr_override(SMMUv3State *s); bool smmuv3_accel_alloc_veventq(SMMUv3State *s, Error **errp); -bool smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, - void *buf, size_t size, Error **errp); +int smmuv3_accel_event_read_validate(IOMMUFDVeventq *veventq, uint32_t type, + void *buf, size_t size, Error **errp); void smmuv3_accel_reset(SMMUv3State *s); SMMUv3AccelCmdqvType smmuv3_accel_cmdqv_type(Object *obj); diff --git a/hw/arm/tegra241-cmdqv.c b/hw/arm/tegra241-cmdqv.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/tegra241-cmdqv.c +++ b/hw/arm/tegra241-cmdqv.c @@ -XXX,XX +XXX,XX @@ static void tegra241_cmdqv_event_read(void *opaque) struct iommu_vevent_tegra241_cmdqv vevent; } buf; Error *local_err = NULL; + int ret; - if (!smmuv3_accel_event_read_validate(veventq, - IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV, - &buf, sizeof(buf), &local_err)) { + ret = smmuv3_accel_event_read_validate(veventq, + IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV, + &buf, sizeof(buf), &local_err); + if (ret < 0) { warn_report_err_once(local_err); return; } + if (ret > 0) { + return; /* EAGAIN/EINTR */ + } if (buf.vevent.lvcmdq_err_map[0] || buf.vevent.lvcmdq_err_map[1]) { cmdqv->vintf_cmdq_err_map[0] = -- 2.43.0
From: Oliver Upton <oupton@kernel.org> Running KVM with (as of writing, out-of-tree) support for FEAT_S2PIE on -cpu max gets stuck in an infinite loop of stage-2 permission faults due to the PTW incorrectly using an effective value of 0 for S2PIR_EL2. Similar to how S1PIE is handled, only use the IMPLEMENTATION SPECIFIC value of 0 for S2PIR_EL2 if EL3 is implemented and PIEN=0. Cc: qemu-stable@nongnu.org Fixes: a811c5dafb ("target/arm: Implement get_S2prot_indirect") Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Oliver Upton <oupton@kernel.org> Message-id: 20260626231738.947317-1-oupton@kernel.org [PMM: removed hardcoded tab] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/ptw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -XXX,XX +XXX,XX @@ static int get_S2prot_indirect(CPUARMState *env, GetPhysAddrResult *result, PAGE_READ | PAGE_WRITE }, }; - uint64_t pir = (env->cp15.scr_el3 & SCR_PIEN ? env->cp15.s2pir_el2 : 0); - int s2pi = extract64(pir, pi_index * 4, 4); + uint64_t pir = env->cp15.s2pir_el2; + int s2pi; + if (arm_feature(env, ARM_FEATURE_EL3) && !(env->cp15.scr_el3 & SCR_PIEN)) { + pir = 0; + } + + s2pi = extract64(pir, pi_index * 4, 4); result->f.prot = perm_table[s2pi][2]; return perm_table[s2pi][s1_is_el0]; } -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> Adds the opcode format for the SIMD versions of FCVTXX and [US]CVTF. These use very similar logic to the FP-to-general and general-to-FP register versions which exist, but use another SIMD/FP register as source or destination. The source and destination size rules are slightly different. Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-1-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++ target/arm/tcg/a64.decode | 15 +++++++ target/arm/tcg/translate-a64.c | 77 +++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 24 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8mm4(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8MM4); } +static inline bool isar_feature_aa64_fprcvt(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64ISAR3, FPRCVT); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FCVTZU_g . 0011110 .. 111001 000000 ..... ..... @icvt FCVTAS_g . 0011110 .. 100100 000000 ..... ..... @icvt FCVTAU_g . 0011110 .. 100101 000000 ..... ..... @icvt +# Conversion between floating-point and integer (SIMD & FP) +SCVTF_simd . 0011110 .. 111100 000000 ..... ..... @icvt +UCVTF_simd . 0011110 .. 111101 000000 ..... ..... @icvt + +FCVTAS_g_simd . 0011110 .. 111010 000000 ..... ..... @icvt +FCVTAU_g_simd . 0011110 .. 111011 000000 ..... ..... @icvt +FCVTMS_g_simd . 0011110 .. 110100 000000 ..... ..... @icvt +FCVTMU_g_simd . 0011110 .. 110101 000000 ..... ..... @icvt +FCVTNS_g_simd . 0011110 .. 101010 000000 ..... ..... @icvt +FCVTNU_g_simd . 0011110 .. 101011 000000 ..... ..... @icvt +FCVTPS_g_simd . 0011110 .. 110010 000000 ..... ..... @icvt +FCVTPU_g_simd . 0011110 .. 110011 000000 ..... ..... @icvt +FCVTZS_g_simd . 0011110 .. 110110 000000 ..... ..... @icvt +FCVTZU_g_simd . 0011110 .. 110111 000000 ..... ..... @icvt + FJCVTZS 0 0011110 01 111110 000000 ..... ..... @rr FMOV_ws 0 0011110 00 100110 000000 ..... ..... @rr diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS(SCVTF_g, do_cvtf_g, a, true) TRANS(UCVTF_g, do_cvtf_g, a, false) /* - * [US]CVTF (vector), scalar version. - * Which sounds weird, but really just means input from fp register + * [US]CVTF (vector), scalar or SIMD version. + * Which sounds weird, but really just means input from FP/SIMD register * instead of input from general register. Input and output element - * size are always equal. + * size are always equal for the scalar version and different for the + * SIMD version. */ -static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed) +static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, MemOp src_mop_int, + bool is_signed) { TCGv_i64 tcg_int; int check = fp_access_check_scalar_hsd(s, a->esz); @@ -XXX,XX +XXX,XX @@ static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed) if (check <= 0) { return check == 0; } - tcg_int = tcg_temp_new_i64(); - read_vec_element(s, tcg_int, a->rn, 0, a->esz | (is_signed ? MO_SIGN : 0)); + read_vec_element(s, tcg_int, a->rn, 0, + src_mop_int | (is_signed ? MO_SIGN : 0)); return do_cvtf_scalar(s, a->esz, a->rd, a->shift, tcg_int, is_signed); } -TRANS(SCVTF_f, do_cvtf_f, a, true) -TRANS(UCVTF_f, do_cvtf_f, a, false) +TRANS(SCVTF_f, do_cvtf_f, a, a->esz, true) +TRANS(UCVTF_f, do_cvtf_f, a, a->esz, false) +TRANS_FEAT(SCVTF_simd, aa64_fprcvt, do_cvtf_f, a, + a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(UCVTF_simd, aa64_fprcvt, do_cvtf_f, a, + a->sf ? MO_64 : MO_32, false) static void do_fcvt_scalar(DisasContext *s, MemOp out, MemOp esz, TCGv_i64 tcg_out, int shift, int rn, @@ -XXX,XX +XXX,XX @@ static bool do_fcvt_g(DisasContext *s, arg_fcvt *a, return true; } + TRANS(FCVTNS_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, true) TRANS(FCVTNU_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, false) TRANS(FCVTPS_g, do_fcvt_g, a, FPROUNDING_POSINF, true) @@ -XXX,XX +XXX,XX @@ TRANS(FCVTAS_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, true) TRANS(FCVTAU_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, false) /* - * FCVT* (vector), scalar version. - * Which sounds weird, but really just means output to fp register + * FCVT* (vector), scalar or SIMD/FP version. + * Which sounds weird, but really just means output to fp or SIMD register * instead of output to general register. Input and output element - * size are always equal. + * size are always equal for the scalar version and different for the + * SIMD version. */ static bool do_fcvt_f(DisasContext *s, arg_fcvt *a, - ARMFPRounding rmode, bool is_signed) + ARMFPRounding rmode, MemOp dst_mop_int, bool is_signed) { TCGv_i64 tcg_int; int check = fp_access_check_scalar_hsd(s, a->esz); @@ -XXX,XX +XXX,XX @@ static bool do_fcvt_f(DisasContext *s, arg_fcvt *a, } tcg_int = tcg_temp_new_i64(); - do_fcvt_scalar(s, a->esz | (is_signed ? MO_SIGN : 0), + do_fcvt_scalar(s, dst_mop_int | (is_signed ? MO_SIGN : 0), a->esz, tcg_int, a->shift, a->rn, rmode); if (!s->fpcr_nep) { clear_vec(s, a->rd); } - write_vec_element(s, tcg_int, a->rd, 0, a->esz); + write_vec_element(s, tcg_int, a->rd, 0, dst_mop_int); return true; } -TRANS(FCVTNS_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, true) -TRANS(FCVTNU_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, false) -TRANS(FCVTPS_f, do_fcvt_f, a, FPROUNDING_POSINF, true) -TRANS(FCVTPU_f, do_fcvt_f, a, FPROUNDING_POSINF, false) -TRANS(FCVTMS_f, do_fcvt_f, a, FPROUNDING_NEGINF, true) -TRANS(FCVTMU_f, do_fcvt_f, a, FPROUNDING_NEGINF, false) -TRANS(FCVTZS_f, do_fcvt_f, a, FPROUNDING_ZERO, true) -TRANS(FCVTZU_f, do_fcvt_f, a, FPROUNDING_ZERO, false) -TRANS(FCVTAS_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, true) -TRANS(FCVTAU_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, false) +TRANS(FCVTNS_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, a->esz, true) +TRANS(FCVTNU_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, a->esz, false) +TRANS(FCVTPS_f, do_fcvt_f, a, FPROUNDING_POSINF, a->esz, true) +TRANS(FCVTPU_f, do_fcvt_f, a, FPROUNDING_POSINF, a->esz, false) +TRANS(FCVTMS_f, do_fcvt_f, a, FPROUNDING_NEGINF, a->esz, true) +TRANS(FCVTMU_f, do_fcvt_f, a, FPROUNDING_NEGINF, a->esz, false) +TRANS(FCVTZS_f, do_fcvt_f, a, FPROUNDING_ZERO, a->esz, true) +TRANS(FCVTZU_f, do_fcvt_f, a, FPROUNDING_ZERO, a->esz, false) +TRANS(FCVTAS_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, a->esz, true) +TRANS(FCVTAU_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, a->esz, false) + +TRANS_FEAT(FCVTNS_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_TIEEVEN, a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(FCVTNU_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_TIEEVEN, a->sf ? MO_64 : MO_32, false) +TRANS_FEAT(FCVTPS_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_POSINF, a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(FCVTPU_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_POSINF, a->sf ? MO_64 : MO_32, false) +TRANS_FEAT(FCVTMS_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_NEGINF, a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(FCVTMU_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_NEGINF, a->sf ? MO_64 : MO_32, false) +TRANS_FEAT(FCVTZS_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_ZERO, a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(FCVTZU_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_ZERO, a->sf ? MO_64 : MO_32, false) +TRANS_FEAT(FCVTAS_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_TIEAWAY, a->sf ? MO_64 : MO_32, true) +TRANS_FEAT(FCVTAU_g_simd, aa64_fprcvt, do_fcvt_f, a, + FPROUNDING_TIEAWAY, a->sf ? MO_64 : MO_32, false) static bool trans_FJCVTZS(DisasContext *s, arg_FJCVTZS *a) { -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> FEAT_FPRCVT allows the vector forms of FCVTXX and [US]CVTF in streaming mode which would otherwise only be available in nonstreaming mode. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-2-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, MemOp src_mop_int, bool is_signed) { TCGv_i64 tcg_int; - int check = fp_access_check_scalar_hsd(s, a->esz); + int check; + + /* FEAT_FPRCVT allows vector forms in streaming mode */ + if (dc_isar_feature(aa64_fprcvt, s)) { + s->is_nonstreaming = false; + } + + check = fp_access_check_scalar_hsd(s, a->esz); if (check <= 0) { return check == 0; @@ -XXX,XX +XXX,XX @@ static bool do_fcvt_f(DisasContext *s, arg_fcvt *a, ARMFPRounding rmode, MemOp dst_mop_int, bool is_signed) { TCGv_i64 tcg_int; - int check = fp_access_check_scalar_hsd(s, a->esz); + int check; + + /* FEAT_FPRCVT allows vector forms in streaming mode */ + if (dc_isar_feature(aa64_fprcvt, s)) { + s->is_nonstreaming = false; + } + + check = fp_access_check_scalar_hsd(s, a->esz); if (check <= 0) { return check == 0; -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-3-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/cpu64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64ISAR3); t = FIELD_DP64(t, ID_AA64ISAR3, FAMINMAX, 1); /* FEAT_FAMINMAX */ + t = FIELD_DP64(t, ID_AA64ISAR3, FPRCVT, 1); /* FEAT_FPRCVT */ SET_IDREG(isar, ID_AA64ISAR3, t); t = GET_IDREG(isar, ID_AA64PFR0); -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-4-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- linux-user/aarch64/elfload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_f8mm8, ARM_HWCAP_A64_F8MM8); GET_FEATURE_ID(aa64_f8mm4, ARM_HWCAP_A64_F8MM4); GET_FEATURE_ID(aa64_ssve_aes, ARM_HWCAP_A64_SME_AES); + GET_FEATURE_ID(aa64_fprcvt, ARM_HWCAP_A64_FPRCVT); return hwcaps; } -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-5-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_FPACCOMBINE (Faulting on combined pointer authentication instructions) - FEAT_FPACC_SPEC (Speculative behavior of combined pointer authentication instructions) - FEAT_FPMR (Floating-point Mode Register) +- FEAT_FPRCVT (Floating-Point to/from Integer in Scalar FP register) - FEAT_FRINTTS (Floating-point to integer instructions) - FEAT_FlagM (Flag manipulation instructions v2) - FEAT_FlagM2 (Enhancements to flag manipulation instructions) -- 2.43.0
From: Jim MacArthur <jim.macarthur@linaro.org> We autodetect the presence of FPRCVT in the test cross compiler, which is a recent feature in GCC and not supported by many distros yet. If this is in place, we compile the existing fcvt.c test with an extra compiler flag which uses the new SIMD instructions; the output from the test is unchanged. The existing [US]CVTF instructions do not have a test, so no new tests are added for the SIMD versions. They have been tested manually to check the new SIMD versions produce the same numerical results as the existing versions. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-6-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/tcg/aarch64/Makefile.target | 14 +++++++++++++- tests/tcg/arm/fcvt.c | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -XXX,XX +XXX,XX @@ config-cc.mak: Makefile $(call cc-option,-march=armv8.5-a, CROSS_CC_HAS_ARMV8_5); \ $(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \ $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE); \ - $(call cc-option,-Wa$(COMMA)-march=armv9-a+sme $$fnia, CROSS_AS_HAS_ARMV9_SME)) 3> config-cc.mak + $(call cc-option,-Wa$(COMMA)-march=armv9-a+sme $$fnia, CROSS_AS_HAS_ARMV9_SME); \ + $(call cc-option,-march=armv9-a+fprcvt, CROSS_CC_HAS_ARMV9_FPRCVT)) 3> config-cc.mak -include config-cc.mak +ifneq ($(CROSS_CC_HAS_ARMV9_FPRCVT),) +AARCH64_TESTS += fcvt-fprcvt +fcvt-fprcvt: LDFLAGS += -lm +fcvt-fprcvt: CFLAGS += $(CROSS_CC_HAS_ARMV9_FPRCVT) -DFPRCVT +fcvt-fprcvt: fcvt.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) +run-fcvt-fprcvt: fcvt-fprcvt + $(call run-test,$<,$(QEMU) $<) + $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) +endif + ifneq ($(CROSS_CC_HAS_ARMV8_2),) AARCH64_TESTS += dcpop dcpop: CFLAGS += $(CROSS_CC_HAS_ARMV8_2) diff --git a/tests/tcg/arm/fcvt.c b/tests/tcg/arm/fcvt.c index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/arm/fcvt.c +++ b/tests/tcg/arm/fcvt.c @@ -XXX,XX +XXX,XX @@ static void convert_single_to_integer(void) #if defined(__arm__) /* asm("vcvt.s32.f32 %s0, %s1" : "=t" (output) : "t" (input)); */ output = input; +#else +#ifdef FPRCVT + asm("fcvtzs d0, %s1\r\n" + "fmov %0, d0" : + "=r" (output) : "w" (input)); #else asm("fcvtzs %0, %s1" : "=r" (output) : "w" (input)); +#endif #endif print_int64(i, output); } @@ -XXX,XX +XXX,XX @@ int main(int argc, char *argv[argc]) convert_double_to_integer(); convert_half_to_integer(); + /* And now with ARM alternative FP16 */ #if defined(__arm__) asm("vmrs r1, fpscr\n\t" -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260626164819.770787-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/cpu-features.h | 5 +++++ target/arm/tcg/cpu64.c | 1 + target/arm/tcg/translate-sve.c | 21 +++++++++++++++------ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) - FEAT_SSVE_AES (Streaming SVE Mode Advanced Encryption Standard and 128-bit polynomial multiply long instructions) +- FEAT_SSVE_FEXPA (Streaming FEXPA instruction) - FEAT_SSVE_FP8DOT2 (SVE2 FP8 2-way dot product to half-precision instructions in Streaming SVE mode) - FEAT_SSVE_FP8DOT4 (SVE2 FP8 4-way dot product to single-precision instructions in Streaming SVE mode) - FEAT_SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_f8mm8, ARM_HWCAP_A64_F8MM8); GET_FEATURE_ID(aa64_f8mm4, ARM_HWCAP_A64_F8MM4); GET_FEATURE_ID(aa64_ssve_aes, ARM_HWCAP_A64_SME_AES); + GET_FEATURE_ID(aa64_ssve_fexpa, ARM_HWCAP_A64_SME_SFEXPA); GET_FEATURE_ID(aa64_fprcvt, ARM_HWCAP_A64_FPRCVT); return hwcaps; diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sve_b16b16(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64ZFR0, B16B16); } +static inline bool isar_feature_aa64_ssve_fexpa(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SFEXPA); +} + static inline bool isar_feature_aa64_ssve_aes(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, AES); diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) SET_IDREG(isar, ID_AA64DFR0, t); t = GET_IDREG(isar, ID_AA64SMFR0); + t = FIELD_DP64(t, ID_AA64SMFR0, SFEXPA, 1); /* FEAT_SSVE_FEXPA */ t = FIELD_DP64(t, ID_AA64SMFR0, AES, 1); /* FEAT_SSVE_AES */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP2, 1); /* FEAT_SSVE_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP4, 1); /* FEAT_SSVE_FP8DOT4 */ diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT_NONSTREAMING(ADR_u32, aa64_sve, do_adr, a, gen_helper_sve_adr_u32) *** SVE Integer Misc - Unpredicated Group */ -static gen_helper_gvec_2 * const fexpa_fns[4] = { - NULL, gen_helper_sve_fexpa_h, - gen_helper_sve_fexpa_s, gen_helper_sve_fexpa_d, -}; -TRANS_FEAT_NONSTREAMING(FEXPA, aa64_sve, gen_gvec_ool_zz, - fexpa_fns[a->esz], a->rd, a->rn, s->fpcr_ah) +static bool trans_FEXPA(DisasContext *s, arg_FEXPA *a) +{ + static gen_helper_gvec_2 * const fexpa_fns[4] = { + NULL, gen_helper_sve_fexpa_h, + gen_helper_sve_fexpa_s, gen_helper_sve_fexpa_d, + }; + + if (!dc_isar_feature(aa64_ssve_fexpa, s)) { + if (!dc_isar_feature(aa64_sve, s)) { + return false; + } + s->is_nonstreaming = true; + } + return gen_gvec_ool_zz(s, fexpa_fns[a->esz], a->rd, a->rn, s->fpcr_ah); +} static gen_helper_gvec_3 * const ftssel_fns[4] = { NULL, gen_helper_sve_ftssel_h, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> CBAR is an IMPDEF register and according to the A9 TRM [1]: In Cortex-A9 MPCore implementations, the base address is reset to PERIPHBASE[31:13] so that software can determine the location of the private memory region [2]. If it doesn't we will confuse the Linux kernel as it probes the system SCU registers [3] and erroneously assumes the system is a buggy Aegis SOC and nerf the emission of SEV instructions, deadlocking any WFE's in the kernel (or QEMU smpboot code). [1] https://developer.arm.com/documentation/ddi0388/i/system-control/register-descriptions/configuration-base-address-register [2] https://developer.arm.com/documentation/ddi0407/g/Introduction/Private-Memory-Region [3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/kernel/head.S?h=v7.1#n550 Fixes: 2d8f048c25ab ("hw/arm: Add NPCM730 and NPCM750 SoC models") Cc: qemu-stable@nongnu.org Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260624103049.884930-2-alex.bennee@linaro.org Suggested-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/npcm7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp) /* CPUs */ for (i = 0; i < nc->num_cpus; i++) { object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", - NPCM7XX_GIC_CPU_IF_ADDR, &error_abort); + NPCM7XX_CPUP_BA, &error_abort); object_property_set_bool(OBJECT(&s->cpu[i]), "reset-hivecs", true, &error_abort); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> The initial version had the wrong DTB which caused issues with image corruption [1]. Update to the latest version. [1] https://github.com/legoater/qemu-aspeed-boot/pull/7 Reviewed-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260624103049.884930-3-alex.bennee@linaro.org Suggested-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/arm/test_aspeed_anacapa.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/arm/test_aspeed_anacapa.py b/tests/functional/arm/test_aspeed_anacapa.py index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/arm/test_aspeed_anacapa.py +++ b/tests/functional/arm/test_aspeed_anacapa.py @@ -XXX,XX +XXX,XX @@ class AnacapaMachine(FacebookAspeedTest): ASSET_ANACAPA_FLASH = Asset( - 'https://github.com/legoater/qemu-aspeed-boot/raw/3fa3212827b04be4034d43b5adeef57c27d6ab18/images/anacapa-bmc/openbmc-20260512025228/obmc-phosphor-image-anacapa-20260512025228.static.mtd.xz', - '2232e241abcfb6d4f6b82cb6c378ce5ce05e364aac6d118785c2b6cc33fe43f3') + 'https://github.com/legoater/qemu-aspeed-boot/raw/refs/heads/master/images/anacapa-bmc/openbmc-20260616025349/obmc-phosphor-image-anacapa-20260616025349.static.mtd.xz', + 'de3841fb6ed3085aec6424358ee6efc4b8ee85688361e5aa1987fd1acb7d3fb4') def test_arm_ast2600_anacapa_openbmc(self): image_path = self.uncompress(self.ASSET_ANACAPA_FLASH) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> The helper will be called multiple times as we exit a loop and until we actually restart (via arm_cpu_exec_halt) we should leave the condition the same. Fixes: 6fd2fcdc61b (target/arm: teach arm_cpu_has_work about halting reasons) Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260624103049.884930-4-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/core/sysemu-cpu-ops.h | 3 +++ target/arm/cpu.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/sysemu-cpu-ops.h +++ b/include/hw/core/sysemu-cpu-ops.h @@ -XXX,XX +XXX,XX @@ typedef struct SysemuCPUOps { /** * @has_work: Callback for checking if there is work to do. + * + * This function should be idempotent (i.e. not change state) as + * it will likely be queried multiple times before a CPU resumes. */ bool (*has_work)(CPUState *cpu); /* MANDATORY NON-NULL */ /** diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static bool arm_cpu_has_work(CPUState *cs) * A wake-up event should only wake us if we are halted on a WFE */ if (cpu->env.halt_reason == HALT_WFE && cpu->env.event_register) { - cpu->env.halt_reason = NOT_HALTED; return true; } @@ -XXX,XX +XXX,XX @@ static bool arm_cpu_has_work(CPUState *cs) | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR | CPU_INTERRUPT_EXITTB)) { - cpu->env.halt_reason = NOT_HALTED; return true; } @@ -XXX,XX +XXX,XX @@ bool arm_cpu_exec_halt(CPUState *cs) if (cpu->wfxt_timer) { timer_del(cpu->wfxt_timer); } + /* clear the halt reason */ + cpu->env.halt_reason = NOT_HALTED; } return leave_halt; } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> We don't want to just use it for timeouts as we will calculate which will comes first. Remove the wxft feature test in favour of the broader architecture checks. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260624103049.884930-5-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 6 +++++- target/arm/cpu.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #ifndef CONFIG_USER_ONLY - if (tcg_enabled() && cpu_isar_feature(aa64_wfxt, cpu)) { + /* + * We use the wfxt_timer for timeouts and event stream so we + * enable from V6K up. There is no event stream on M-profile. + */ + if (tcg_enabled() && arm_feature(env, ARM_FEATURE_V6K)) { cpu->wfxt_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, arm_wfxt_timer_cb, cpu); } diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ struct ArchCPU { * pmu_op_finish() - it does not need other handling during migration */ QEMUTimer *pmu_timer; - /* Timer used for WFxT timeouts */ + /* Timer used for WFxT timeouts OR event stream events */ QEMUTimer *wfxt_timer; /* GPIO outputs for generic timer */ -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Remove the restrictions that make this a M-profile only operation and enable the instructions for all Arm profiles. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260624103049.884930-6-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a32.decode | 5 ++--- target/arm/tcg/a64.decode | 5 ++--- target/arm/tcg/op_helper.c | 4 +--- target/arm/tcg/t16.decode | 4 +--- target/arm/tcg/t32.decode | 4 +--- target/arm/tcg/translate-a64.c | 17 +++++++++++++++++ target/arm/tcg/translate.c | 20 +++++++++++++++++--- target/arm/tcg/translate.h | 18 ++++++++++++++++++ 8 files changed, 59 insertions(+), 18 deletions(-) diff --git a/target/arm/tcg/a32.decode b/target/arm/tcg/a32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a32.decode +++ b/target/arm/tcg/a32.decode @@ -XXX,XX +XXX,XX @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn WFE ---- 0011 0010 0000 1111 ---- 0000 0010 WFI ---- 0011 0010 0000 1111 ---- 0000 0011 - # TODO: Implement SEV, SEVL; may help SMP performance. - # SEV ---- 0011 0010 0000 1111 ---- 0000 0100 - # SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 + SEV ---- 0011 0010 0000 1111 ---- 0000 0100 + SEVL ---- 0011 0010 0000 1111 ---- 0000 0101 ESB ---- 0011 0010 0000 1111 ---- 0001 0000 ] diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ ERETA 1101011 0100 11111 00001 m:1 11111 11111 &reta # ERETAA, ERETAB YIELD 1101 0101 0000 0011 0010 0000 001 11111 WFE 1101 0101 0000 0011 0010 0000 010 11111 WFI 1101 0101 0000 0011 0010 0000 011 11111 - # We implement WFE to never block, so our SEV/SEVL are NOPs - # SEV 1101 0101 0000 0011 0010 0000 100 11111 - # SEVL 1101 0101 0000 0011 0010 0000 101 11111 + SEV 1101 0101 0000 0011 0010 0000 100 11111 + SEVL 1101 0101 0000 0011 0010 0000 101 11111 # Our DGL is a NOP because we don't merge memory accesses anyway. # DGL 1101 0101 0000 0011 0010 0000 110 11111 XPACLRI 1101 0101 0000 0011 0010 0000 111 11111 diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sev)(CPUARMState *env) CPUState *cs = env_cpu(env); CPU_FOREACH(cs) { ARMCPU *target_cpu = ARM_CPU(cs); - if (arm_feature(&target_cpu->env, ARM_FEATURE_M)) { - target_cpu->env.event_register = true; - } + target_cpu->env.event_register = true; if (!qemu_cpu_is_self(cs)) { qemu_cpu_kick(cs); } diff --git a/target/arm/tcg/t16.decode b/target/arm/tcg/t16.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/t16.decode +++ b/target/arm/tcg/t16.decode @@ -XXX,XX +XXX,XX @@ REVSH 1011 1010 11 ... ... @rdm WFE 1011 1111 0010 0000 WFI 1011 1111 0011 0000 - # M-profile SEV is implemented. - # TODO: Implement SEV for other profiles, and SEVL for all profiles; may help SMP performance. SEV 1011 1111 0100 0000 - # SEVL 1011 1111 0101 0000 + SEVL 1011 1111 0101 0000 # The canonical nop has the second nibble as 0000, but the whole of the # rest of the space is a reserved hint, behaves as nop. diff --git a/target/arm/tcg/t32.decode b/target/arm/tcg/t32.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/t32.decode +++ b/target/arm/tcg/t32.decode @@ -XXX,XX +XXX,XX @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm WFE 1111 0011 1010 1111 1000 0000 0000 0010 WFI 1111 0011 1010 1111 1000 0000 0000 0011 - # M-profile SEV is implemented. - # TODO: Implement SEV for other profiles, and SEVL for all profiles; may help SMP performance. SEV 1111 0011 1010 1111 1000 0000 0000 0100 - # SEVL 1111 0011 1010 1111 1000 0000 0000 0101 + SEVL 1111 0011 1010 1111 1000 0000 0000 0101 ESB 1111 0011 1010 1111 1000 0000 0001 0000 ] diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_WFI(DisasContext *s, arg_WFI *a) return true; } +static bool trans_SEV(DisasContext *s, arg_SEV *a) +{ + /* + * SEV is a NOP for user-mode emulation. + */ +#ifndef CONFIG_USER_ONLY + gen_helper_sev(tcg_env); +#endif + return true; +} + +static bool trans_SEVL(DisasContext *s, arg_SEV *a) +{ + gen_event_reg(); + return true; +} + static bool trans_WFE(DisasContext *s, arg_WFI *a) { /* diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -XXX,XX +XXX,XX @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a) static bool trans_SEV(DisasContext *s, arg_SEV *a) { /* - * Currently SEV is a NOP for non-M-profile and in user-mode emulation. - * For system-mode M-profile, it sets the event register. + * SEV is a NOP for user-mode emulation. For v6T2 and earlier + * non-M-profile cores this encoding is a NOP hint. */ #ifndef CONFIG_USER_ONLY - if (arm_dc_feature(s, ARM_FEATURE_M)) { + if (arm_dc_feature(s, ARM_FEATURE_M) || + arm_dc_feature(s, ARM_FEATURE_V7)) { gen_helper_sev(tcg_env); } #endif return true; } +static bool trans_SEVL(DisasContext *s, arg_SEV *a) +{ + /* + * SEVL only exists for v8A; for M-profile and v7A and earlier + * this encoding is an unallocated must-NOP hint. + */ + if (!arm_dc_feature(s, ARM_FEATURE_M) && + arm_dc_feature(s, ARM_FEATURE_V8)) { + gen_event_reg(); + } + return true; +} + static bool trans_WFE(DisasContext *s, arg_WFE *a) { /* diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ static inline void gen_restore_rmode(TCGv_i32 old, TCGv_ptr fpst) gen_helper_set_rmode(old, old, fpst); } +/* + * Event Register signalling. + * + * A bunch of activities trigger events, we just need to latch on to + * true. The event eventually gets consumed by WFE/WFET. + * + * user-mode treats these as NOPs. + */ + +static inline void gen_event_reg(void) +{ +#ifndef CONFIG_USER_ONLY + TCGv_i32 set_event = tcg_constant_i32(1); + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, event_register) != 1); + tcg_gen_st8_i32(set_event, tcg_env, offsetof(CPUARMState, event_register)); +#endif +} + /* * Helpers for implementing sets of trans_* functions. * Defer the implementation of NAME to FUNC, with optional extra arguments. -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> To enable full architectural behaviour for A-profile we need to do a number of things: - add support for the event stream to wake things up - add support for potential trap on sleep - handle the global monitor's interactions with WFE - remove the M-profile specific gates Event stream ------------ Two generic timers (K and H) are capable of generating timer event stream events. Provide a helper to calculate when the nearest one will happen. Now we can calculate when the next event stream event is we can re-use the wfxt_timer and configure it to fire as we enter a WFE that is going to sleep. Reverse the M-profile logic so we can enter a sleep state in both profiles. We also take care to use atomics for accessing env->event_register as we now have potential access outside the vCPU context. Traps ----- A-profile can trap WFE's *if* the instruction would otherwise sleep. To do this we need to pass the instruction size so we can deal with the is_16bit syndrome encoding. Global Monitor -------------- To avoid issues with QEMU's incomplete ldst exclusive handling causing potential deadlocks in common WFE enabled locking patterns we take advantage of the architectures flexibility and treat being in the exclusive region as a reason to exit. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260624103049.884930-7-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 13 +++ target/arm/tcg/helper-defs.h | 2 +- target/arm/tcg/op_helper.c | 160 ++++++++++++++++++++++++++++----- target/arm/tcg/translate-a64.c | 12 +-- target/arm/tcg/translate.c | 18 +--- 5 files changed, 158 insertions(+), 47 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ bool arm_cpu_exec_halt(CPUState *cs) } #endif +/* + * Unlike almost everything else that messes with the halt_reason and + * event_register details the timer callbacks are not in the vCPU + * context. + * + * To prevent races we atomically consume a HALT_WFE and set the event + * register. Either way we trigger the an exit event. + */ static void arm_wfxt_timer_cb(void *opaque) { ARMCPU *cpu = opaque; CPUState *cs = CPU(cpu); + CPUARMState *env = &cpu->env; + + if (qatomic_cmpxchg(&env->halt_reason, HALT_WFE, NOT_HALTED)) { + qatomic_set(&env->event_register, true); + } /* * We expect the CPU to be halted; this will cause arm_cpu_is_work() diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_2(exception_swstep, noreturn, env, i32) DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr) DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) -DEF_HELPER_1(wfe, void, env) +DEF_HELPER_2(wfe, void, env, i32) DEF_HELPER_2(wfit, void, env, i32) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sev)(CPUARMState *env) } } -void HELPER(wfe)(CPUARMState *env) +#ifndef CONFIG_USER_ONLY +/* + * Event Stream events don't do anything apart from wake up sleeping + * cores. These helpers calculate the next event stream event time so + * the WFE helper can decide when its next wake up tick will be. + */ +static int64_t gt_recalc_one_evt(CPUARMState *env, uint32_t control, uint64_t offset) +{ + ARMCPU *cpu = env_archcpu(env); + bool evnten = FIELD_EX32(control, CNTxCTL, EVNTEN); + + if (evnten) { + int evnti = FIELD_EX32(control, CNTxCTL, EVNTI); + bool evntis = FIELD_EX32(control, CNTxCTL, EVNTIS); + bool evntdir = FIELD_EX32(control, CNTxCTL, EVNTDIR); + /* + * To figure out when the next event timer should fire we need + * to calculate which bit of the counter we want to flip and + * which transition counts. + * + * So we calculate 1 << bit - current lower bits and then add + * 1 << bit if the bit needs to flip twice to meet evntdir + */ + int bit = evntis ? evnti + 8 : evnti; + uint64_t count = gt_get_countervalue(env) - offset; + uint64_t target_bit = BIT_ULL(bit); + uint64_t lower_bits = MAKE_64BIT_MASK(0, bit - 1); + uint64_t next_tick = target_bit - (count & lower_bits); + uint64_t abstick; + + /* do we need to bit flip twice? */ + if (((count & target_bit) != 0) ^ evntdir) { + next_tick += target_bit; + } + + /* + * Note that the desired next expiry time might be beyond the + * signed-64-bit range of a QEMUTimer -- in this case we just + * set the timer for as far in the future as possible. When the + * timer expires we will reset the timer for any remaining period. + */ + if (uadd64_overflow(next_tick, offset, &abstick)) { + abstick = UINT64_MAX; + } + if (abstick > INT64_MAX / gt_cntfrq_period_ns(cpu)) { + return INT64_MAX; + } else { + return abstick; + } + } + + return -1; +} + +/* + * Calculate the next event stream time and return it. Returns -1 if + * no event streams are enabled. It is up to the WFE helpers to decide + * on the next time. + */ +static int64_t gt_calc_next_event_stream(CPUARMState *env) +{ + ARMCPU *cpu = env_archcpu(env); + uint64_t hcr = arm_hcr_el2_eff(env); + int64_t next_time = -1; + uint64_t offset; + + /* Unless we are missing EL2 this can generate events */ + if (arm_feature(env, ARM_FEATURE_EL2)) { + offset = gt_direct_access_timer_offset(env, GTIMER_PHYS); + next_time = gt_recalc_one_evt(env, env->cp15.cnthctl_el2, offset); + } + + /* Event stream events from virtual counter enabled? */ + if (!cpu_isar_feature(aa64_vh, cpu) || + !((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE))) { + int64_t next_virt_time; + offset = gt_direct_access_timer_offset(env, GTIMER_VIRT); + next_virt_time = gt_recalc_one_evt(env, env->cp15.c14_cntkctl, offset); + + /* is this earlier than the next physical event? */ + if (next_virt_time > 0) { + if (next_time < 0 || next_virt_time < next_time) { + next_time = next_virt_time; + } + } + } + + return next_time; +} +#endif + +void HELPER(wfe)(CPUARMState *env, uint32_t insn_len) { #ifdef CONFIG_USER_ONLY /* @@ -XXX,XX +XXX,XX @@ void HELPER(wfe)(CPUARMState *env) #else /* * WFE (Wait For Event) is a hint instruction. - * For Cortex-M (M-profile), we implement the strict architectural behavior: + * * 1. Check the Event Register (set by SEV or SEVONPEND). * 2. If set, clear it and continue (consume the event). */ - if (arm_feature(env, ARM_FEATURE_M)) { - CPUState *cs = env_cpu(env); + CPUState *cs = env_cpu(env); + ARMCPU *cpu = env_archcpu(env); + uint32_t excp; + int target_el; - if (env->event_register) { - env->event_register = false; - return; - } - - env->halt_reason = HALT_WFE; - cs->exception_index = EXCP_HLT; - cs->halted = 1; - cpu_loop_exit(cs); - } else { - /* - * For A-profile and others, we rely on the existing "yield" behavior. - * Don't actually halt the CPU, just yield back to top - * level loop. This is not going into a "low power state" - * (ie halting until some event occurs), so we never take - * a configurable trap to a different exception level - */ - HELPER(yield)(env); + if (qatomic_xchg(&env->event_register, false)) { + return; } + + /* We might sleep, so now we check to see if we should trap */ + target_el = check_wfx_trap(env, true, &excp); + if (target_el) { + if (env->aarch64) { + env->pc -= insn_len; + } else { + env->regs[15] -= insn_len; + } + raise_exception(env, excp, syn_wfx(1, 0xe, 0, false, WFE, insn_len == 2), + target_el); + } + + /* + * If the CPU has entered the exclusive region we could sleep + * until the global monitor moves from Exclusive to Open Access. + * However it would be expensive for QEMU to fully model the + * global monitor and not doing so would potentially trigger + * deadlocks in WFE enabled locking code. However as WFE is a hint + * instruction the architecture allows for the PE to leave + * low-power state for any reason. QEMU chooses to treat being in + * an exclusive region as such and return directly. + */ + if (env->exclusive_addr != -1) { + return; + } + + /* For A-profile we also can be woken by the event stream */ + if (cpu->wfxt_timer) { + int64_t next_event = gt_calc_next_event_stream(env); + if (next_event > 0) { + timer_mod(cpu->wfxt_timer, next_event); + } + } + + env->halt_reason = HALT_WFE; + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); #endif } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a) static bool trans_WFE(DisasContext *s, arg_WFI *a) { - /* - * When running in MTTCG we don't generate jumps to the yield and - * WFE helpers as it won't affect the scheduling of other vCPUs. - * If we wanted to more completely model WFE/SEV so we don't busy - * spin unnecessarily we would need to do something more involved. - */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - s->base.is_jmp = DISAS_WFE; - } + s->base.is_jmp = DISAS_WFE; return true; } @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) */ case DISAS_WFE: gen_a64_update_pc(dc, 4); - gen_helper_wfe(tcg_env); + gen_helper_wfe(tcg_env, tcg_constant_i32(4)); tcg_gen_exit_tb(NULL, 0); break; case DISAS_WFI: diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -XXX,XX +XXX,XX @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a) static bool trans_WFE(DisasContext *s, arg_WFE *a) { - /* - * When running single-threaded TCG code, use the helper to ensure that - * the next round-robin scheduled vCPU gets a crack. - * - * For Cortex-M, we implement the architectural WFE behavior (sleeping - * until an event occurs or the Event Register is set). - * For other profiles, we currently treat this as a NOP or yield, - * to preserve existing performance characteristics. - */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_WFE; - } + /* For WFE, halt the vCPU until an event. */ + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_WFE; return true; } @@ -XXX,XX +XXX,XX @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) tcg_gen_exit_tb(NULL, 0); break; case DISAS_WFE: - gen_helper_wfe(tcg_env); + gen_helper_wfe(tcg_env, tcg_constant_i32(curr_insn_len(dc))); /* * The helper can return if the event register is set, so we * must go back to the main loop to check for events. -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Now we have the event stream and SEV/SEVL implemented we can finally enable WFET for Aarch64. To avoid issues with QEMU's incomplete ldst exclusive handling causing potential deadlocks in common WFE enabled locking patterns we take advantage of the architectures flexibility and treat being in the exclusive region as a reason to exit. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260624103049.884930-8-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-defs.h | 1 + target/arm/tcg/op_helper.c | 94 ++++++++++++++++++++++++++++++++++ target/arm/tcg/translate-a64.c | 15 +++--- 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) DEF_HELPER_2(wfe, void, env, i32) DEF_HELPER_2(wfit, void, env, i32) +DEF_HELPER_2(wfet, void, env, i32) DEF_HELPER_1(yield, void, env) DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_2(pre_smc, void, env, i32) diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(wfe)(CPUARMState *env, uint32_t insn_len) #endif } +void HELPER(wfet)(CPUARMState *env, uint32_t rd) +{ +#ifdef CONFIG_USER_ONLY + /* + * As for WFIT make it NOP here, because trying to raise EXCP_HLT + * would trigger an abort. + */ + return; +#else + CPUState *cs = env_cpu(env); + uint32_t excp; + int target_el; + ARMCPU *cpu; + uint64_t cntval, timeout, offset, cntvct, nexttick; + int64_t next_event; + + /* + * As for WFE if the event register is already set we can consume + * the event and return immediately. + */ + if (qatomic_xchg(&env->event_register, false)) { + return; + } + + /* + * Don't bother to go into our "low power state" if + * we would just wake up immediately. + * + * We want the value that we would get if we read CNTVCT_EL0 from + * the current exception level, so the direct_access offset, not + * the indirect_access one. Compare the pseudocode LocalTimeoutEvent(), + * which calls VirtualCounterTimer(). + */ + cntval = gt_get_countervalue(env); + offset = gt_direct_access_timer_offset(env, GTIMER_VIRT); + cntvct = cntval - offset; + timeout = env->xregs[rd]; + if (cpu_has_work(cs) || cntvct >= timeout) { + return; + } + + /* We might sleep, so now we check to see if we should trap */ + target_el = check_wfx_trap(env, true, &excp); + if (target_el) { + env->pc -= 4; + raise_exception(env, excp, syn_wfx(1, 0xe, rd, true, WFET, false), target_el); + } + + /* + * If the CPU has entered the exclusive region we could sleep + * until the global monitor moves from Exclusive to Open Access. + * However it would be expensive for QEMU to fully model the + * global monitor and not doing so would potentially trigger + * deadlocks in WFE enabled locking code. However as WFE is a hint + * instruction the architecture allows for the PE to leave + * low-power state for any reason. QEMU chooses to treat being in + * an exclusive region as such and return directly. + */ + if (env->exclusive_addr != -1) { + return; + } + + /* + * Finally work out if the timeout or event stream will kick in + * earlier. + * + * The WFET should time out when CNTVCT_EL0 >= the specified value. + */ + cpu = env_archcpu(env); + if (uadd64_overflow(timeout, offset, &nexttick)) { + nexttick = UINT64_MAX; + } + if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) { + nexttick = INT64_MAX; + } + + next_event = gt_calc_next_event_stream(env); + if (next_event > 0 && next_event < nexttick) { + timer_mod(cpu->wfxt_timer, next_event); + } else { + if (nexttick == INT64_MAX) { + timer_mod_ns(cpu->wfxt_timer, INT64_MAX); + } else { + timer_mod(cpu->wfxt_timer, nexttick); + } + } + + env->halt_reason = HALT_WFE; + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); +#endif +} + void HELPER(yield)(CPUARMState *env) { CPUState *cs = env_cpu(env); diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_WFET(DisasContext *s, arg_WFET *a) return false; } - /* - * We rely here on our WFE implementation being a NOP, so we - * don't need to do anything different to handle the WFET timeout - * from what trans_WFE does. - */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - s->base.is_jmp = DISAS_WFE; + if (s->ss_active) { + /* Act like a NOP under architectural singlestep */ + return true; } + + gen_a64_update_pc(s, 4); + gen_helper_wfet(tcg_env, tcg_constant_i32(a->rd)); + /* Go back to the main loop to check for interrupts */ + s->base.is_jmp = DISAS_EXIT; return true; } -- 2.43.0
We implement the fw_cfg device for more architectures and machines that we let on about in our documentation. Luckily most of the new ones (notably riscv and loongarch) have followed the straightforward layout that the Arm virt board picked. Restructure the documentation to present this as the "standard" layout, followed by the other layouts used by various other boards for historical reasons. This adds PA-RISC, SPARC, PPC and MIPS. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260529174639.451353-2-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> --- docs/specs/fw_cfg.rst | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/specs/fw_cfg.rst b/docs/specs/fw_cfg.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/specs/fw_cfg.rst +++ b/docs/specs/fw_cfg.rst @@ -XXX,XX +XXX,XX @@ increasing address order, similar to memcpy(). Register Locations ------------------ +For a memory-mapped fw_cfg device, the standard register layout is: + + * base address : Data Register (64 bit) + * base address + 8 : Selector Register (16 bit) + * base address + 16 : DMA Address Register (64 bit) + +Some architectures or machines have a different layout for historical reasons: + x86, x86_64 * Selector Register IOport: 0x510 * Data Register IOport: 0x511 * DMA Address IOport: 0x514 -Arm - * Selector Register address: Base + 8 (2 bytes) - * Data Register address: Base + 0 (8 bytes) - * DMA Address address: Base + 16 (8 bytes) +PA-RISC: + * base address : Selector Register (16 bit) + * base address + 4 : Data Register (8 bit) + +32-bit SPARC, PPC ``g3beige``, ``mac99``, ``prep``: + * base address : Selector Register (16 bit) + * base address + 2 : Data Register (8 bit) + +64-bit SPARC: + * base address : Selector Register (16 bit) + * base address + 1 : Data Register (8 bit) + +MIPS ``loongson3-virt`` machine: + * base address : Selector Register (16 bit) + * base address + 8 : Data Register (64 bit) + ACPI Interface -------------- -- 2.43.0
Currently fw_cfg_init_mem_dma() allows the caller to customize the register layout, by specifying separately the offsets for control, data and DMA registers, plus the width of the data register. In practice, all the boards using this function specify the same standard layout: "base + 8, base, 8, base + 16", meaning that the data register is 8 bytes and the registers are data at offset 0, control/selector at offset 8, and DMA at offset 16. Allowing every board to be different is gratuitous and useless variation which leads to code in guest OSes having architecture ifdeffery to cope with it. Avoid potentially introducing any more of this by removing all the arguments from fw_cfg_init_mem_dma(), so that the callers only specify the base address. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260529174639.451353-3-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> --- hw/arm/virt.c | 2 +- hw/loongarch/fw_cfg.c | 3 +-- hw/nvram/fw_cfg.c | 10 ++++------ hw/riscv/virt.c | 3 +-- include/hw/nvram/fw_cfg.h | 23 ++++++++++++++++++++--- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -XXX,XX +XXX,XX @@ static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as) FWCfgState *fw_cfg; char *nodename; - fw_cfg = fw_cfg_init_mem_dma(base + 8, base, 8, base + 16, as); + fw_cfg = fw_cfg_init_mem_dma(base, as); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus); nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/loongarch/fw_cfg.c +++ b/hw/loongarch/fw_cfg.c @@ -XXX,XX +XXX,XX @@ FWCfgState *virt_fw_cfg_init(ram_addr_t ram_size, MachineState *ms) int max_cpus = ms->smp.max_cpus; int smp_cpus = ms->smp.cpus; - fw_cfg = fw_cfg_init_mem_dma(VIRT_FWCFG_BASE + 8, VIRT_FWCFG_BASE, 8, - VIRT_FWCFG_BASE + 16, &address_space_memory); + fw_cfg = fw_cfg_init_mem_dma(VIRT_FWCFG_BASE, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -XXX,XX +XXX,XX @@ static FWCfgState *fw_cfg_init_mem_internal(hwaddr ctl_addr, return s; } -FWCfgState *fw_cfg_init_mem_dma(hwaddr ctl_addr, - hwaddr data_addr, uint32_t data_width, - hwaddr dma_addr, AddressSpace *dma_as) +FWCfgState *fw_cfg_init_mem_dma(hwaddr base_addr, AddressSpace *dma_as) { - assert(dma_addr && dma_as); - return fw_cfg_init_mem_internal(ctl_addr, data_addr, data_width, - dma_addr, dma_as); + assert(dma_as); + return fw_cfg_init_mem_internal(base_addr + 8, base_addr, 8, + base_addr + 16, dma_as); } FWCfgState *fw_cfg_init_mem_nodma(hwaddr ctl_addr, hwaddr data_addr, diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -XXX,XX +XXX,XX @@ static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base) { FWCfgState *fw_cfg; - fw_cfg = fw_cfg_init_mem_dma(base + 8, base, 8, base + 16, - &address_space_memory); + fw_cfg = fw_cfg_init_mem_dma(base, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus); return fw_cfg; diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -XXX,XX +XXX,XX @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, AddressSpace *dma_as); FWCfgState *fw_cfg_init_mem_nodma(hwaddr ctl_addr, hwaddr data_addr, unsigned data_width); -FWCfgState *fw_cfg_init_mem_dma(hwaddr ctl_addr, - hwaddr data_addr, uint32_t data_width, - hwaddr dma_addr, AddressSpace *dma_as); +/** + * fw_cfg_init_mem_dma: + * @base_addr: address to map the device at + * @as: the device will do DMA to/from this AddressSpace + * + * Create and map a fw_cfg device at the specified base address. + * + * This always creates a device with DMA support, and the "standard" + * register layout: + * - offset 0 : data, 64 bits + * - offset 8 : selector, 16 bits + * - offset 16 : DMA address, 64 bits + * + * The device will be created, configured and realized, and its + * memory regions for the registers will be mapped at the specified + * address. + * + * Returns the device object. + */ +FWCfgState *fw_cfg_init_mem_dma(hwaddr base_addr, AddressSpace *dma_as); FWCfgState *fw_cfg_find(void); bool fw_cfg_dma_enabled(void *opaque); -- 2.43.0
The fw_cfg_init_io_dma() function allows the caller to specify the base port number of the selector/data register and the base port number of the DMA address register separately. No caller actually uses this: they all pass in base + 4 for the dma_iobase. To reduce the risk of unnecessary variation in what different x86 machine types use as their fw_cfg register layout, remove the dma_iobase argument from fw_cfg_init_io_dma(), and have the function always use the same "DMA port is base port + 4" layout. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com> Message-id: 20260529174639.451353-4-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> --- hw/i386/fw_cfg.c | 3 +-- hw/i386/microvm.c | 3 +-- hw/i386/pc.c | 3 +-- hw/nvram/fw_cfg.c | 8 ++++---- include/hw/nvram/fw_cfg.h | 17 +++++++++++++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -XXX,XX +XXX,XX @@ FWCfgState *fw_cfg_arch_create(MachineState *ms, const CPUArchIdList *cpus = mc->possible_cpu_arch_ids(ms); int nb_numa_nodes = ms->numa_state->num_nodes; - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, - &address_space_memory); + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, boot_cpus); /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -XXX,XX +XXX,XX @@ static void microvm_memory_init(MicrovmMachineState *mms) e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM); } - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, - &address_space_memory); + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, machine->smp.cpus); fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, machine->smp.max_cpus); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -XXX,XX +XXX,XX @@ void xen_load_linux(PCMachineState *pcms) assert(MACHINE(pcms)->kernel_filename != NULL); - fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, - &address_space_memory); + fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, &address_space_memory); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); rom_set_fw(fw_cfg); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -XXX,XX +XXX,XX @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp) qemu_add_machine_init_done_notifier(&s->machine_ready); } -FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, - AddressSpace *dma_as) +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as) { DeviceState *dev; SysBusDevice *sbd; FWCfgIoState *ios; FWCfgState *s; MemoryRegion *iomem = get_system_io(); - bool dma_requested = dma_iobase && dma_as; + bool dma_requested = dma_as; dev = qdev_new(TYPE_FW_CFG_IO); if (!dma_requested) { @@ -XXX,XX +XXX,XX @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, /* 64 bits for the address field */ s->dma_as = dma_as; s->dma_addr = 0; - memory_region_add_subregion(iomem, dma_iobase, &s->dma_iomem); + /* DMA register ioport is always at base + 4 */ + memory_region_add_subregion(iomem, iobase + 4, &s->dma_iomem); } return s; diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -XXX,XX +XXX,XX @@ bool fw_cfg_add_file_from_generator(FWCfgState *s, Object *parent, const char *part, const char *filename, Error **errp); -FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase, - AddressSpace *dma_as); +/** + * fw_cfg_init_io_dma: + * @iobase: x86 port number which is the base of the fw_cfg port range + * @dma_as: the device will do DMA to/from this AddressSpace + * + * Create a fw_cfg device and map it into the specified I/O port range. + * + * This creates a device with the x86 PC standard port I/O layout: + * - Selector Register IOport: @iobase + * - Data Register IOport: @iobase + 1 + * - DMA Address IOport: @iobase + 4 + * + * Returns the device object. + */ +FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as); FWCfgState *fw_cfg_init_mem_nodma(hwaddr ctl_addr, hwaddr data_addr, unsigned data_width); /** -- 2.43.0
Currently fw_cfg_init_io_dma() allows the caller to pass a NULL dma_as argument, which causes it to create a fw_cfg without the DMA port or DMA support. None of the callers use this capability: they all pass &address_space_memory. We don't really want to leave the door open for some future x86 machine type which doesn't support DMA for the fw_cfg device, so remove this, and instead make the function assert that it has a non-NULL dma_as argument, like fw_cfg_init_mem_dma(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com> Message-id: 20260529174639.451353-5-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> --- hw/nvram/fw_cfg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -XXX,XX +XXX,XX @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as) FWCfgIoState *ios; FWCfgState *s; MemoryRegion *iomem = get_system_io(); - bool dma_requested = dma_as; + + assert(dma_as); 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)); -- 2.43.0
The last few commits have added doc comments for all the fw_cfg_init* functions except for fw_cfg_init_mem_nodma(). Fill in the gap by adding a doc comment for it. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@mailo.com> Message-id: 20260529174639.451353-6-peter.maydell@linaro.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> --- include/hw/nvram/fw_cfg.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -XXX,XX +XXX,XX @@ bool fw_cfg_add_file_from_generator(FWCfgState *s, * Returns the device object. */ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, AddressSpace *dma_as); + +/** + * fw_cfg_init_mem_nodma: + * + * @ctl_addr: address of the selector register + * @data_addr: address of the data address + * @data_width: width of the data register in bytes + * + * Create a fw_cfg device without DMA support, and map its + * registers at the specified addresses. + * + * Do not use this function in code for a board type that didn't + * already support the fw_cfg device. All new board types should + * include DMA support and use the standard register layout -- use + * fw_cfg_init_mem_dma() instead. + * + * Returns the device object. + */ FWCfgState *fw_cfg_init_mem_nodma(hwaddr ctl_addr, hwaddr data_addr, unsigned data_width); /** -- 2.43.0
From: jack wang <163wangjack@gmail.com> Signed-off-by: jack wang <163wangjack@gmail.com> [PMM: trace include is just "trace.h"] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/imx_ccm.c | 18 +++--------------- hw/misc/trace-events | 4 ++++ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "hw/misc/imx_ccm.h" #include "qemu/module.h" - -#ifndef DEBUG_IMX_CCM -#define DEBUG_IMX_CCM 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_CCM) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \ - __func__, ##args); \ - } \ - } while (0) +#include "trace.h" uint32_t imx_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) @@ -XXX,XX +XXX,XX @@ uint32_t imx_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) freq = klass->get_clock_frequency(dev, clock); } - DPRINTF("(clock = %d) = %u\n", clock, freq); + trace_imx_ccm_get_clock_frequency(clock, freq); return freq; } @@ -XXX,XX +XXX,XX @@ uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq) freq = ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) / (mfd * pd)) << 10; - DPRINTF("(pllreg = 0x%08x, base_freq = %u) = %d\n", pllreg, base_freq, - freq); + trace_imx_ccm_calc_pll(pllreg, base_freq, freq); return freq; } diff --git a/hw/misc/trace-events b/hw/misc/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -XXX,XX +XXX,XX @@ iotkit_secctl_s_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit Sec iotkit_secctl_ns_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs read: offset 0x%x data 0x%" PRIx64 " size %u" iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u" +# imx_ccm.c +imx_ccm_get_clock_frequency(uint32_t clock, uint32_t freq) "(clock = %u) = %u" +imx_ccm_calc_pll(uint32_t pllreq, uint32_t base_freq, uint32_t freq) "(pllreg = 0x%08x, base_freq = %u) = %u" + # imx6_ccm.c imx6_analog_get_periph_clk(uint32_t freq) "freq = %u Hz" imx6_analog_get_pll2_clk(uint32_t freq) "freq = %u Hz" -- 2.43.0
From: jack wang <163wangjack@gmail.com> Signed-off-by: jack wang <163wangjack@gmail.com> [PMM: Removed incorrect change to a function prototype; use just "trace.h" for include] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/imx25_ccm.c | 32 +++++++++----------------------- hw/misc/trace-events | 9 +++++++++ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/imx25_ccm.c +++ b/hw/misc/imx25_ccm.c @@ -XXX,XX +XXX,XX @@ #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" +#include "hw/misc/trace.h" -#ifndef DEBUG_IMX25_CCM -#define DEBUG_IMX25_CCM 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX25_CCM) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \ - __func__, ##args); \ - } \ - } while (0) static const char *imx25_ccm_reg_name(uint32_t reg) { @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev) freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ); } - DPRINTF("freq = %u\n", freq); + trace_imx25_ccm_get_mpll_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev) freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV)); - DPRINTF("freq = %u\n", freq); + trace_imx25_ccm_get_mcu_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev) freq = imx25_ccm_get_mcu_clk(dev) / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV)); - DPRINTF("freq = %u\n", freq); + trace_imx25_ccm_get_ahb_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev) freq = imx25_ccm_get_ahb_clk(dev) / 2; - DPRINTF("freq = %u\n", freq); + trace_imx25_ccm_get_ipg_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev) static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) { uint32_t freq = 0; - DPRINTF("Clock = %d)\n", clock); + trace_imx25_ccm_get_clock_frequency(clock, freq); switch (clock) { case CLK_NONE: @@ -XXX,XX +XXX,XX @@ static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) break; } - DPRINTF("Clock = %d) = %u\n", clock, freq); + trace_imx25_ccm_get_clock_frequency(clock, freq); return freq; } @@ -XXX,XX +XXX,XX @@ static void imx25_ccm_reset(DeviceState *dev) { IMX25CCMState *s = IMX25_CCM(dev); - DPRINTF("\n"); - memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t)); s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01; s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800; @@ -XXX,XX +XXX,XX @@ static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size) HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset); } - DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2), - value); + trace_imx25_ccm_read(imx25_ccm_reg_name(offset >> 2), value); return value; } @@ -XXX,XX +XXX,XX @@ static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value, { IMX25CCMState *s = (IMX25CCMState *)opaque; - DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2), - (uint32_t)value); + trace_imx25_ccm_write(imx25_ccm_reg_name(offset >> 2), value); if (offset < 0x70) { /* diff --git a/hw/misc/trace-events b/hw/misc/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -XXX,XX +XXX,XX @@ imx6_src_reset(void) "" imx7_src_read(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 imx7_src_write(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 +# imx25_ccm.c +imx25_ccm_get_mpll_clk(uint32_t freq) "freq = %u" +imx25_ccm_get_mcu_clk(uint32_t freq) "freq = %u" +imx25_ccm_get_ahb_clk(uint32_t freq) "freq = %u" +imx25_ccm_get_ipg_clk(uint32_t freq) "freq = %u" +imx25_ccm_get_clock_frequency(unsigned clock, uint32_t freq) "(clock = %d) = %u" +imx25_ccm_read(const char *reg, uint32_t value) "reg[%s] => 0x%" PRIx32 +imx25_ccm_write(const char *reg, uint32_t value) "reg[%s] <= 0x%" PRIx32 + # iotkit-sysinfo.c iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" -- 2.43.0
Signed-off-by: jack wang <163wangjack@gmail.com> [PMM: Remove stray loss of a brace; use trace.h] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/imx31_ccm.c | 33 +++++++++------------------------ hw/misc/trace-events | 10 ++++++++++ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/imx31_ccm.c +++ b/hw/misc/imx31_ccm.c @@ -XXX,XX +XXX,XX @@ #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" +#include "trace.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ -#ifndef DEBUG_IMX31_CCM -#define DEBUG_IMX31_CCM 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX31_CCM) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \ - __func__, ##args); \ - } \ - } while (0) - static const char *imx31_ccm_reg_name(uint32_t reg) { static char unknown[20]; @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_pll_ref_clk(IMXCCMState *dev) freq = CKIH_FREQ; } - DPRINTF("freq = %u\n", freq); + trace_imx31_ccm_get_pll_ref_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_mpll_clk(IMXCCMState *dev) freq = imx_ccm_calc_pll(s->reg[IMX31_CCM_MPCTL_REG], imx31_ccm_get_pll_ref_clk(dev)); - DPRINTF("freq = %u\n", freq); + trace_imx31_ccm_get_mpll_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_mcu_main_clk(IMXCCMState *dev) freq = imx31_ccm_get_mpll_clk(dev); } - DPRINTF("freq = %u\n", freq); + trace_imx31_ccm_get_mcu_main_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_hclk_clk(IMXCCMState *dev) freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], MAX)); - DPRINTF("freq = %u\n", freq); + trace_imx31_ccm_get_hclk_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_ipg_clk(IMXCCMState *dev) freq = imx31_ccm_get_hclk_clk(dev) / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], IPG)); - DPRINTF("freq = %u\n", freq); + trace_imx31_ccm_get_ipg_clk(freq); return freq; } @@ -XXX,XX +XXX,XX @@ static uint32_t imx31_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) break; } - DPRINTF("Clock = %d) = %u\n", clock, freq); + trace_imx31_ccm_get_clock_frequency(clock, freq); return freq; } @@ -XXX,XX +XXX,XX @@ static void imx31_ccm_reset(DeviceState *dev) { IMX31CCMState *s = IMX31_CCM(dev); - DPRINTF("()\n"); - memset(s->reg, 0, sizeof(uint32_t) * IMX31_CCM_MAX_REG); s->reg[IMX31_CCM_CCMR_REG] = 0x074b0b7d; @@ -XXX,XX +XXX,XX @@ static uint64_t imx31_ccm_read(void *opaque, hwaddr offset, unsigned size) HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset); } - DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2), - value); + trace_imx31_ccm_read(imx31_ccm_reg_name(offset >> 2), value); return (uint64_t)value; } @@ -XXX,XX +XXX,XX @@ static void imx31_ccm_write(void *opaque, hwaddr offset, uint64_t value, { IMX31CCMState *s = (IMX31CCMState *)opaque; - DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2), - (uint32_t)value); + trace_imx31_ccm_write(imx31_ccm_reg_name(offset >> 2), value); switch (offset >> 2) { case IMX31_CCM_CCMR_REG: diff --git a/hw/misc/trace-events b/hw/misc/trace-events index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -XXX,XX +XXX,XX @@ imx25_ccm_get_clock_frequency(unsigned clock, uint32_t freq) "(clock = %d) = %u" imx25_ccm_read(const char *reg, uint32_t value) "reg[%s] => 0x%" PRIx32 imx25_ccm_write(const char *reg, uint32_t value) "reg[%s] <= 0x%" PRIx32 +# imx31_ccm.c +imx31_ccm_get_mpll_clk(uint32_t freq) "freq = %u" +imx31_ccm_get_pll_ref_clk(uint32_t freq) "freq = %u" +imx31_ccm_get_mcu_main_clk(uint32_t freq) "freq = %u" +imx31_ccm_get_hclk_clk(uint32_t freq) "freq = %u" +imx31_ccm_get_ipg_clk(uint32_t freq) "freq = %u" +imx31_ccm_get_clock_frequency(unsigned clock, uint32_t freq) "(clock = %u) = %u" +imx31_ccm_read(const char *reg, uint32_t value) "reg[%s] => 0x%" PRIx32 +imx31_ccm_write(const char *reg, uint32_t value) "reg[%s] <= 0x%" PRIx32 + # iotkit-sysinfo.c iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" -- 2.43.0
From: Jason Wright <wrigjl@proton.me> Commit 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS") gave ID_AA64ISAR0_EL1 a readfn so the RNDR field can reflect SCR_EL3.TRNDR at read time, and marked the cpreg ARM_CP_NO_RAW in the system-emulation path. HVF then trips its hvf_arch_init_vcpu() assertion that no ID register in hvf_sreg_list[] is NO_RAW, aborting on boot on Apple Silicon: Assertion failed: (!(ri->type & ARM_CP_NO_RAW)), function hvf_arch_init_vcpu, file hvf.c, line 1441. Reproduce with: qemu-system-aarch64 -M virt,accel=hvf -cpu host \ -nographic -display none -bios /dev/null Fix it the same way ID_AA64PFR0_EL1 already is: list HV_SYS_REG_ID_AA64ISAR0_EL1 in the SYNC_NO_RAW_REGS block in sysreg.c.inc so the assert loop skips it, and seed the vCPU's copy at init time. While here, unify how the three isar.idregs[]-backed ID registers are seeded. isar.idregs[] already holds QEMU's intended value for each (the host caps, probed once at realize via hv_vcpu_config_get_feature_reg(), plus any QEMU adjustment), so there is no need to read each register back from the vCPU first. Seed PFR0, ISAR0 and MMFR0 directly from isar.idregs[], dropping the two per-vCPU hv_vcpu_get_sys_reg() reads: - PFR0: take the GIC sysreg-interface bit from env->gicv3state, as the id_aa64pfr0_read() readfn does. Identical to the previous code whenever a GICv3 sysreg interface is present (the configuration HVF runs in practice); it differs only in that a vCPU with no GICv3 now reports ID_AA64PFR0_EL1.GIC == 0 instead of inheriting the host's value, which matches the field's meaning. - ISAR0: no overlay is needed; HVF does not expose EL3, so SCR_EL3.TRNDR is never set and the readfn is constant. - MMFR0: still clamp PARANGE to the chosen IPA size, updating isar.idregs[] in place because the page-table walker and the ID_AA64MMFR0_EL1 cpreg resetvalue read PARANGE back from there. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3533 Reported-by: Zenghui Yu <zenghui.yu@linux.dev> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Fixes: 887eaa8a29 ("target/arm: implement FEAT_RNG_TRAP for RNDR/RNDRRS") Signed-off-by: Jason Wright <wrigjl@proton.me> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Zenghui Yu <zenghui.yu@linux.dev> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/hvf/hvf.c | 10 ++++------ target/arm/hvf/sysreg.c.inc | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -XXX,XX +XXX,XX @@ int hvf_arch_init_vcpu(CPUState *cpu) arm_cpu->mp_affinity); assert_hvf_ok(ret); - ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, &pfr); - assert_hvf_ok(ret); + pfr = GET_IDREG(&arm_cpu->isar, ID_AA64PFR0); pfr |= env->gicv3state ? (1 << 24) : 0; ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr); assert_hvf_ok(ret); - /* We're limited to underlying hardware caps, override internal versions */ - ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1, - &arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]); + ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64ISAR0_EL1, + GET_IDREG(&arm_cpu->isar, ID_AA64ISAR0)); assert_hvf_ok(ret); clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar); ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1, - arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]); + GET_IDREG(&arm_cpu->isar, ID_AA64MMFR0)); assert_hvf_ok(ret); if (!hvf_irqchip_in_kernel()) { diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc index XXXXXXX..XXXXXXX 100644 --- a/target/arm/hvf/sysreg.c.inc +++ b/target/arm/hvf/sysreg.c.inc @@ -XXX,XX +XXX,XX @@ DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 2, 0, 0, 2, 0) DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 3, 0, 0, 0, 0) DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 3, 0, 0, 0, 5) DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) +DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) #endif DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) /* Add ID_AA64PFR2_EL1 here when HVF supports it */ DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) -DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1) #ifdef SYNC_NO_MMFR0 -- 2.43.0
From: Gerd Hoffmann <kraxel@redhat.com> Function is simliar to load_image_to_fw_cfg() but loads the image into a named fw_cfg file instead of fixed keys. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260521112806.504961-2-kraxel@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/nvram/fw_cfg.c | 22 ++++++++++++++++++++++ include/hw/nvram/fw_cfg.h | 15 +++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index XXXXXXX..XXXXXXX 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -XXX,XX +XXX,XX @@ void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, fw_cfg_add_bytes(fw_cfg, data_key, data, size); } +void load_image_to_fw_cfg_file(FWCfgState *fw_cfg, + const char *fw_cfg_name, + const char *image_name) +{ + GMappedFile *mapped_file; + GError *gerr = NULL; + + if (image_name == NULL) { + return; + } + + mapped_file = g_mapped_file_new(image_name, false, &gerr); + if (!mapped_file) { + error_report("qemu: error reading %s: %s", + image_name, gerr->message); + exit(1); + } + fw_cfg_add_file(fw_cfg, fw_cfg_name, + g_mapped_file_get_contents(mapped_file), + g_mapped_file_get_length(mapped_file)); +} + static void fw_cfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -XXX,XX +XXX,XX @@ void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, uint16_t data_key, const char *image_name, bool try_decompress); +/** + * load_image_to_fw_cfg_file() - Load an image file into an fw_cfg entry + * identified by fw_cfg file name. + * @fw_cfg: The firmware config instance to store the data in. + * @fw_cfg_name: The name of the fw_cfg (pseudo) file. + * @image_name: The name of the image file to load. If it is NULL, the + * function returns without doing anything. + * + * In case of failure, the function prints an error message to stderr and the + * process exits with status 1. + */ +void load_image_to_fw_cfg_file(FWCfgState *fw_cfg, + const char *fw_cfg_name, + const char *image_name); + #endif -- 2.43.0
From: Gerd Hoffmann <kraxel@redhat.com> Use the new helper function instead of open-coding the shim image load. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260521112806.504961-3-kraxel@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/i386/x86-common.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -XXX,XX +XXX,XX @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_file(fw_cfg, "etc/boot/kernel", kernel, kernel_size); if (machine->shim_filename) { - GMappedFile *mapped_file; - GError *gerr = NULL; - - mapped_file = g_mapped_file_new(machine->shim_filename, false, &gerr); - if (!mapped_file) { - fprintf(stderr, "qemu: error reading shim %s: %s\n", - machine->shim_filename, gerr->message); - exit(1); - } - - fw_cfg_add_file(fw_cfg, "etc/boot/shim", - g_mapped_file_get_contents(mapped_file), - g_mapped_file_get_length(mapped_file)); + load_image_to_fw_cfg_file(fw_cfg, "etc/boot/shim", + machine->shim_filename); } if (sev_enabled()) { -- 2.43.0
From: Gerd Hoffmann <kraxel@redhat.com> Add support for direct kernel boot with shim to the arm platform. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Message-id: 20260521112806.504961-4-kraxel@redhat.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/boot.c | 6 ++++++ include/hw/arm/boot.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -XXX,XX +XXX,XX @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info) fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, info->kernel_cmdline); } + + if (info->shim_filename) { + load_image_to_fw_cfg_file(fw_cfg, "etc/boot/shim", + info->shim_filename); + } } /* @@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info) * doesn't support secure. */ assert(!(info->secure_board_setup && kvm_enabled())); + info->shim_filename = ms->shim_filename; info->kernel_filename = ms->kernel_filename; info->kernel_cmdline = ms->kernel_cmdline; info->initrd_filename = ms->initrd_filename; diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/boot.h +++ b/include/hw/arm/boot.h @@ -XXX,XX +XXX,XX @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, /* arm_boot.c */ struct arm_boot_info { uint64_t ram_size; + const char *shim_filename; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; -- 2.43.0
From: Bin Meng <bin.meng@processmission.com> The Zynq board documentation only showed a generic direct kernel boot command. Add Buildroot ZC702 commands for booting through U-Boot proper with the generic loader and for direct Linux boot from the generated SD image. Signed-off-by: Bin Meng <bin.meng@processmission.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 20260628114925.418293-1-bin.meng@processmission.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/xlnx-zynq.rst | 54 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/system/arm/xlnx-zynq.rst b/docs/system/arm/xlnx-zynq.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/xlnx-zynq.rst +++ b/docs/system/arm/xlnx-zynq.rst @@ -XXX,XX +XXX,XX @@ The QEMU xilinx-zynq-a9 board supports the following devices: - DDR Memory - USB 2.0 x2 -Running -""""""" -Direct Linux boot of a generic Arm upstream Linux kernel: +Running Buildroot ZC702 Images +"""""""""""""""""""""""""""""" + +Buildroot has a ZC702 defconfig. Buildroot 2026.05 release is tested at the +time of writing. From the Buildroot source tree: .. code-block:: bash - $ qemu-system-aarch64 -M xilinx-zynq-a9 \ - -dtb zynq-zc702.dtb -serial null -serial mon:stdio \ - -display none -m 1024 \ - -initrd rootfs.cpio.gz -kernel zImage + $ make zynq_zc702_defconfig + $ make + +The generated files are in ``output/images/``. The examples below use: + + * ``u-boot.bin`` + * ``uImage`` + * ``sdcard.img`` + +QEMU's SD card model requires a power-of-two image size. Work on a copy +of the Buildroot SD image and resize the copy, not the original output: + +.. code-block:: bash + + $ cp output/images/sdcard.img sdcard-qemu.img + $ qemu-img resize -f raw sdcard-qemu.img 128M + +To boot through the U-Boot image generated by Buildroot, use the generic +loader device to place the raw ``u-boot.bin`` at the address it was linked +for and start the CPU there. The ``zynq_zc702_defconfig`` U-Boot image is +U-Boot proper, not a Zynq boot ROM image, and is linked at ``0x04000000``: + +.. code-block:: bash + + $ qemu-system-arm -M xilinx-zynq-a9 -m 1G \ + -machine boot-mode=sd \ + -display none -serial null -serial mon:stdio \ + -device loader,file=output/images/u-boot.bin,addr=0x04000000,cpu-num=0 \ + -drive file=sdcard-qemu.img,if=sd,format=raw + +Direct Linux boot of the generated Buildroot image is also supported. The Zynq +ZC702 DTB is generated by Buildroot and is located in +``output/images/zynq-zc702.dtb``. The kernel image is generated as a uImage: + +.. code-block:: bash + + $ qemu-system-arm -M xilinx-zynq-a9 -m 1G \ + -display none -serial null -serial mon:stdio \ + -kernel output/images/uImage \ + -dtb output/images/zynq-zc702.dtb \ + -append "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootwait" \ + -drive file=sdcard-qemu.img,if=sd,format=raw For configuring the boot-mode provide the following on the command line: -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++ target/arm/tcg/helper-sme-defs.h | 4 ++ target/arm/tcg/sme.decode | 12 +++++ target/arm/tcg/sme_helper.c | 76 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 29 ++++++++++++ target/arm/tcg/translate.h | 5 +++ target/arm/tcg/vec_internal.h | 8 ++++ 7 files changed, 139 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ssve_fexpa(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SFEXPA); } +static inline bool isar_feature_aa64_sme_mop4(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SMOP4); +} + static inline bool isar_feature_aa64_ssve_aes(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, AES); diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme2_sel_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_5(sme2_sel_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_5(sme2_sel_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_5(sme2_sel_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) + +DEF_HELPER_FLAGS_5(sme_fmop4a_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_ah_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4h 1100 0000 1001 101 idx:1 10 01 00 zn:5 zd:5 &lut LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ &lut zn=%zn_ax2 idx=0 + +# SME MOP4 Quarter-tile outer products + +&mop4 zad zn zm s:bool n:bool m:bool + +%mop4_zm 17:3 !function=times_2_plus_16 +%mop4_zn 6:3 !function=times_2 + +@mop4_o2 .... .... ... m:1 .... .... .. n:1 ... . s:1 .. zad:2 \ + &mop4 zm=%mop4_zm zn=%mop4_zn + +FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_sel_d)(void *vd, void *vn, void *vm, } } } + +void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque, + uint32_t desc, size_t esize, + void (*fn)(void *, void *, void *, void *)) +{ + intptr_t oprsz = simd_maxsz(desc); + intptr_t dim = oprsz / 2; /* in bytes */ + bool nreg_m1 = extract32(desc, SIMD_DATA_SHIFT + 0, 1); + bool mreg_m1 = extract32(desc, SIMD_DATA_SHIFT + 1, 1); + intptr_t host_adj = HOST_BIG_ENDIAN ? 8 - esize : 0; + + for (int outprod = 0; outprod < 4; outprod++) { + bool row_hv = outprod & 2; + bool col_hv = outprod & 1; + intptr_t row_base = row_hv ? dim : 0; + intptr_t col_base = col_hv ? dim : 0; + void *op1 = vzn + (col_hv && nreg_m1 ? sizeof(ARMVectorReg) : 0); + void *op2 = vzm + (row_hv && mreg_m1 ? sizeof(ARMVectorReg) : 0); + + for (intptr_t row = 0; row < dim; row += esize) { + intptr_t row_idx = row_base + row; + void *vza_row = vza + tile_vslice_offset(row_idx); + void *e1 = op1 + (row_idx ^ host_adj); + + for (intptr_t col = 0; col < dim; col += esize) { + intptr_t col_idx = col_base + col; + void *e2 = op2 + (col_idx ^ host_adj); + void *e3 = vza_row + (col_idx ^ host_adj); + + fn(e3, e1, e2, fn_opaque); + } + } + } +} + +static void inner_fmop4a_ss(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float32_muladd(*n, *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4a_ss)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_fmop4a_ss); +} + +static void inner_fmop4s_ss(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float32_muladd(float32_chs(*n), *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4s_ss)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_fmop4s_ss); +} + +static void inner_ah_fmop4s_ss(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float32_muladd(*n, *m, *d, float_muladd_negate_product, fpst); +} + +void HELPER(sme_ah_fmop4s_ss)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_ah_fmop4s_ss); +} diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(LUTI4_s_4h, aa64_sme2p1, do_lut_s4, a, gen_helper_sme2_luti4_4h) TRANS_FEAT(LUTI4_s_4b, aa64_sme2p1_lutv2, do_lut_s4, a, gen_helper_sme2_luti4_4b) + +static bool do_mop4_fp(DisasContext *s, arg_mop4 *a, MemOp esz, + ARMFPStatusFlavour e_fpst, + gen_helper_gvec_3_ptr * const fns[3]) +{ + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, (a->m << 1) | a->n); + int fns_idx = (a->s ? 1 + s->fpcr_ah : 0); + TCGv_ptr za, zn, zm, fpst; + + if (!sme_smza_enabled_check(s)) { + return true; + } + + za = get_tile(s, esz, a->zad); + zn = vec_full_reg_ptr(s, a->zn); + zm = vec_full_reg_ptr(s, a->zm); + fpst = fpstatus_ptr(e_fpst); + + fns[fns_idx](za, zn, zm, fpst, tcg_constant_i32(desc)); + return true; +} + +static gen_helper_gvec_3_ptr * const fmop4_ss[3] = { + gen_helper_sme_fmop4a_ss, + gen_helper_sme_fmop4s_ss, + gen_helper_sme_ah_fmop4s_ss +}; +TRANS_FEAT(FMOP4_ss, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ZA, fmop4_ss) diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ static inline int times_2_plus_1(DisasContext *s, int x) return x * 2 + 1; } +static inline int times_2_plus_16(DisasContext *s, int x) +{ + return x * 2 + 16; +} + static inline int rsub_64(DisasContext *s, int x) { return 64 - x; diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -XXX,XX +XXX,XX @@ void HELPER(NAME)(void *vd, void *vn, void *vm, \ clear_tail(d, oprsz, simd_maxsz(desc)); \ } +/* + * Perform SME quarter-tile outer product. + * Iterate over ZAtile[] for esize, calling fn for each element. + */ +void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque, + uint32_t desc, size_t esize, + void (*fn)(void *, void *, void *, void *)); + #endif /* TARGET_ARM_VEC_INTERNAL_H */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/helper-sme-defs.h | 4 +++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 42 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 8 ++++++ 5 files changed, 62 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ isar_feature_aa64_sme_f16f16_or_f8f16(const ARMISARegisters *id) return isar_feature_aa64_sme_f16f16(id) || isar_feature_aa64_sme_f8f16(id); } +static inline bool isar_feature_aa64_sme_mop4_f16f16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f16f16(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme2_sel_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_5(sme2_sel_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) DEF_HELPER_FLAGS_5(sme2_sel_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32, i32) +DEF_HELPER_FLAGS_5(sme_fmop4a_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_fmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_ah_fmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + DEF_HELPER_FLAGS_5(sme_fmop4a_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_ah_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ %mop4_zm 17:3 !function=times_2_plus_16 %mop4_zn 6:3 !function=times_2 +@mop4_o1 .... .... ... m:1 .... .... .. n:1 ... . s:1 ... zad:1 \ + &mop4 zm=%mop4_zm zn=%mop4_zn @mop4_o2 .... .... ... m:1 .... .... .. n:1 ... . s:1 .. zad:2 \ &mop4 zm=%mop4_zm zn=%mop4_zn +FMOP4_hh 1000 0001 000. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque, } } +static void inner_fmop4a_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + float16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float16_muladd(*n, *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4a_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float16), inner_fmop4a_hh); +} + +static void inner_fmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + float16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float16_muladd(float16_chs(*n), *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4s_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float16), inner_fmop4s_hh); +} + +static void inner_ah_fmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + float16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float16_muladd(*n, *m, *d, float_muladd_negate_product, fpst); +} + +void HELPER(sme_ah_fmop4s_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float16), inner_ah_fmop4s_hh); +} + static void inner_fmop4a_ss(void *vd, void *vn, void *vm, void *vinfo) { float32 *d = vd, *n = vn, *m = vm; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_mop4_fp(DisasContext *s, arg_mop4 *a, MemOp esz, return true; } +static gen_helper_gvec_3_ptr * const fmop4_hh[3] = { + gen_helper_sme_fmop4a_hh, + gen_helper_sme_fmop4s_hh, + gen_helper_sme_ah_fmop4s_hh +}; +TRANS_FEAT(FMOP4_hh, aa64_sme_mop4_f16f16, + do_mop4_fp, a, MO_16, FPST_ZA_F16, fmop4_hh) + static gen_helper_gvec_3_ptr * const fmop4_ss[3] = { gen_helper_sme_fmop4a_ss, gen_helper_sme_fmop4s_ss, -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/helper-sme-defs.h | 4 +++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 42 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 8 ++++++ 5 files changed, 62 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme_mop4_f16f16(const ARMISARegisters *id) return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f16f16(id); } +static inline bool isar_feature_aa64_sme_mop4_f64f64(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f64f64(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_fmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, DEF_HELPER_FLAGS_5(sme_fmop4a_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_ah_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(sme_fmop4a_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_fmop4s_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_ah_fmop4s_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ &mop4 zm=%mop4_zm zn=%mop4_zn @mop4_o2 .... .... ... m:1 .... .... .. n:1 ... . s:1 .. zad:2 \ &mop4 zm=%mop4_zm zn=%mop4_zn +@mop4_o3 .... .... ... m:1 .... .... .. n:1 ... . s:1 . zad:3 \ + &mop4 zm=%mop4_zm zn=%mop4_zn FMOP4_hh 1000 0001 000. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 +FMOP4_dd 1000 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_ah_fmop4s_ss)(void *vza, void *vzn, void *vzm, { sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_ah_fmop4s_ss); } + +static void inner_fmop4a_dd(void *vd, void *vn, void *vm, void *vinfo) +{ + float64 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float64_muladd(*n, *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4a_dd)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float64), inner_fmop4a_dd); +} + +static void inner_fmop4s_dd(void *vd, void *vn, void *vm, void *vinfo) +{ + float64 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float64_muladd(float64_chs(*n), *m, *d, 0, fpst); +} + +void HELPER(sme_fmop4s_dd)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float64), inner_fmop4s_dd); +} + +static void inner_ah_fmop4s_dd(void *vd, void *vn, void *vm, void *vinfo) +{ + float64 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = float64_muladd(*n, *m, *d, float_muladd_negate_product, fpst); +} + +void HELPER(sme_ah_fmop4s_dd)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float64), inner_ah_fmop4s_dd); +} diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_3_ptr * const fmop4_ss[3] = { gen_helper_sme_ah_fmop4s_ss }; TRANS_FEAT(FMOP4_ss, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ZA, fmop4_ss) + +static gen_helper_gvec_3_ptr * const fmop4_dd[3] = { + gen_helper_sme_fmop4a_dd, + gen_helper_sme_fmop4s_dd, + gen_helper_sme_ah_fmop4s_dd +}; +TRANS_FEAT(FMOP4_dd, aa64_sme_mop4_f64f64, + do_mop4_fp, a, MO_64, FPST_ZA, fmop4_dd) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/helper-sme-defs.h | 4 +++ target/arm/tcg/sme.decode | 1 + target/arm/tcg/sme_helper.c | 42 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 8 ++++++ 5 files changed, 60 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ isar_feature_aa64_sme_f16f16_or_f8f16(const ARMISARegisters *id) return isar_feature_aa64_sme_f16f16(id) || isar_feature_aa64_sme_f8f16(id); } +static inline bool isar_feature_aa64_sme_mop4_b16b16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_b16b16(id); +} + static inline bool isar_feature_aa64_sme_mop4_f16f16(const ARMISARegisters *id) { return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f16f16(id); diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_fmop4s_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, DEF_HELPER_FLAGS_5(sme_fmop4a_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_fmop4s_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_ah_fmop4s_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(sme_bfmop4a_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_bfmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ @mop4_o3 .... .... ... m:1 .... .... .. n:1 ... . s:1 . zad:3 \ &mop4 zm=%mop4_zm zn=%mop4_zn +BFMOP4_hh 1000 0001 001. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_hh 1000 0001 000. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4_dd 1000 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_ah_fmop4s_dd)(void *vza, void *vzn, void *vzm, { sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float64), inner_ah_fmop4s_dd); } + +static void inner_bfmop4a_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + bfloat16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfloat16_muladd(*n, *m, *d, 0, fpst); +} + +void HELPER(sme_bfmop4a_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(bfloat16), inner_bfmop4a_hh); +} + +static void inner_bfmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + bfloat16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfloat16_muladd(bfloat16_chs(*n), *m, *d, 0, fpst); +} + +void HELPER(sme_bfmop4s_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(bfloat16), inner_bfmop4s_hh); +} + +static void inner_ah_bfmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) +{ + bfloat16 *d = vd, *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfloat16_muladd(*n, *m, *d, float_muladd_negate_product, fpst); +} + +void HELPER(sme_ah_bfmop4s_hh)(void *vza, void *vzn, void *vzm, + float_status *fpst, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(bfloat16), inner_ah_bfmop4s_hh); +} diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_mop4_fp(DisasContext *s, arg_mop4 *a, MemOp esz, return true; } +static gen_helper_gvec_3_ptr * const bfmop4_hh[3] = { + gen_helper_sme_bfmop4a_hh, + gen_helper_sme_bfmop4s_hh, + gen_helper_sme_ah_bfmop4s_hh +}; +TRANS_FEAT(BFMOP4_hh, aa64_sme_mop4_b16b16, + do_mop4_fp, a, MO_16, FPST_ZA, bfmop4_hh) + static gen_helper_gvec_3_ptr * const fmop4_hh[3] = { gen_helper_sme_fmop4a_hh, gen_helper_sme_fmop4s_hh, -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 4 ++ target/arm/tcg/sme.decode | 2 + target/arm/tcg/sme_helper.c | 84 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 16 ++++-- 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_fmop4s_dd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, DEF_HELPER_FLAGS_5(sme_bfmop4a_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_bfmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(sme_bfmop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(sme_bfmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ BFMOP4_hh 1000 0001 001. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_hh 1000 0001 000. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4_dd 1000 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 + +BFMOP4_sh 1000 0001 000. ...0 0000 00.. ..0. 00.. @mop4_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_ah_bfmop4s_hh)(void *vza, void *vzn, void *vzm, { sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(bfloat16), inner_ah_bfmop4s_hh); } + +static void inner_bfmop4a_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd(*d, *n, *m, fpst); +} + +static void inner_ebf_bfmop4a_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd_ebf(*d, *n, *m, fpst); +} + +void HELPER(sme_bfmop4a_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + float_status fpst; + + sme_mop4(vza, vzn, vzm, &fpst, desc, sizeof(float32), + is_ebf(env, &fpst) ? inner_ebf_bfmop4a_sh + : inner_bfmop4a_sh); +} + +static void inner_bfmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd(*d, *n ^ 0x80008000u, *m, fpst); +} + +static void inner_ebf_bfmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd_ebf(*d, *n ^ 0x80008000u, *m, fpst); +} + +void HELPER(sme_bfmop4s_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + float_status fpst; + + sme_mop4(vza, vzn, vzm, &fpst, desc, sizeof(float32), + is_ebf(env, &fpst) ? inner_ebf_bfmop4s_sh + : inner_bfmop4s_sh); +} + +static void inner_ah_bfmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd(*d, bf16mop_ah_neg_adj_pair(*n, -1), *m, fpst); +} + +static void inner_ebf_ah_bfmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + float_status *fpst = vinfo; + + *d = bfdotadd_ebf(*d, bf16mop_ah_neg_adj_pair(*n, -1), *m, fpst); +} + +void HELPER(sme_ah_bfmop4s_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + float_status fpst; + + sme_mop4(vza, vzn, vzm, &fpst, desc, sizeof(float32), + is_ebf(env, &fpst) ? inner_ebf_ah_bfmop4s_sh + : inner_ah_bfmop4s_sh); +} diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(LUTI4_s_4b, aa64_sme2p1_lutv2, do_lut_s4, a, gen_helper_sme2_luti4_4b) static bool do_mop4_fp(DisasContext *s, arg_mop4 *a, MemOp esz, - ARMFPStatusFlavour e_fpst, - gen_helper_gvec_3_ptr * const fns[3]) + int e_fpst, gen_helper_gvec_3_ptr * const fns[3]) { int svl = streaming_vec_reg_size(s); uint32_t desc = simd_desc(svl, svl, (a->m << 1) | a->n); @@ -XXX,XX +XXX,XX @@ static bool do_mop4_fp(DisasContext *s, arg_mop4 *a, MemOp esz, za = get_tile(s, esz, a->zad); zn = vec_full_reg_ptr(s, a->zn); zm = vec_full_reg_ptr(s, a->zm); - fpst = fpstatus_ptr(e_fpst); + if (e_fpst >= 0) { + fpst = fpstatus_ptr(e_fpst); + } else { + fpst = tcg_env; + } fns[fns_idx](za, zn, zm, fpst, tcg_constant_i32(desc)); return true; @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_3_ptr * const fmop4_dd[3] = { }; TRANS_FEAT(FMOP4_dd, aa64_sme_mop4_f64f64, do_mop4_fp, a, MO_64, FPST_ZA, fmop4_dd) + +static gen_helper_gvec_3_ptr * const bfmop4_sh[3] = { + gen_helper_sme_bfmop4a_sh, + gen_helper_sme_bfmop4s_sh, + gen_helper_sme_ah_bfmop4s_sh +}; +TRANS_FEAT(BFMOP4_sh, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ENV, bfmop4_sh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 4 +++ target/arm/tcg/sme.decode | 1 + target/arm/tcg/sme_helper.c | 51 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 7 +++++ 4 files changed, 63 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst DEF_HELPER_FLAGS_5(sme_bfmop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_bfmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(sme_fmop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(sme_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(sme_ah_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4_dd 1000 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 BFMOP4_sh 1000 0001 000. ...0 0000 00.. ..0. 00.. @mop4_o2 +FMOP4_sh 1000 0001 001. ...0 0000 00.. ..0. 00.. @mop4_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_ah_bfmop4s_sh)(void *vza, void *vzn, void *vzm, is_ebf(env, &fpst) ? inner_ebf_ah_bfmop4s_sh : inner_ah_bfmop4s_sh); } + +static void inner_fmop4a_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + CPUArchState *env = vinfo; + + *d = f16_dotadd(*d, *n, *m, + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); +} + +void HELPER(sme_fmop4a_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, env, desc, sizeof(float32), inner_fmop4a_sh); +} + +static void inner_fmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + CPUArchState *env = vinfo; + + *d = f16_dotadd(*d, *n ^ 0x80008000u, *m, + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); +} + +void HELPER(sme_fmop4s_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, env, desc, sizeof(float32), inner_fmop4s_sh); +} + +static void inner_ah_fmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + CPUArchState *env = vinfo; + + *d = f16_dotadd(*d, f16mop_ah_neg_adj_pair(*n, -1), *m, + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); +} + +void HELPER(sme_ah_fmop4s_sh)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + sme_mop4(vza, vzn, vzm, env, desc, sizeof(float32), inner_ah_fmop4s_sh); +} diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_3_ptr * const bfmop4_sh[3] = { gen_helper_sme_ah_bfmop4s_sh }; TRANS_FEAT(BFMOP4_sh, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ENV, bfmop4_sh) + +static gen_helper_gvec_3_ptr * const fmop4_sh[3] = { + gen_helper_sme_fmop4a_sh, + gen_helper_sme_fmop4s_sh, + gen_helper_sme_ah_fmop4s_sh +}; +TRANS_FEAT(FMOP4_sh, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ENV, fmop4_sh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/fp8_helper.c | 16 ++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sme.decode | 5 +++++ target/arm/tcg/translate-sme.c | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme_mop4_f64f64(const ARMISARegisters *id) return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f64f64(id); } +static inline bool isar_feature_aa64_sme_mop4_f8f32(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f8f32(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_fvdot_idx_hb)(void *vd, void *vn, void *vm, } while (++i & 7); } while (i < elements); } + +static void inner_fmop4a_sb(void *vd, void *vn, void *vm, void *vinfo) +{ + float32 *d = vd; + uint32_t *n = vn, *m = vm; + FP8MulContext *ctx = vinfo; + + *d = f8dotadd_s(*n, *m, 4, *d, ctx); +} + +void HELPER(sme_fmop4a_sb)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + sme_mop4(vza, vzn, vzm, &ctx, desc, sizeof(float32), inner_fmop4a_sb); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_7(sme_fmopa_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, ptr, DEF_HELPER_FLAGS_5(sme_fvdot_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_fvdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(sme_fmop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ @mop4_o3 .... .... ... m:1 .... .... .. n:1 ... . s:1 . zad:3 \ &mop4 zm=%mop4_zm zn=%mop4_zn +@mop4_o2_s0 .... .... ... m:1 .... .... .. n:1 ... . ... zad:2 \ + &mop4 zm=%mop4_zm zn=%mop4_zn s=0 + BFMOP4_hh 1000 0001 001. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_hh 1000 0001 000. ...0 0000 00.. ..0. 100. @mop4_o1 FMOP4_ss 1000 0000 000. ...0 0000 00.. ..0. 00.. @mop4_o2 @@ -XXX,XX +XXX,XX @@ FMOP4_dd 1000 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 BFMOP4_sh 1000 0001 000. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4_sh 1000 0001 001. ...0 0000 00.. ..0. 00.. @mop4_o2 + +FMOP4A_sb 1000 0000 001. ...0 0000 00.. ..00 00.. @mop4_o2_s0 diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_3_ptr * const fmop4_sh[3] = { gen_helper_sme_ah_fmop4s_sh }; TRANS_FEAT(FMOP4_sh, aa64_sme_mop4, do_mop4_fp, a, MO_32, FPST_ENV, fmop4_sh) + +static bool do_mop4_fp8(DisasContext *s, arg_mop4 *a, MemOp esz, + gen_helper_gvec_3_ptr *fn) +{ + if (fpmr_access_check(s) && sme_smza_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, (a->m << 1) | a->n); + TCGv_ptr za = get_tile(s, esz, a->zad); + TCGv_ptr zn = vec_full_reg_ptr(s, a->zn); + TCGv_ptr zm = vec_full_reg_ptr(s, a->zm); + + fn(za, zn, zm, tcg_env, tcg_constant_i32(desc)); + } + return true; +} + +TRANS_FEAT(FMOP4A_sb, aa64_sme_mop4_f8f32, + do_mop4_fp8, a, MO_32, gen_helper_sme_fmop4a_sb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/fp8_helper.c | 16 ++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/translate-sme.c | 2 ++ 5 files changed, 27 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme_mop4_f8f32(const ARMISARegisters *id) return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f8f32(id); } +static inline bool isar_feature_aa64_sme_mop4_f8f16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f8f16(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_fmop4a_sb)(void *vza, void *vzn, void *vzm, FP8MulContext ctx = fp8_mul_start(env, -1); sme_mop4(vza, vzn, vzm, &ctx, desc, sizeof(float32), inner_fmop4a_sb); } + +static void inner_fmop4a_hb(void *vd, void *vn, void *vm, void *vinfo) +{ + float16 *d = vd; + uint16_t *n = vn, *m = vm; + FP8MulContext *ctx = vinfo; + + *d = f8dotadd_h(*n, *m, 2, *d, ctx); +} + +void HELPER(sme_fmop4a_hb)(void *vza, void *vzn, void *vzm, + CPUArchState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + sme_mop4(vza, vzn, vzm, &ctx, desc, sizeof(float16), inner_fmop4a_hb); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_fvdot_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_5(sme_fvdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_fmop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(sme_fmop4a_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ @mop4_o3 .... .... ... m:1 .... .... .. n:1 ... . s:1 . zad:3 \ &mop4 zm=%mop4_zm zn=%mop4_zn +@mop4_o1_s0 .... .... ... m:1 .... .... .. n:1 ... . .... zad:1 \ + &mop4 zm=%mop4_zm zn=%mop4_zn s=0 @mop4_o2_s0 .... .... ... m:1 .... .... .. n:1 ... . ... zad:2 \ &mop4 zm=%mop4_zm zn=%mop4_zn s=0 @@ -XXX,XX +XXX,XX @@ BFMOP4_sh 1000 0001 000. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4_sh 1000 0001 001. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4A_sb 1000 0000 001. ...0 0000 00.. ..00 00.. @mop4_o2_s0 +FMOP4A_hb 1000 0000 001. ...0 0000 00.. ..00 100. @mop4_o1_s0 diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_mop4_fp8(DisasContext *s, arg_mop4 *a, MemOp esz, TRANS_FEAT(FMOP4A_sb, aa64_sme_mop4_f8f32, do_mop4_fp8, a, MO_32, gen_helper_sme_fmop4a_sb) +TRANS_FEAT(FMOP4A_hb, aa64_sme_mop4_f8f16, + do_mop4_fp8, a, MO_16, gen_helper_sme_fmop4a_hb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 3 +++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/sme_helper.c | 16 ++++++++++++++++ target/arm/tcg/translate-sme.c | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_bfmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_5(sme_fmop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(sme_ah_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(sme_smop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_smop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ FMOP4_sh 1000 0001 001. ...0 0000 00.. ..0. 00.. @mop4_o2 FMOP4A_sb 1000 0000 001. ...0 0000 00.. ..00 00.. @mop4_o2_s0 FMOP4A_hb 1000 0000 001. ...0 0000 00.. ..00 100. @mop4_o1_s0 + +SMOP4_sh 1000 0000 000. ...0 1000 00.. ..0. 10.. @mop4_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_ah_fmop4s_sh)(void *vza, void *vzn, void *vzm, { sme_mop4(vza, vzn, vzm, env, desc, sizeof(float32), inner_ah_fmop4s_sh); } + +#define IMOP4_2WAY(NAME, OP, TYPED, TYPEN, TYPEM) \ +static void inner_##NAME(void *vd, void *vn, void *vm, void *vinfo) \ +{ \ + TYPEN *n = vn; TYPEM *m = vm; TYPED *d = vd; \ + *d OP##= (TYPED)n[0] * m[0] + (TYPED)n[1] * m[1]; \ +} \ +void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, uint32_t desc) \ +{ \ + sme_mop4(vza, vzn, vzm, NULL, desc, sizeof(TYPED), inner_##NAME); \ +} + +IMOP4_2WAY(smop4a_sh, +, int32_t, int16_t, int16_t) +IMOP4_2WAY(smop4s_sh, -, int32_t, int16_t, int16_t) + +#undef IMOP4_2WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(FMOP4A_sb, aa64_sme_mop4_f8f32, do_mop4_fp8, a, MO_32, gen_helper_sme_fmop4a_sb) TRANS_FEAT(FMOP4A_hb, aa64_sme_mop4_f8f16, do_mop4_fp8, a, MO_16, gen_helper_sme_fmop4a_hb) + +static bool do_mop4_int(DisasContext *s, arg_mop4 *a, MemOp esz, + gen_helper_gvec_3 *fn) +{ + if (sme_smza_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, (a->m << 1) | a->n); + TCGv_ptr za = get_tile(s, esz, a->zad); + TCGv_ptr zn = vec_full_reg_ptr(s, a->zn); + TCGv_ptr zm = vec_full_reg_ptr(s, a->zm); + + fn(za, zn, zm, tcg_constant_i32(desc)); + } + return true; +} + +TRANS_FEAT(SMOP4_sh, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_smop4s_sh : gen_helper_sme_smop4a_sh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/helper-sme-defs.h | 4 ++++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/sme_helper.c | 19 +++++++++++++++++++ target/arm/tcg/translate-sme.c | 4 ++++ 5 files changed, 34 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme_mop4_f8f16(const ARMISARegisters *id) return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_f8f16(id); } +static inline bool isar_feature_aa64_sme_mop4_i16i64(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_mop4(id) && isar_feature_aa64_sme_i16i64(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_4(sme_smop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_smop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_smop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_smop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_smop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ FMOP4A_sb 1000 0000 001. ...0 0000 00.. ..00 00.. @mop4_o2_s0 FMOP4A_hb 1000 0000 001. ...0 0000 00.. ..00 100. @mop4_o1_s0 SMOP4_sh 1000 0000 000. ...0 1000 00.. ..0. 10.. @mop4_o2 +SMOP4_sb 1000 0000 000. ...0 1000 00.. ..0. 00.. @mop4_o2 +SMOP4_dh 1010 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ IMOP4_2WAY(smop4a_sh, +, int32_t, int16_t, int16_t) IMOP4_2WAY(smop4s_sh, -, int32_t, int16_t, int16_t) #undef IMOP4_2WAY + +#define IMOP4_4WAY(NAME, OP, TYPED, TYPEN, TYPEM) \ +static void inner_##NAME(void *vd, void *vn, void *vm, void *vinfo) \ +{ \ + TYPEN *n = vn; TYPEM *m = vm; TYPED *d = vd; \ + *d OP##= (TYPED)n[0] * m[0] + (TYPED)n[1] * m[1] + \ + (TYPED)n[2] * m[2] + (TYPED)n[3] * m[3]; \ +} \ +void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, uint32_t desc) \ +{ \ + sme_mop4(vza, vzn, vzm, NULL, desc, sizeof(TYPED), inner_##NAME); \ +} + +IMOP4_4WAY(smop4a_sb, +, int32_t, int8_t, int8_t) +IMOP4_4WAY(smop4s_sb, -, int32_t, int8_t, int8_t) +IMOP4_4WAY(smop4a_dh, +, int64_t, int16_t, int16_t) +IMOP4_4WAY(smop4s_dh, -, int64_t, int16_t, int16_t) + +#undef IMOP4_4WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_mop4_int(DisasContext *s, arg_mop4 *a, MemOp esz, TRANS_FEAT(SMOP4_sh, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_smop4s_sh : gen_helper_sme_smop4a_sh) +TRANS_FEAT(SMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_smop4s_sb : gen_helper_sme_smop4a_sb) +TRANS_FEAT(SMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, + a->s ? gen_helper_sme_smop4s_dh : gen_helper_sme_smop4a_dh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 5 +++++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 5 +++++ target/arm/tcg/translate-sme.c | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme_smop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sme_sumop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_sumop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_sumop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_sumop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ FMOP4A_hb 1000 0000 001. ...0 0000 00.. ..00 100. @mop4_o1_s0 SMOP4_sh 1000 0000 000. ...0 1000 00.. ..0. 10.. @mop4_o2 SMOP4_sb 1000 0000 000. ...0 1000 00.. ..0. 00.. @mop4_o2 SMOP4_dh 1010 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 + +SUMOP4_sb 1000 0000 001. ...0 1000 00.. ..0. 00.. @mop4_o2 +SUMOP4_dh 1010 0000 111. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ IMOP4_4WAY(smop4s_sb, -, int32_t, int8_t, int8_t) IMOP4_4WAY(smop4a_dh, +, int64_t, int16_t, int16_t) IMOP4_4WAY(smop4s_dh, -, int64_t, int16_t, int16_t) +IMOP4_4WAY(sumop4a_sb, +, int32_t, int8_t, uint8_t) +IMOP4_4WAY(sumop4s_sb, -, int32_t, int8_t, uint8_t) +IMOP4_4WAY(sumop4a_dh, +, int64_t, int16_t, uint16_t) +IMOP4_4WAY(sumop4s_dh, -, int64_t, int16_t, uint16_t) + #undef IMOP4_4WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_smop4s_sb : gen_helper_sme_smop4a_sb) TRANS_FEAT(SMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, a->s ? gen_helper_sme_smop4s_dh : gen_helper_sme_smop4a_dh) + +TRANS_FEAT(SUMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_sumop4s_sb : gen_helper_sme_sumop4a_sb) +TRANS_FEAT(SUMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, + a->s ? gen_helper_sme_sumop4s_dh : gen_helper_sme_sumop4a_dh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 3 +++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/sme_helper.c | 3 +++ target/arm/tcg/translate-sme.c | 3 +++ 4 files changed, 11 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme_ah_fmop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_4(sme_smop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_umop4a_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_umop4s_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + DEF_HELPER_FLAGS_4(sme_smop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_smop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ FMOP4A_sb 1000 0000 001. ...0 0000 00.. ..00 00.. @mop4_o2_s0 FMOP4A_hb 1000 0000 001. ...0 0000 00.. ..00 100. @mop4_o1_s0 SMOP4_sh 1000 0000 000. ...0 1000 00.. ..0. 10.. @mop4_o2 +UMOP4_sh 1000 0001 000. ...0 1000 00.. ..0. 10.. @mop4_o2 + SMOP4_sb 1000 0000 000. ...0 1000 00.. ..0. 00.. @mop4_o2 SMOP4_dh 1010 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, uint32_t desc) \ IMOP4_2WAY(smop4a_sh, +, int32_t, int16_t, int16_t) IMOP4_2WAY(smop4s_sh, -, int32_t, int16_t, int16_t) +IMOP4_2WAY(umop4a_sh, +, int32_t, uint16_t, uint16_t) +IMOP4_2WAY(umop4s_sh, -, int32_t, uint16_t, uint16_t) + #undef IMOP4_2WAY #define IMOP4_4WAY(NAME, OP, TYPED, TYPEN, TYPEM) \ diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_mop4_int(DisasContext *s, arg_mop4 *a, MemOp esz, TRANS_FEAT(SMOP4_sh, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_smop4s_sh : gen_helper_sme_smop4a_sh) +TRANS_FEAT(UMOP4_sh, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_umop4s_sh : gen_helper_sme_umop4a_sh) + TRANS_FEAT(SMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_smop4s_sb : gen_helper_sme_smop4a_sb) TRANS_FEAT(SMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 5 +++++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 5 +++++ target/arm/tcg/translate-sme.c | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme_sumop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_sumop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_sumop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_sumop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sme_umop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_umop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_umop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_umop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ SMOP4_dh 1010 0000 110. ...0 0000 00.. ..0. 1... @mop4_o3 SUMOP4_sb 1000 0000 001. ...0 1000 00.. ..0. 00.. @mop4_o2 SUMOP4_dh 1010 0000 111. ...0 0000 00.. ..0. 1... @mop4_o3 + +UMOP4_sb 1000 0001 001. ...0 1000 00.. ..0. 00.. @mop4_o2 +UMOP4_dh 1010 0001 111. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ IMOP4_4WAY(sumop4s_sb, -, int32_t, int8_t, uint8_t) IMOP4_4WAY(sumop4a_dh, +, int64_t, int16_t, uint16_t) IMOP4_4WAY(sumop4s_dh, -, int64_t, int16_t, uint16_t) +IMOP4_4WAY(umop4a_sb, +, int32_t, uint8_t, uint8_t) +IMOP4_4WAY(umop4s_sb, -, int32_t, uint8_t, uint8_t) +IMOP4_4WAY(umop4a_dh, +, int64_t, uint16_t, uint16_t) +IMOP4_4WAY(umop4s_dh, -, int64_t, uint16_t, uint16_t) + #undef IMOP4_4WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(SUMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_sumop4s_sb : gen_helper_sme_sumop4a_sb) TRANS_FEAT(SUMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, a->s ? gen_helper_sme_sumop4s_dh : gen_helper_sme_sumop4a_dh) + +TRANS_FEAT(UMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_umop4s_sb : gen_helper_sme_umop4a_sb) +TRANS_FEAT(UMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, + a->s ? gen_helper_sme_umop4s_dh : gen_helper_sme_umop4a_dh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 5 +++++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 5 +++++ target/arm/tcg/translate-sme.c | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme_umop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_umop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_umop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(sme_umop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sme_usmop4a_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_usmop4s_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_usmop4a_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sme_usmop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ SUMOP4_dh 1010 0000 111. ...0 0000 00.. ..0. 1... @mop4_o3 UMOP4_sb 1000 0001 001. ...0 1000 00.. ..0. 00.. @mop4_o2 UMOP4_dh 1010 0001 111. ...0 0000 00.. ..0. 1... @mop4_o3 + +USMOP4_sb 1000 0001 000. ...0 1000 00.. ..0. 00.. @mop4_o2 +USMOP4_dh 1010 0001 110. ...0 0000 00.. ..0. 1... @mop4_o3 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ IMOP4_4WAY(umop4s_sb, -, int32_t, uint8_t, uint8_t) IMOP4_4WAY(umop4a_dh, +, int64_t, uint16_t, uint16_t) IMOP4_4WAY(umop4s_dh, -, int64_t, uint16_t, uint16_t) +IMOP4_4WAY(usmop4a_sb, +, int32_t, uint8_t, int8_t) +IMOP4_4WAY(usmop4s_sb, -, int32_t, uint8_t, int8_t) +IMOP4_4WAY(usmop4a_dh, +, int64_t, uint16_t, int16_t) +IMOP4_4WAY(usmop4s_dh, -, int64_t, uint16_t, int16_t) + #undef IMOP4_4WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(UMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, a->s ? gen_helper_sme_umop4s_sb : gen_helper_sme_umop4a_sb) TRANS_FEAT(UMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, a->s ? gen_helper_sme_umop4s_dh : gen_helper_sme_umop4a_dh) + +TRANS_FEAT(USMOP4_sb, aa64_sme_mop4, do_mop4_int, a, MO_32, + a->s ? gen_helper_sme_usmop4s_sb : gen_helper_sme_usmop4a_sb) +TRANS_FEAT(USMOP4_dh, aa64_sme_mop4_i16i64, do_mop4_int, a, MO_64, + a->s ? gen_helper_sme_usmop4s_dh : gen_helper_sme_usmop4a_dh) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702204314.79224-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_F8F32 (SME2 ZA-targeting FP8 multiply-accumulate, dot product, and outer product to single-precision instructions) - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) +- FEAT_SME_MOP4 (Quarter-tile outer product instructions) - FEAT_SSVE_AES (Streaming SVE Mode Advanced Encryption Standard and 128-bit polynomial multiply long instructions) - FEAT_SSVE_FEXPA (Streaming FEXPA instruction) - FEAT_SSVE_FP8DOT2 (SVE2 FP8 2-way dot product to half-precision instructions in Streaming SVE mode) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_ssve_aes, ARM_HWCAP_A64_SME_AES); GET_FEATURE_ID(aa64_ssve_fexpa, ARM_HWCAP_A64_SME_SFEXPA); GET_FEATURE_ID(aa64_fprcvt, ARM_HWCAP_A64_FPRCVT); + GET_FEATURE_ID(aa64_sme_mop4, ARM_HWCAP_A64_SME_SMOP4); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64SMFR0); t = FIELD_DP64(t, ID_AA64SMFR0, SFEXPA, 1); /* FEAT_SSVE_FEXPA */ + t = FIELD_DP64(t, ID_AA64SMFR0, SMOP4, 1); /* FEAT_SME_MOP4 */ t = FIELD_DP64(t, ID_AA64SMFR0, AES, 1); /* FEAT_SSVE_AES */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP2, 1); /* FEAT_SSVE_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP4, 1); /* FEAT_SSVE_FP8DOT4 */ -- 2.43.0
Currently we use vfp_access_check() for AArch32 VFP and Neon instructions. This is not quite right: * there are optional CPACR.ASEDIS and HCPTR.TASE controls that allow trapping of just the Neon and not VFP instructions * Neon instructions are supposed to report a slightly different syndrome in HCR when they trap to AArch32 EL2 As a preliminary refactor so we have somewhere we can make this distinction, separate out Neon access checks into a separate neon_access_check(), which initially just calls vfp_access_check(). The set of insns this needs to cover are those described in section E1.3.9 of the DDI0487M.b Arm ARM. For us this corresponds to everything in neon-dp.decode and neon-ls.decode and thus in translate-neon.c, plus three insns that we handle in translate-vfp.c: - VDUP (general-purpose register) - VMOV (general-purpose register to scalar) byte and halfword - VMOV (scalar to general-purpose register) byte and halfword (which are the ones in that file with ARM_FEATURE_NEON checks). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-2-peter.maydell@linaro.org --- target/arm/tcg/translate-a32.h | 1 + target/arm/tcg/translate-neon.c | 74 ++++++++++++++++----------------- target/arm/tcg/translate-vfp.c | 33 +++++++++++---- 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/target/arm/tcg/translate-a32.h b/target/arm/tcg/translate-a32.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a32.h +++ b/target/arm/tcg/translate-a32.h @@ -XXX,XX +XXX,XX @@ void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); void arm_gen_condlabel(DisasContext *s); bool vfp_access_check(DisasContext *s); bool vfp_access_check_m(DisasContext *s, bool skip_context_update); +bool neon_access_check(DisasContext *s); void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop); void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop); void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop); diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -XXX,XX +XXX,XX @@ static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_neon_ddda_env(DisasContext *s, int q, int vd, int vn, int vm, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VCADD(DisasContext *s, arg_VCADD *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VFML(DisasContext *s, arg_VFML *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) } } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_narrow_3d(DisasContext *s, arg_3diff *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_long_3d(DisasContext *s, arg_3diff *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2scalar(DisasContext *s, arg_2scalar *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VEXT(DisasContext *s, arg_VEXT *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_zip_uzp(DisasContext *s, arg_2misc *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_vmovn(DisasContext *s, arg_2misc *a, return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VTRN(DisasContext *s, arg_2misc *a) return false; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -XXX,XX +XXX,XX @@ bool vfp_access_check(DisasContext *s) } } +/* + * Access check for Neon; this is for instructions which can be + * trapped by CPACR.ASEDIS and HCPTR.TASE. Support for those traps + * is optional and we currently do not implement them, so this + * is identical to a VFP access check for now. + */ +bool neon_access_check(DisasContext *s) +{ + return vfp_access_check(s); +} + static bool trans_VSEL(DisasContext *s, arg_VSEL *a) { uint32_t rd, rn, rm; @@ -XXX,XX +XXX,XX @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) { /* VMOV scalar to general purpose register */ TCGv_i32 tmp; + bool insn_is_neon = false; /* * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has * all sizes, whether the CPU has fp or not. */ if (!dc_isar_feature(aa32_mve, s)) { - if (a->size == MO_32 - ? !dc_isar_feature(aa32_fpsp_v2, s) - : !arm_dc_feature(s, ARM_FEATURE_NEON)) { + insn_is_neon = a->size != MO_32; + if (insn_is_neon + ? !arm_dc_feature(s, ARM_FEATURE_NEON) + : !dc_isar_feature(aa32_fpsp_v2, s)) { return false; } } @@ -XXX,XX +XXX,XX @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) } } - if (!vfp_access_check(s)) { + if (!(insn_is_neon ? neon_access_check(s) : vfp_access_check(s))) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) { /* VMOV general purpose register to scalar */ TCGv_i32 tmp; + bool insn_is_neon = false; /* * SIZE == MO_32 is a VFP instruction; otherwise NEON. MVE has * all sizes, whether the CPU has fp or not. */ if (!dc_isar_feature(aa32_mve, s)) { - if (a->size == MO_32 - ? !dc_isar_feature(aa32_fpsp_v2, s) - : !arm_dc_feature(s, ARM_FEATURE_NEON)) { + insn_is_neon = a->size != MO_32; + if (insn_is_neon + ? !arm_dc_feature(s, ARM_FEATURE_NEON) + : !dc_isar_feature(aa32_fpsp_v2, s)) { return false; } } @@ -XXX,XX +XXX,XX @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) } } - if (!vfp_access_check(s)) { + if (!(insn_is_neon ? neon_access_check(s) : vfp_access_check(s))) { return true; } @@ -XXX,XX +XXX,XX @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a) size = 2; } - if (!vfp_access_check(s)) { + if (!neon_access_check(s)) { return true; } -- 2.43.0
Currently we have one syn_fp_access_trap() which we use for fp traps from A64 and from VFP and Neon A32. This means that A64 has to specify arguments that are always fixed for it (coproc and is_16bit) and A32 can't specify arguments it needs to (TA). Split it up into syn_a64_fp_access_trap() and syn_a32_fp_access_trap(). This is a refactor with no behavioural change. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-3-peter.maydell@linaro.org --- target/arm/syndrome.h | 28 ++++++++++++++++++++++------ target/arm/tcg/translate-a64.c | 2 +- target/arm/tcg/translate-vfp.c | 2 +- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, /* * ISS encoding for an exception from an access to a register of - * instruction resulting from the FPEN or TFP traps. + * instruction resulting from the FPEN or TFP traps. Note that + * the TA and COPROC fields are only valid when an AArch32 insn + * traps to AArch32 EL2; they are RES0 for traps to AArch64. */ -FIELD(FP_ISS, COPROC, 0, 4) /* ARMv7 only */ +FIELD(FP_ISS, COPROC, 0, 4) +FIELD(FP_ISS, TA, 5, 1) FIELD(FP_ISS, COND, 20, 4) FIELD(FP_ISS, CV, 24, 1) -static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit, - int coproc) +static inline uint32_t syn_a64_fp_access_trap(int cv, int cond) { - /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */ + /* AArch64 FP/SIMD trap: TA and coproc are RES0, insn is 64 bits */ uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP); - res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + res = FIELD_DP32(res, SYNDROME, IL, 1); res = FIELD_DP32(res, FP_ISS, CV, cv); res = FIELD_DP32(res, FP_ISS, COND, cond); + + return res; +} + +static inline uint32_t syn_a32_fp_access_trap(int cv, int cond, + int ta, int coproc) +{ + /* AArch32 VFP or Neon trap: TA and coproc valid, insn is 64 bits */ + uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, FP_ISS, CV, cv); + res = FIELD_DP32(res, FP_ISS, COND, cond); + res = FIELD_DP32(res, FP_ISS, TA, ta); res = FIELD_DP32(res, FP_ISS, COPROC, coproc); return res; diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool fp_access_check_only(DisasContext *s) s->fp_access_checked = -1; gen_exception_insn_el(s, 0, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, false, 0), + syn_a64_fp_access_trap(1, 0xe), s->fp_excp_el); return false; } diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -XXX,XX +XXX,XX @@ static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled) * this field to 0xA. */ int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa; - uint32_t syn = syn_fp_access_trap(1, 0xe, false, coproc); + uint32_t syn = syn_a32_fp_access_trap(1, 0xe, 0, coproc); gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el); return false; -- 2.43.0
When an AArch32 Neon or VFP insn is trapped to AArch64 EL2, bits [19:0] of the syndrome in ESR_EL2 are RES0. However, when it is trapped to AArch32 EL2, the HSR syndrome information defines some extra fields: [5] : TA [3:0] : coproc where the TA bit is 1 for a trapped Neon insn and 0 for a trapped VFP insn, and the coproc field is 0b1010 when TA is 0, and 0 when TA is 1. We attempted to address this in commit fa33eead ("target/arm: Add coproc parameter to syn_fp_access_trap"), but got it wrong: we thought the RES0 condition was "is v8A" rather than "is EL2 AArch32", and we made all insns be TA=0 coproc = 0b1010 rather than only the VFP ones. Correct the condition we use to decide the coproc and TA fields. We set these fields unconditionally; later on in arm_cpu_do_interrupt_aarch64() we will squash them to zero if we are taking the exception to AArch64. NB: there is some disagreement between different revisions of the Arm ARM about the exact handling of 'coproc': * the v8A Arm ARM text says coproc is 0b1010 when TA is 1 * the v8A Arm ARM pseudocode in AArch32_CheckFPAdvSIMDTrap() sets coproc to 0b1010 when TA is 0 * the v7A Arm ARM text says coproc is 0b1010 when TA is 0 * the v7A Arm ARM pseudocode sets coproc to 0b1010 when TA is 0 The v7A Arm ARM pseudocode also disagrees with the v7A text, v8A text and v8A pseudocode in only setting TA to 1 for traps caused by HCPTR.TASE; the others set Ta for all trapped AdvSIMD insns (i.e. including traps caused by HCPTR.TCP10). We assume that the v8A pseudocode is incorrect about coproc (as it is the odd one out) and that the v7A pseudocode is incorrect about when TA is set (again, as it is the odd one out). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1153 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-4-peter.maydell@linaro.org --- target/arm/tcg/translate-vfp.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -XXX,XX +XXX,XX @@ static void gen_update_fp_context(DisasContext *s) * whether VFP is enabled via FPEXC.EN: this should be true for FMXR/FMRX * accesses to FPSID, FPEXC, MVFR0, MVFR1, MVFR2, and false for all other insns. */ -static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled) +static bool vfp_access_check_a(DisasContext *s, bool ignore_vfp_enabled, + bool is_neon) { if (s->fp_excp_el) { /* - * The full syndrome is only used for HSR when HCPTR traps: - * For v8, when TA==0, coproc is RES0. - * For v7, any use of a Floating-point instruction or access - * to a Floating-point Extension register that is trapped to - * Hyp mode because of a trap configured in the HCPTR sets - * this field to 0xA. + * The full syndrome is only used for HSR when HCPTR traps. + * When trapping to AArch64, the TA and coproc fields are RES0 + * (we will squash them in arm_cpu_do_interrupt_aarch64()). + * When trapping to AArch32: + * - for VFP insns, TA=0 and coproc = 0b1010 + * - for Neon insns, TA=1 and coproc = 0 */ - int coproc = arm_dc_feature(s, ARM_FEATURE_V8) ? 0 : 0xa; - uint32_t syn = syn_a32_fp_access_trap(1, 0xe, 0, coproc); + int coproc = is_neon ? 0 : 0xa; + uint32_t syn = syn_a32_fp_access_trap(1, 0xe, is_neon, coproc); gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->fp_excp_el); return false; @@ -XXX,XX +XXX,XX @@ bool vfp_access_check(DisasContext *s) if (arm_dc_feature(s, ARM_FEATURE_M)) { return vfp_access_check_m(s, false); } else { - return vfp_access_check_a(s, false); + return vfp_access_check_a(s, false, false); } } @@ -XXX,XX +XXX,XX @@ bool vfp_access_check(DisasContext *s) */ bool neon_access_check(DisasContext *s) { - return vfp_access_check(s); + if (arm_dc_feature(s, ARM_FEATURE_M)) { + return vfp_access_check_m(s, false); + } else { + return vfp_access_check_a(s, false, true); + } } static bool trans_VSEL(DisasContext *s, arg_VSEL *a) @@ -XXX,XX +XXX,XX @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) * Call vfp_access_check_a() directly, because we need to tell * it to ignore FPEXC.EN for some register accesses. */ - if (!vfp_access_check_a(s, ignore_vfp_enabled)) { + if (!vfp_access_check_a(s, ignore_vfp_enabled, false)) { return true; } -- 2.43.0
Currently we handle cp15.nsacr with raw bit numbers in the few places we need to work with it. We're about to add some more uses of this field, so define its fields with the FIELD macro and use the macros in the places that were previously using bit numbers. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260702184019.3431139-5-peter.maydell@linaro.org --- target/arm/cpu.c | 2 +- target/arm/helper.c | 10 +++++----- target/arm/internals.h | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ void arm_emulate_firmware_reset(CPUState *cpustate, int target_el) /* Put CPU into non-secure state */ env->cp15.scr_el3 |= SCR_NS; /* Set NSACR.{CP11,CP10} so NS can access the FPU */ - env->cp15.nsacr |= 3 << 10; + env->cp15.nsacr |= R_NSACR_CP10_MASK | R_NSACR_CP11_MASK; } if (have_el2 && target_el < 2) { diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, * is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00. */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { + !arm_is_secure(env) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { mask = R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); } @@ -XXX,XX +XXX,XX @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t value = env->cp15.cpacr_el1; if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { + !arm_is_secure(env) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { value = ~(R_CPACR_CP11_MASK | R_CPACR_CP10_MASK); } return value; @@ -XXX,XX +XXX,XX @@ static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, * is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1. */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { + !arm_is_secure(env) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { uint64_t mask = R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; value = (value & ~mask) | (env->cp15.cptr_el[2] & mask); } @@ -XXX,XX +XXX,XX @@ static uint64_t cptr_el2_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t value = env->cp15.cptr_el[2]; if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) { + !arm_is_secure(env) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { value |= R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; } return value; @@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el) */ if ((arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && cur_el <= 2 && !arm_is_secure_below_el3(env))) { - if (!extract32(env->cp15.nsacr, 10, 1)) { + if (!FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { /* FP insns act as UNDEF */ return cur_el == 2 ? 2 : 1; } diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ FIELD(CPACR_EL1, FPEN, 20, 2) FIELD(CPACR_EL1, SMEN, 24, 2) FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */ +/* Bit definitions for NSACR (AArch32 only) */ +FIELD(NSACR, CP10, 10, 1) +FIELD(NSACR, CP11, 11, 1) +FIELD(NSACR, NSD32DIS, 14, 1) /* v7; RES0 in v8 */ +FIELD(NSACR, NSASEDIS, 15, 1) +FIELD(NSACR, RFR, 19, 1) /* v7; RES0 in v8 */ +FIELD(NSACR, NSTRCDIS, 20, 1) + /* Bit definitions for HCPTR (AArch32 only) */ FIELD(HCPTR, TCP10, 10, 1) FIELD(HCPTR, TCP11, 11, 1) -- 2.43.0
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb