: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
Hi; here's another arm pullreq; main parts here are the new i.MX 8MM EVK board, and a lot of refactoring. thanks -- PMM The following changes since commit aa15257174da180c6a8a9d58f87319cfe61c5520: Merge tag 'pbouvier/pr/plugins-20260424' of https://gitlab.com/p-b-o/qemu into staging (2026-04-25 10:22:04 -0400) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260427 for you to fetch changes up to 4575da5ecb7a27544aa6da1f78e700e8100ceaea: target/arm: report register in WFIT syndromes (2026-04-27 11:46:34 +0100) ---------------------------------------------------------------- target-arm queue: docs/system: add FEAT_AA32 and FEAT_AA64 to emulation list hw/arm: Add the i.MX 8MM EVK(Evaluation Kit) board target/arm: Build M-profile helper code once only hw/arm: Remove hw_error() for the unimplemented CM_LMBUSCNT register hw: Move ARM_SYSCTL_GPIO definitions to arm sysctl specific header target/arm: Allow 'aarch64=off' to be set for TCG CPUs target/arm: Allow some sysregs to not have to be an exact match for migration hw/arm/raspi4b: NOP all DTB nodes when removing unimplemented devices hw/arm/fsl-imx6ul: Implement LCDIF display device target/arm: Refactor syndrome value code to use registerfields target/arm: Report the register in WFxT syndromes ---------------------------------------------------------------- Alex Bennée (24): docs/system: add FEAT_AA32 and FEAT_AA64 to emulation list target/arm: migrate basic syndrome helpers to registerfields target/arm: migrate system/cp trap syndromes to registerfields target/arm: migrate FP/SIMD trap syndromes to registerfields target/arm: migrate eret trap syndromes to registerfields target/arm: migrate SME trap syndromes to registerfields target/arm: migrate PAC trap syndromes to registerfields target/arm: migrate BTI trap syndromes to registerfields target/arm: migrate BXJ trap syndromes to registerfields target/arm: migrate Granule Protection traps to registerfields target/arm: migrate fault syndromes to registerfields target/arm: migrate debug syndromes to registerfields target/arm: migrate wfx syndromes to registerfields target/arm: migrate gcs syndromes to registerfields target/arm: migrate memory op syndromes to registerfields target/arm: migrate check_hcr_el2_trap to use syndrome helper target/arm: use syndrome helpers in arm_cpu_do_interrupt_aarch32_hyp target/arm: use syndrome helpers to set SAME_EL EC bit target/arm: make whpx use syndrome helpers for decode target/arm: make hvf use syndrome helpers for decode target/arm: use syndrome helpers in merge_syn_data_abort target/arm: use syndrome helpers to query VNCR bit target/arm: remove old syndrome defines target/arm: report register in WFIT syndromes Eric Auger (7): target/arm/cpu: Introduce the infrastructure for cpreg migration tolerances target/arm/machine: Handle ToleranceNotOnBothEnds migration tolerances target/arm/machine: Handle ToleranceOnlySrcTestValue migration tolerance target/arm/cpu64: Mitigate migration failures due to spurious TCR_EL1, PIRE0_EL1 and PIR_EL1 target/arm/cpu64: Define cpreg migration tolerance for KVM_REG_ARM_VENDOR_HYP_BMAP_2 target/arm/helper: Define cpreg migration tolerance for DGBDTR_EL0 Revert "target/arm: Reinstate bogus AArch32 DBGDTRTX register for migration compat" Gaurav Sharma (15): hw/arm: Add the i.MX 8MM EVK(Evaluation Kit) board hw/misc/imx8mp_analog: Add property to analog device hw/arm/fsl-imx8mm: Add Analog device IP to iMX8MM SOC hw/arm/fsl-imx8mm: Add Clock Control Module IP to iMX8MM hw/arm/fsl-imx8mm: Implemented support for SNVS hw/arm/fsl-imx8mm: Adding support for USDHC storage controllers hw/arm/fsl-imx8mm: Add PCIe support hw/arm/fsl-imx8mm: Add GPIO controllers hw/arm/fsl-imx8mm: Adding support for I2C emulation hw/arm/fsl-imx8mm: Adding support for SPI controller hw/arm/fsl-imx8mm: Adding support for Watchdog Timers hw/arm/fsl-imx8mm: Adding support for General Purpose Timers hw/arm/fsl-imx8mm: Adding support for ENET ethernet controller hw/arm/fsl-imx8mm: Adding support for USB controller hw/arm/fsl-imx8mm: Adding functional testing of iMX8MM emulation Osama Abdelkader (1): hw/arm/raspi4b: NOP all DTB nodes when removing unimplemented devices Peter Maydell (4): hw: Move ARM_SYSCTL_GPIO definitions to arm sysctl specific header target/arm: Clear AArch64 ID regs from ARMISARegisters if AArch64 disabled target/arm: Allow 'aarch64=off' to be set for TCG CPUs tests/functional/aarch64: Add basic test of TCG aarch64=off Philippe Mathieu-Daudé (9): target/arm: Ignore endianness when setting MTE tags target/arm: Explode MO_TExx -> MO_TE | MO_xx target/arm: Hoist MO_TE into mve_advance_vpt() target/arm: Hoist MO_TE into MVE DO_VSTR() macro target/arm: Introduce mo_endian() helper target/arm: Replace MO_TE -> mo_endian() for MVE helpers target/arm: Compile mve_helper.c once target/arm: Replace MO_TE -> mo_endian() for Cortex-M helpers target/arm: Compile m_helper.c once Thomas Huth (1): hw/arm: Remove hw_error() for the unimplemented CM_LMBUSCNT register Yucai Liu (2): hw/display: Add i.MX6UL LCDIF device model hw/arm/fsl-imx6ul: Wire in the LCDIF device model MAINTAINERS | 16 +- docs/system/arm/cpu-features.rst | 10 +- docs/system/arm/emulation.rst | 2 + docs/system/arm/{imx8mp-evk.rst => imx8m.rst} | 49 +- docs/system/target-arm.rst | 2 +- hw/arm/Kconfig | 25 + hw/arm/fsl-imx6ul.c | 12 +- hw/arm/fsl-imx8mm.c | 704 ++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 130 ++++ hw/arm/integratorcp.c | 3 - hw/arm/meson.build | 2 + hw/arm/raspi4b.c | 10 +- hw/arm/realview.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/virt.c | 1 - hw/display/Kconfig | 4 + hw/display/imx6ul_lcdif.c | 453 ++++++++++++++ hw/display/meson.build | 1 + hw/misc/arm_sysctl.c | 2 +- hw/misc/imx8mp_analog.c | 12 +- hw/timer/imx_gpt.c | 26 + hw/vmapple/vmapple.c | 1 - include/hw/arm/fsl-imx6ul.h | 4 +- include/hw/arm/fsl-imx8mm.h | 242 ++++++++ include/hw/arm/primecell.h | 12 - include/hw/display/imx6ul_lcdif.h | 37 ++ include/hw/misc/arm_sysctl.h | 16 + include/hw/misc/imx8mp_analog.h | 3 + include/hw/timer/imx_gpt.h | 2 + target/arm/cpu-features.h | 5 + target/arm/cpu.c | 153 ++++- target/arm/cpu.h | 4 +- target/arm/cpu64.c | 39 ++ target/arm/debug_helper.c | 29 - target/arm/helper.c | 27 +- target/arm/hvf/hvf.c | 14 +- target/arm/internals.h | 60 ++ target/arm/machine.c | 33 +- target/arm/syndrome.h | 595 ++++++++++++++---- target/arm/tcg/debug.c | 2 +- target/arm/tcg/helper-a64.c | 2 +- target/arm/tcg/helper-defs.h | 2 +- target/arm/tcg/m_helper.c | 8 +- target/arm/tcg/meson.build | 6 +- target/arm/tcg/mve_helper.c | 102 ++-- target/arm/tcg/op_helper.c | 7 +- target/arm/tcg/tlb_helper.c | 6 +- target/arm/tcg/translate-a64.c | 2 +- target/arm/tcg/vfp_helper.c | 5 +- target/arm/trace-events | 2 + target/arm/whpx/whpx-all.c | 13 +- tests/functional/aarch64/meson.build | 3 + tests/functional/aarch64/test_imx8mm_evk.py | 69 +++ tests/functional/aarch64/test_virt_aarch64_off.py | 37 ++ tests/qtest/arm-cpu-features.c | 8 +- 55 files changed, 2743 insertions(+), 275 deletions(-) rename docs/system/arm/{imx8mp-evk.rst => imx8m.rst} (58%) create mode 100644 hw/arm/fsl-imx8mm.c create mode 100644 hw/arm/imx8mm-evk.c create mode 100644 hw/display/imx6ul_lcdif.c create mode 100644 include/hw/arm/fsl-imx8mm.h delete mode 100644 include/hw/arm/primecell.h create mode 100644 include/hw/display/imx6ul_lcdif.h create mode 100644 include/hw/misc/arm_sysctl.h create mode 100755 tests/functional/aarch64/test_imx8mm_evk.py create mode 100755 tests/functional/aarch64/test_virt_aarch64_off.py
From: Alex Bennée <alex.bennee@linaro.org> This is just a documentation tweak as we already support both. FEAT_AA32 implies FEAT_AA32EL0. FEAT_AA64 implies FEAT_AA64EL[0123]. This is however useful if you are using emulation.rst as a source of truth of what QEMU emulates and when cross checking with Features.json from Arm. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260421093506.616307-1-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 2 ++ 1 file changed, 2 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 @@ QEMU's TCG emulation includes support for the Armv5, Armv6, Armv7, Armv8 and Armv9 versions of the A-profile architecture. It also has support for the following architecture extensions: +- FEAT_AA32 (PE Support for AArch32) - FEAT_AA32BF16 (AArch32 BFloat16 instructions) - FEAT_AA32EL0 (Support for AArch32 at EL0) - FEAT_AA32EL1 (Support for AArch32 at EL1) @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_AA32EL3 (Support for AArch32 at EL3) - FEAT_AA32HPD (AArch32 hierarchical permission disables) - FEAT_AA32I8MM (AArch32 Int8 matrix multiplication instructions) +- FEAT_AA64 (PE uses AArch64 after last reboot) - FEAT_AA64EL0 (Support for AArch64 at EL0) - FEAT_AA64EL1 (Support for AArch64 at EL1) - FEAT_AA64EL2 (Support for AArch64 at EL2) -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Implemented CPUs, RAM, UARTs and Interrupt Controller Other peripherals are represented as TYPE_UNIMPLEMENTED_DEVICE Complete memory map of the SoC is provided. Set default RAM size to 2GB and default CPU count to 4 to match the real i.MX8MM EVK hardware configuration. Documentation is shared with imx8mp-evk to avoid duplication. Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> [PMM: fixed over-long lines in doc] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 11 +- docs/system/arm/{imx8mp-evk.rst => imx8m.rst} | 49 ++- docs/system/target-arm.rst | 2 +- hw/arm/Kconfig | 12 + hw/arm/fsl-imx8mm.c | 377 ++++++++++++++++++ hw/arm/imx8mm-evk.c | 112 ++++++ hw/arm/meson.build | 2 + include/hw/arm/fsl-imx8mm.h | 158 ++++++++ 8 files changed, 709 insertions(+), 14 deletions(-) rename docs/system/arm/{imx8mp-evk.rst => imx8m.rst} (58%) create mode 100644 hw/arm/fsl-imx8mm.c create mode 100644 hw/arm/imx8mm-evk.c create mode 100644 include/hw/arm/fsl-imx8mm.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/pci-host/designware.c F: include/hw/pci-host/designware.h F: docs/system/arm/mcimx7d-sabre.rst +MCIMX8MM-EVK / iMX8MM +M: Gaurav Sharma <gaurav.sharma_7@nxp.com> +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/fsl-imx8mm.c +F: hw/arm/imx8mm-evk.c +F: include/hw/arm/fsl-imx8mm.h +F: docs/system/arm/imx8m.rst + MCIMX8MP-EVK / i.MX8MP M: Bernhard Beschow <shentey@gmail.com> L: qemu-arm@nongnu.org @@ -XXX,XX +XXX,XX @@ F: hw/rtc/rs5c372.c F: include/hw/arm/fsl-imx8mp.h F: include/hw/misc/imx8mp_*.h F: include/hw/pci-host/fsl_imx8m_phy.h -F: docs/system/arm/imx8mp-evk.rst +F: docs/system/arm/imx8m.rst F: tests/functional/aarch64/test_imx8mp_evk.py F: tests/qtest/rs5c372-test.c diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8m.rst similarity index 58% rename from docs/system/arm/imx8mp-evk.rst rename to docs/system/arm/imx8m.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/imx8mp-evk.rst +++ b/docs/system/arm/imx8m.rst @@ -XXX,XX +XXX,XX @@ -NXP i.MX 8M Plus Evaluation Kit (``imx8mp-evk``) -================================================ +NXP i.MX 8M Plus and i.MX 8M Mini Evaluation Kits (``imx8mp-evk``, ``imx8mm-evk``) +================================================================================== -The ``imx8mp-evk`` machine models the i.MX 8M Plus Evaluation Kit, based on an -i.MX 8M Plus SoC. +The ``imx8mp-evk`` and ``imx8mm-evk`` machine models the i.MX 8M Plus +and i.MX 8M Mini Evaluation Kits, based on i.MX 8M Plus and i.MX8M +Mini SoCs. Supported devices ----------------- -The ``imx8mp-evk`` machine implements the following devices: +The ``imx8mp-evk`` and ``imx8mm-evk`` machines implement the +following devices: * Up to 4 Cortex-A53 cores * Generic Interrupt Controller (GICv3) @@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices: Boot options ------------ -The ``imx8mp-evk`` machine can start a Linux kernel directly using the standard -``-kernel`` functionality. +The ``imx8mp-evk`` and ``imx8mm-evk`` machines can start a Linux +kernel directly using the standard ``-kernel`` functionality. Direct Linux Kernel Boot '''''''''''''''''''''''' @@ -XXX,XX +XXX,XX @@ is to generate an image with Buildroot. Version 2024.11.1 is tested at the time of writing and involves two steps. First run the following commands in the toplevel directory of the Buildroot source tree: +For i.MX 8M Plus EVK: + .. code-block:: bash $ make freescale_imx8mpevk_defconfig $ make +For i.MX 8M Mini EVK: + +.. code-block:: bash + + $ make freescale_imx8mmevk_defconfig + $ make + Once finished successfully there is an ``output/image`` subfolder. Navigate into it and resize the SD card image to a power of two: @@ -XXX,XX +XXX,XX @@ it and resize the SD card image to a power of two: Now that everything is prepared the machine can be started as follows: +For i.MX 8M Plus EVK: + .. code-block:: bash $ qemu-system-aarch64 -M imx8mp-evk \ @@ -XXX,XX +XXX,XX @@ Now that everything is prepared the machine can be started as follows: -append "root=/dev/mmcblk2p2" \ -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2 +For i.MX 8M Mini EVK: + +.. code-block:: bash + + $ qemu-system-aarch64 -M imx8mm-evk -smp 4 -m 2G \ + -display none -serial null -serial stdio \ + -kernel Image \ + -dtb imx8mm-evk.dtb \ + -append "root=/dev/mmcblk2p2" \ + -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2 KVM Acceleration ---------------- @@ -XXX,XX +XXX,XX @@ To enable hardware-assisted acceleration via KVM, append ``-accel kvm`` to the command line. While this speeds up performance significantly, be aware of the following limitations: -* The ``imx8mp-evk`` machine is not included under the "virtualization use case" - of :doc:`QEMU's security policy </system/security>`. This means that you - should not trust that it can contain malicious guests, whether it is run - using TCG or KVM. If you don't trust your guests and you're relying on QEMU to - be the security boundary, you want to choose another machine such as ``virt``. +* The ``imx8mp-evk`` and ``imx8mm-evk`` machines are not included + under the "virtualization use case" of :doc:`QEMU's security + policy </system/security>`. This means that you should not trust that + it can contain malicious guests, whether it is run using TCG or KVM. + If you don't trust your guests and you're relying on QEMU to be the + security boundary, you want to choose another machine such as + ``virt``. * Rather than Cortex-A53 CPUs, the same CPU type as the host's will be used. This is a limitation of KVM and may not work with guests with a tight dependency on Cortex-A53. diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/target-arm.rst +++ b/docs/system/target-arm.rst @@ -XXX,XX +XXX,XX @@ Board-specific documentation arm/imx25-pdk arm/mcimx6ul-evk arm/mcimx7d-sabre - arm/imx8mp-evk + arm/imx8m arm/orangepi arm/raspi arm/collie diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK depends on TCG select FSL_IMX8MP +config FSL_IMX8MM + bool + select ARM_GIC + select IMX + +config FSL_IMX8MM_EVK + bool + default y + depends on AARCH64 + depends on TCG + select FSL_IMX8MM + config ARM_SMMUV3_ACCEL bool depends on ARM_SMMUV3 diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ +/* + * i.MX 8MM SoC Implementation + * + * Based on hw/arm/fsl-imx6.c + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * iMX8MM Reference Manual - https://www.nxp.com/products/i.MX8MMINI -> Documentation + */ + +#include "qemu/osdep.h" +#include "system/address-spaces.h" +#include "hw/arm/bsa.h" +#include "hw/arm/fsl-imx8mm.h" +#include "hw/misc/unimp.h" +#include "hw/core/boards.h" +#include "system/kvm.h" +#include "system/system.h" +#include "target/arm/cpu.h" +#include "target/arm/cpu-qom.h" +#include "target/arm/kvm_arm.h" +#include "qapi/error.h" +#include "qobject/qlist.h" + +static const struct { + hwaddr addr; + size_t size; + const char *name; +} fsl_imx8mm_memmap[] = { + [FSL_IMX8MM_RAM] = { FSL_IMX8MM_RAM_START, FSL_IMX8MM_RAM_SIZE_MAX, "ram" }, + [FSL_IMX8MM_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" }, + [FSL_IMX8MM_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" }, + [FSL_IMX8MM_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" }, + [FSL_IMX8MM_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" }, + [FSL_IMX8MM_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" }, + [FSL_IMX8MM_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" }, + [FSL_IMX8MM_VPU] = { 0x38340000, 2 * MiB, "vpu" }, + [FSL_IMX8MM_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" }, + [FSL_IMX8MM_VPU_G2_DECODER] = { 0x38310000, 1 * MiB, "vpu_g2_decoder" }, + [FSL_IMX8MM_VPU_G1_DECODER] = { 0x38300000, 1 * MiB, "vpu_g1_decoder" }, + [FSL_IMX8MM_USB2_OTG] = { 0x32e50200, 0x200, "usb2_otg" }, + [FSL_IMX8MM_USB2] = { 0x32e50000, 0x200, "usb2" }, + [FSL_IMX8MM_USB1_OTG] = { 0x32e40200, 0x200, "usb1_otg" }, + [FSL_IMX8MM_USB1] = { 0x32e40000, 0x200, "usb1" }, + [FSL_IMX8MM_GPU2D] = { 0x38000000, 64 * KiB, "gpu2d" }, + [FSL_IMX8MM_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" }, + [FSL_IMX8MM_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" }, + [FSL_IMX8MM_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" }, + [FSL_IMX8MM_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" }, + + /* AIPS-4 Begin */ + [FSL_IMX8MM_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" }, + [FSL_IMX8MM_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" }, + [FSL_IMX8MM_MEDIA_BLK_CTL] = { 0x32e28000, 256, "media_blk_ctl" }, + [FSL_IMX8MM_LCDIF] = { 0x32e00000, 64 * KiB, "lcdif" }, + [FSL_IMX8MM_MIPI_DSI] = { 0x32e10000, 64 * KiB, "mipi_dsi" }, + [FSL_IMX8MM_MIPI_CSI] = { 0x32e30000, 64 * KiB, "mipi_csi" }, + [FSL_IMX8MM_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" }, + /* AIPS-4 End */ + + [FSL_IMX8MM_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" }, + + /* AIPS-3 Begin */ + [FSL_IMX8MM_ENET1] = { 0x30be0000, 64 * KiB, "enet1" }, + [FSL_IMX8MM_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" }, + [FSL_IMX8MM_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" }, + [FSL_IMX8MM_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" }, + [FSL_IMX8MM_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" }, + [FSL_IMX8MM_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" }, + [FSL_IMX8MM_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" }, + [FSL_IMX8MM_MU_B] = { 0x30ab0000, 64 * KiB, "mu_b" }, + [FSL_IMX8MM_MU_A] = { 0x30aa0000, 64 * KiB, "mu_a" }, + [FSL_IMX8MM_UART4] = { 0x30a60000, 64 * KiB, "uart4" }, + [FSL_IMX8MM_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" }, + [FSL_IMX8MM_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" }, + [FSL_IMX8MM_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" }, + [FSL_IMX8MM_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" }, + [FSL_IMX8MM_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" }, + [FSL_IMX8MM_CAAM] = { 0x30900000, 256 * KiB, "caam" }, + [FSL_IMX8MM_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" }, + [FSL_IMX8MM_UART2] = { 0x30890000, 64 * KiB, "uart2" }, + [FSL_IMX8MM_UART3] = { 0x30880000, 64 * KiB, "uart3" }, + [FSL_IMX8MM_UART1] = { 0x30860000, 64 * KiB, "uart1" }, + [FSL_IMX8MM_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" }, + [FSL_IMX8MM_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" }, + [FSL_IMX8MM_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" }, + /* AIPS-3 End */ + + /* AIPS-2 Begin */ + [FSL_IMX8MM_QOSC] = { 0x307f0000, 64 * KiB, "qosc" }, + [FSL_IMX8MM_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" }, + [FSL_IMX8MM_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" }, + [FSL_IMX8MM_GPT4] = { 0x30700000, 64 * KiB, "gpt4" }, + [FSL_IMX8MM_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" }, + [FSL_IMX8MM_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" }, + [FSL_IMX8MM_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" }, + [FSL_IMX8MM_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" }, + [FSL_IMX8MM_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" }, + [FSL_IMX8MM_PWM4] = { 0x30690000, 64 * KiB, "pwm4" }, + [FSL_IMX8MM_PWM3] = { 0x30680000, 64 * KiB, "pwm3" }, + [FSL_IMX8MM_PWM2] = { 0x30670000, 64 * KiB, "pwm2" }, + [FSL_IMX8MM_PWM1] = { 0x30660000, 64 * KiB, "pwm1" }, + [FSL_IMX8MM_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" }, + /* AIPS-2 End */ + + /* AIPS-1 Begin */ + [FSL_IMX8MM_CSU] = { 0x303e0000, 64 * KiB, "csu" }, + [FSL_IMX8MM_RDC] = { 0x303d0000, 64 * KiB, "rdc" }, + [FSL_IMX8MM_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" }, + [FSL_IMX8MM_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" }, + [FSL_IMX8MM_GPC] = { 0x303a0000, 64 * KiB, "gpc" }, + [FSL_IMX8MM_SRC] = { 0x30390000, 64 * KiB, "src" }, + [FSL_IMX8MM_CCM] = { 0x30380000, 64 * KiB, "ccm" }, + [FSL_IMX8MM_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" }, + [FSL_IMX8MM_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" }, + [FSL_IMX8MM_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" }, + [FSL_IMX8MM_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" }, + [FSL_IMX8MM_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" }, + [FSL_IMX8MM_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" }, + [FSL_IMX8MM_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" }, + [FSL_IMX8MM_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" }, + [FSL_IMX8MM_SDMA2] = { 0x302c0000, 64 * KiB, "sdma2" }, + [FSL_IMX8MM_SDMA3] = { 0x302b0000, 64 * KiB, "sdma3" }, + [FSL_IMX8MM_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" }, + [FSL_IMX8MM_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" }, + [FSL_IMX8MM_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" }, + [FSL_IMX8MM_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" }, + [FSL_IMX8MM_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" }, + [FSL_IMX8MM_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" }, + [FSL_IMX8MM_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" }, + [FSL_IMX8MM_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" }, + [FSL_IMX8MM_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" }, + [FSL_IMX8MM_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" }, + [FSL_IMX8MM_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" }, + [FSL_IMX8MM_SAI6] = { 0x30060000, 64 * KiB, "sai6" }, + [FSL_IMX8MM_SAI5] = { 0x30050000, 64 * KiB, "sai5" }, + [FSL_IMX8MM_SAI3] = { 0x30030000, 64 * KiB, "sai3" }, + [FSL_IMX8MM_SAI2] = { 0x30020000, 64 * KiB, "sai2" }, + [FSL_IMX8MM_SAI1] = { 0x30010000, 64 * KiB, "sai1" }, + + /* AIPS-1 End */ + + [FSL_IMX8MM_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" }, + [FSL_IMX8MM_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" }, + [FSL_IMX8MM_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" }, + [FSL_IMX8MM_OCRAM] = { 0x00900000, 256 * KiB, "ocram" }, + [FSL_IMX8MM_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" }, + [FSL_IMX8MM_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" }, + [FSL_IMX8MM_OCRAM_S] = { 0x00180000, 32 * KiB, "ocram_s" }, + [FSL_IMX8MM_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" }, + [FSL_IMX8MM_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" }, + [FSL_IMX8MM_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" }, +}; + +static void fsl_imx8mm_init(Object *obj) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + FslImx8mmState *s = FSL_IMX8MM(obj); + const char *cpu_type = ms->cpu_type ?: ARM_CPU_TYPE_NAME("cortex-a53"); + int i; + + for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MM_NUM_CPUS); i++) { + g_autofree char *name = g_strdup_printf("cpu%d", i); + object_initialize_child(obj, name, &s->cpu[i], cpu_type); + } + + object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { + g_autofree char *name = g_strdup_printf("uart%d", i + 1); + object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); + } + +} + +static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + FslImx8mmState *s = FSL_IMX8MM(dev); + DeviceState *gicdev = DEVICE(&s->gic); + int i; + + if (ms->smp.cpus > FSL_IMX8MM_NUM_CPUS) { + error_setg(errp, "%s: Only %d CPUs are supported (%d requested)", + TYPE_FSL_IMX8MM, FSL_IMX8MM_NUM_CPUS, ms->smp.cpus); + return; + } + + /* CPUs */ + for (i = 0; i < ms->smp.cpus; i++) { + /* On uniprocessor, the CBAR is set to 0 */ + if (ms->smp.cpus > 1 && + object_property_find(OBJECT(&s->cpu[i]), "reset-cbar")) { + object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar", + fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr, + &error_abort); + } + + /* + * CNTFID0 base frequency in Hz of system counter + */ + object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000, + &error_abort); + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el2")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el2", + !kvm_enabled(), &error_abort); + } + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", + !kvm_enabled(), &error_abort); + } + + if (i) { + /* + * Secondary CPUs start in powered-down state (and can be + * powered up via the SRC system reset controller) + */ + object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off", + true, &error_abort); + } + + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { + return; + } + } + + /* GIC */ + { + SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic); + QList *redist_region_count; + bool pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL); + + qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus); + qdev_prop_set_uint32(gicdev, "num-irq", + FSL_IMX8MM_NUM_IRQS + GIC_INTERNAL); + redist_region_count = qlist_new(); + qlist_append_int(redist_region_count, ms->smp.cpus); + qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count); + object_property_set_link(OBJECT(&s->gic), "sysmem", + OBJECT(get_system_memory()), &error_fatal); + if (!sysbus_realize(gicsbd, errp)) { + return; + } + sysbus_mmio_map(gicsbd, 0, fsl_imx8mm_memmap[FSL_IMX8MM_GIC_DIST].addr); + sysbus_mmio_map(gicsbd, 1, fsl_imx8mm_memmap[FSL_IMX8MM_GIC_REDIST].addr); + + /* + * Wire the outputs from each CPU's generic timer and the GICv3 + * maintenance interrupt signal to the appropriate GIC PPI inputs, and + * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs. + */ + for (i = 0; i < ms->smp.cpus; i++) { + DeviceState *cpudev = DEVICE(&s->cpu[i]); + int intidbase = FSL_IMX8MM_NUM_IRQS + i * GIC_INTERNAL; + qemu_irq irq; + + /* + * Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs. + */ + static const int timer_irqs[] = { + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, + }; + + for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) { + irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]); + qdev_connect_gpio_out(cpudev, j, irq); + } + + irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ); + qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", + 0, irq); + + irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ); + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq); + + sysbus_connect_irq(gicsbd, i, + qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); + sysbus_connect_irq(gicsbd, i + ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); + sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); + sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + + if (kvm_enabled()) { + if (pmu) { + assert(arm_feature(&s->cpu[i].env, ARM_FEATURE_PMU)); + if (kvm_irqchip_in_kernel()) { + kvm_arm_pmu_set_irq(&s->cpu[i], VIRTUAL_PMU_IRQ); + } + kvm_arm_pmu_init(&s->cpu[i]); + } + } + } + } + + /* UARTs */ + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } serial_table[FSL_IMX8MM_NUM_UARTS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_UART1].addr, FSL_IMX8MM_UART1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART2].addr, FSL_IMX8MM_UART2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART3].addr, FSL_IMX8MM_UART3_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_UART4].addr, FSL_IMX8MM_UART4_IRQ }, + }; + + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i)); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + qdev_get_gpio_in(gicdev, serial_table[i].irq)); + } + + /* On-Chip RAM */ + if (!memory_region_init_ram(&s->ocram, OBJECT(dev), "imx8mm.ocram", + fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].size, + errp)) { + return; + } + memory_region_add_subregion(get_system_memory(), + fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, + &s->ocram); + + /* Unimplemented devices */ + for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { + switch (i) { + case FSL_IMX8MM_GIC_DIST: + case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_RAM: + case FSL_IMX8MM_OCRAM: + case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + /* device implemented and treated above */ + break; + + default: + create_unimplemented_device(fsl_imx8mm_memmap[i].name, + fsl_imx8mm_memmap[i].addr, + fsl_imx8mm_memmap[i].size); + break; + } + } +} + +static void fsl_imx8mm_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = fsl_imx8mm_realize; + + dc->desc = "i.MX 8MM SoC"; +} + +static const TypeInfo fsl_imx8mm_types[] = { + { + .name = TYPE_FSL_IMX8MM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FslImx8mmState), + .instance_init = fsl_imx8mm_init, + .class_init = fsl_imx8mm_class_init, + }, +}; + +DEFINE_TYPES(fsl_imx8mm_types) diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ +/* + * NXP i.MX 8MM Evaluation Kit System Emulation + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "system/address-spaces.h" +#include "hw/arm/boot.h" +#include "hw/arm/fsl-imx8mm.h" +#include "hw/arm/machines-qom.h" +#include "hw/core/boards.h" +#include "hw/core/qdev-properties.h" +#include "system/kvm.h" +#include "system/qtest.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include <libfdt.h> + +static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt) +{ + int i, offset; + + /* Temporarily disable following nodes until they are implemented */ + const char *nodes_to_remove[] = { + "nxp,imx8mm-fspi", + "fsl,imx8mm-mipi-csi", + "fsl,imx8mm-mipi-dsim" + }; + + for (i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) { + const char *dev_str = nodes_to_remove[i]; + + offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); + while (offset >= 0) { + fdt_nop_node(fdt, offset); + offset = fdt_node_offset_by_compatible(fdt, offset, dev_str); + } + } + + /* Remove cpu-idle-states property from CPU nodes */ + offset = fdt_node_offset_by_compatible(fdt, -1, "arm,cortex-a53"); + while (offset >= 0) { + fdt_nop_property(fdt, offset, "cpu-idle-states"); + offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53"); + } + + if (kvm_enabled()) { + /* Use system counter frequency from host CPU to fix time in guest */ + offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); + while (offset >= 0) { + fdt_nop_property(fdt, offset, "clock-frequency"); + offset = fdt_node_offset_by_compatible(fdt, offset, "arm,armv8-timer"); + } + } +} + +static void imx8mm_evk_init(MachineState *machine) +{ + static struct arm_boot_info boot_info; + FslImx8mmState *s; + + if (machine->ram_size > FSL_IMX8MM_RAM_SIZE_MAX) { + error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")", + machine->ram_size, FSL_IMX8MM_RAM_SIZE_MAX); + exit(1); + } + + boot_info = (struct arm_boot_info) { + .loader_start = FSL_IMX8MM_RAM_START, + .board_id = -1, + .ram_size = machine->ram_size, + .psci_conduit = QEMU_PSCI_CONDUIT_SMC, + .modify_dtb = imx8mm_evk_modify_dtb, + }; + + s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine), + "soc", &error_fatal, NULL)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal); + + memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, + machine->ram); + + if (!qtest_enabled()) { + arm_load_kernel(&s->cpu[0], machine, &boot_info); + } +} + +static const char *imx8mm_evk_get_default_cpu_type(const MachineState *ms) +{ + if (kvm_enabled()) { + return ARM_CPU_TYPE_NAME("host"); + } + + return ARM_CPU_TYPE_NAME("cortex-a53"); +} + +static void imx8mm_evk_machine_init(MachineClass *mc) +{ + mc->desc = "NXP i.MX 8MM EVK Board"; + mc->init = imx8mm_evk_init; + mc->max_cpus = FSL_IMX8MM_NUM_CPUS; + mc->default_cpus = FSL_IMX8MM_NUM_CPUS; + mc->default_ram_size = 2 * GiB; + mc->default_ram_id = "imx8mm-evk.ram"; + mc->get_default_cpu_type = imx8mm_evk_get_default_cpu_type; +} + +DEFINE_MACHINE_AARCH64("imx8mm-evk", imx8mm_evk_machine_init) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -XXX,XX +XXX,XX @@ arm_common_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c')) arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM', if_true: files('fsl-imx8mm.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MM_EVK', if_true: files('imx8mm-evk.c')) arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3_ACCEL', if_true: files('smmuv3-accel.c')) stub_ss.add(files('smmuv3-accel-stubs.c')) diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ +/* + * i.MX 8MM SoC Definitions + * + * Copyright (c) 2025, NXP Semiconductors + * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef FSL_IMX8MM_H +#define FSL_IMX8MM_H + +#include "cpu.h" +#include "hw/char/imx_serial.h" +#include "hw/intc/arm_gicv3_common.h" +#include "qom/object.h" +#include "qemu/units.h" + +#define TYPE_FSL_IMX8MM "fsl-imx8mm" +OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) + +#define FSL_IMX8MM_RAM_START 0x40000000 +#define FSL_IMX8MM_RAM_SIZE_MAX (4 * GiB) + +enum FslImx8mmConfiguration { + FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_IRQS = 128, + FSL_IMX8MM_NUM_UARTS = 4, +}; + +struct FslImx8mmState { + SysBusDevice parent_obj; + + ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; + GICv3State gic; + IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; + MemoryRegion ocram; +}; + +enum FslImx8mmMemoryRegions { + FSL_IMX8MM_A53_DAP, + FSL_IMX8MM_AIPS1_CONFIGURATION, + FSL_IMX8MM_AIPS2_CONFIGURATION, + FSL_IMX8MM_AIPS3_CONFIGURATION, + FSL_IMX8MM_AIPS4_CONFIGURATION, + FSL_IMX8MM_ANA_OSC, + FSL_IMX8MM_ANA_PLL, + FSL_IMX8MM_ANA_TSENSOR, + FSL_IMX8MM_APBH_DMA, + FSL_IMX8MM_BOOT_ROM, + FSL_IMX8MM_BOOT_ROM_PROTECTED, + FSL_IMX8MM_CAAM, + FSL_IMX8MM_CAAM_MEM, + FSL_IMX8MM_CCM, + FSL_IMX8MM_CSU, + FSL_IMX8MM_DDR_CTL, + FSL_IMX8MM_DDR_PERF_MON, + FSL_IMX8MM_DDR_PHY, + FSL_IMX8MM_DDR_PHY_BROADCAST, + FSL_IMX8MM_ECSPI1, + FSL_IMX8MM_ECSPI2, + FSL_IMX8MM_ECSPI3, + FSL_IMX8MM_ENET1, + FSL_IMX8MM_GIC_DIST, + FSL_IMX8MM_GIC_REDIST, + FSL_IMX8MM_GPC, + FSL_IMX8MM_GPIO1, + FSL_IMX8MM_GPIO2, + FSL_IMX8MM_GPIO3, + FSL_IMX8MM_GPIO4, + FSL_IMX8MM_GPIO5, + FSL_IMX8MM_GPT1, + FSL_IMX8MM_GPT2, + FSL_IMX8MM_GPT3, + FSL_IMX8MM_GPT4, + FSL_IMX8MM_GPT5, + FSL_IMX8MM_GPT6, + FSL_IMX8MM_GPU2D, + FSL_IMX8MM_I2C1, + FSL_IMX8MM_I2C2, + FSL_IMX8MM_I2C3, + FSL_IMX8MM_I2C4, + FSL_IMX8MM_INTERCONNECT, + FSL_IMX8MM_IOMUXC, + FSL_IMX8MM_IOMUXC_GPR, + FSL_IMX8MM_MEDIA_BLK_CTL, + FSL_IMX8MM_LCDIF, + FSL_IMX8MM_MIPI_CSI, + FSL_IMX8MM_MIPI_DSI, + FSL_IMX8MM_MU_A, + FSL_IMX8MM_MU_B, + FSL_IMX8MM_OCOTP_CTRL, + FSL_IMX8MM_OCRAM, + FSL_IMX8MM_OCRAM_S, + FSL_IMX8MM_PCIE1, + FSL_IMX8MM_PCIE1_MEM, + FSL_IMX8MM_PCIE_PHY1, + FSL_IMX8MM_PERFMON1, + FSL_IMX8MM_PERFMON2, + FSL_IMX8MM_PWM1, + FSL_IMX8MM_PWM2, + FSL_IMX8MM_PWM3, + FSL_IMX8MM_PWM4, + FSL_IMX8MM_QOSC, + FSL_IMX8MM_QSPI, + FSL_IMX8MM_QSPI1_RX_BUFFER, + FSL_IMX8MM_QSPI1_TX_BUFFER, + FSL_IMX8MM_QSPI_MEM, + FSL_IMX8MM_RAM, + FSL_IMX8MM_RDC, + FSL_IMX8MM_SAI1, + FSL_IMX8MM_SAI2, + FSL_IMX8MM_SAI3, + FSL_IMX8MM_SAI5, + FSL_IMX8MM_SAI6, + FSL_IMX8MM_SDMA1, + FSL_IMX8MM_SDMA2, + FSL_IMX8MM_SDMA3, + FSL_IMX8MM_SEMAPHORE1, + FSL_IMX8MM_SEMAPHORE2, + FSL_IMX8MM_SEMAPHORE_HS, + FSL_IMX8MM_SNVS_HP, + FSL_IMX8MM_SPBA1, + FSL_IMX8MM_SRC, + FSL_IMX8MM_SYSCNT_CMP, + FSL_IMX8MM_SYSCNT_CTRL, + FSL_IMX8MM_SYSCNT_RD, + FSL_IMX8MM_TCM_DTCM, + FSL_IMX8MM_TCM_ITCM, + FSL_IMX8MM_TZASC, + FSL_IMX8MM_UART1, + FSL_IMX8MM_UART2, + FSL_IMX8MM_UART3, + FSL_IMX8MM_UART4, + FSL_IMX8MM_USB1, + FSL_IMX8MM_USB2, + FSL_IMX8MM_USB1_OTG, + FSL_IMX8MM_USB2_OTG, + FSL_IMX8MM_USDHC1, + FSL_IMX8MM_USDHC2, + FSL_IMX8MM_USDHC3, + FSL_IMX8MM_VPU, + FSL_IMX8MM_VPU_BLK_CTRL, + FSL_IMX8MM_VPU_G1_DECODER, + FSL_IMX8MM_VPU_G2_DECODER, + FSL_IMX8MM_WDOG1, + FSL_IMX8MM_WDOG2, + FSL_IMX8MM_WDOG3, +}; + +enum FslImx8mmIrqs { + FSL_IMX8MM_UART1_IRQ = 26, + FSL_IMX8MM_UART2_IRQ = 27, + FSL_IMX8MM_UART3_IRQ = 28, + FSL_IMX8MM_UART4_IRQ = 29, +}; + +#endif /* FSL_IMX8MM_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add configurable properties for register reset values that differ between i.MX 8M variants (Plus, Mini, etc.). This allows the same device implementation to be shared across multiple SoCs. Properties added: - arm-pll-fdiv-ctl0-reset: ARM PLL divider control reset value Default value is set to match i.MX 8MP reset value (0x000FA031). This can be overridden in the variant like iMX8MM with its own reset value. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/misc/imx8mp_analog.c | 12 +++++++++++- include/hw/misc/imx8mp_analog.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/imx8mp_analog.c +++ b/hw/misc/imx8mp_analog.c @@ -XXX,XX +XXX,XX @@ #include "qemu/log.h" #include "hw/misc/imx8mp_analog.h" +#include "hw/core/qdev-properties.h" #include "migration/vmstate.h" #define ANALOG_PLL_LOCK BIT(31) @@ -XXX,XX +XXX,XX @@ static void imx8mp_analog_reset(DeviceState *dev) s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f; s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081; s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810; - s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031; + + /* Use property value instead of hardcoded */ + s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = s->arm_pll_fdiv_ctl0_reset; + s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f; s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081; s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810; @@ -XXX,XX +XXX,XX @@ static const VMStateDescription imx8mp_analog_vmstate = { }, }; +static const Property imx8mp_analog_properties[] = { + DEFINE_PROP_UINT32("arm-pll-fdiv-ctl0-reset", IMX8MPAnalogState, + arm_pll_fdiv_ctl0_reset, 0x000fa031), /* imx8mp default */ +}; + static void imx8mp_analog_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_legacy_reset(dc, imx8mp_analog_reset); + device_class_set_props(dc, imx8mp_analog_properties); dc->vmsd = &imx8mp_analog_vmstate; dc->desc = "i.MX 8M Plus Analog Module"; } diff --git a/include/hw/misc/imx8mp_analog.h b/include/hw/misc/imx8mp_analog.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/misc/imx8mp_analog.h +++ b/include/hw/misc/imx8mp_analog.h @@ -XXX,XX +XXX,XX @@ struct IMX8MPAnalogState { } mmio; uint32_t analog[ANALOG_MAX]; + + /* Property for variant-specific reset values */ + uint32_t arm_pll_fdiv_ctl0_reset; }; #endif /* IMX8MP_ANALOG_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add the Analog IP to i.MX8MM SoC. iMX8MM and i.MX8MP uses the same Analog IP so the analog ip source will be shared. The ARM PLL divider control register (arm-pll-fdiv-ctl0) has a different reset value on i.MX8MM (0x000fa030) compared to i.MX8MP (0x000fa031). So iMX8MM will be overriding this property with its own reset-value. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 12 ++++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool select ARM_GIC + select FSL_IMX8MP_ANALOG select IMX config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { g_autofree char *name = g_strdup_printf("uart%d", i + 1); object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } + /* Analog */ + object_property_set_uint(OBJECT(&s->analog), "arm-pll-fdiv-ctl0-reset", + 0x000fa030, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_ANA_PLL].addr); + /* UARTs */ for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { + case FSL_IMX8MM_ANA_PLL: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" +#include "hw/misc/imx8mp_analog.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMX8MPAnalogState analog; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; }; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Add the Clock Control Module (CCM) device to i.MX8MM SoC. The CCM implementation is shared with i.MX8MP as the register layout is identical between the two variants.Hence iMX8MM will be using the source of iMX8MP CCM. Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 10 ++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM bool select ARM_GIC select FSL_IMX8MP_ANALOG + select FSL_IMX8MP_CCM select IMX config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM); + object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } + /* CCM */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_CCM].addr); + /* Analog */ object_property_set_uint(OBJECT(&s->analog), "arm-pll-fdiv-ctl0-reset", 0x000fa030, &error_abort); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { case FSL_IMX8MM_ANA_PLL: + case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx8mp_analog.h" +#include "hw/misc/imx8mp_ccm.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> SNVS contains an RTC which allows Linux to deal correctly with time Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 10 ++++++++++ include/hw/arm/fsl-imx8mm.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG); + object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); + for (i = 0; i < FSL_IMX8MM_NUM_UARTS; i++) { g_autofree char *name = g_strdup_printf("uart%d", i + 1); object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* SNVS */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_RAM: case FSL_IMX8MM_OCRAM: + case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: /* device implemented and treated above */ break; diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/intc/arm_gicv3_common.h" +#include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" #include "qom/object.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { GICv3State gic; IMX8MPCCMState ccm; IMX8MPAnalogState analog; + IMX7SNVSState snvs; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; }; -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of SD/MMC cards through a virtual SDHCI interface The emulated SDHCI controller allows guest OS to use emulated storage as a standard block device. This will allow running the images such as those generated by Buildroot. Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 25 +++++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 17 +++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 4 files changed, 50 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select SDHCI config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); + object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); + } } static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* USDHCs */ + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } usdhc_table[FSL_IMX8MM_NUM_USDHCS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC1].addr, FSL_IMX8MM_USDHC1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC2].addr, FSL_IMX8MM_USDHC2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USDHC3].addr, FSL_IMX8MM_USDHC3_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0, + qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); + } + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: /* device implemented and treated above */ break; diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/imx8mm-evk.c +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ static void imx8mm_evk_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, machine->ram); + for (int i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { + BusState *bus; + DeviceState *carddev; + BlockBackend *blk; + DriveInfo *di = drive_get(IF_SD, i, 0); + + if (!di) { + continue; + } + + blk = blk_by_legacy_dinfo(di); + bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus"); + carddev = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); + qdev_realize_and_unref(carddev, bus, &error_fatal); + } + if (!qtest_enabled()) { arm_load_kernel(&s->cpu[0], machine, &boot_info); } diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/sd/sdhci.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, + FSL_IMX8MM_NUM_USDHCS = 3, }; struct FslImx8mmState { @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX7SNVSState snvs; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; + SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmMemoryRegions { }; enum FslImx8mmIrqs { + FSL_IMX8MM_USDHC1_IRQ = 22, + FSL_IMX8MM_USDHC2_IRQ = 23, + FSL_IMX8MM_USDHC3_IRQ = 24, + FSL_IMX8MM_UART1_IRQ = 26, FSL_IMX8MM_UART2_IRQ = 27, FSL_IMX8MM_UART3_IRQ = 28, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> This enables support for Designware PCI Express Controller emulation It provides a controlled environment to debug the linux pci subsystem Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 3 +++ hw/arm/fsl-imx8mm.c | 30 ++++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 10 ++++++++++ 3 files changed, 43 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool + imply PCI_DEVICES select ARM_GIC select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX select SDHCI + select PCI_EXPRESS_DESIGNWARE + select PCI_EXPRESS_FSL_IMX8M_PHY config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); + object_initialize_child(obj, "pcie_phy", &s->pcie_phy, + TYPE_FSL_IMX8M_PCIE_PHY); } static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* PCIe */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_PCIE1].addr); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTA_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTB_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTC_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_INTD_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_PCI_MSI_IRQ)); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_PCIE_PHY1].addr); + /* Unimplemented devices */ for (i = 0; i < ARRAY_SIZE(fsl_imx8mm_memmap); i++) { switch (i) { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_PCIE1: + case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/pci-host/designware.h" +#include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; + DesignwarePCIEHost pcie; + FslImx8mPciePhyState pcie_phy; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART2_IRQ = 27, FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + + FSL_IMX8MM_PCI_INTA_IRQ = 122, + FSL_IMX8MM_PCI_INTB_IRQ = 123, + FSL_IMX8MM_PCI_INTC_IRQ = 124, + FSL_IMX8MM_PCI_INTD_IRQ = 125, + FSL_IMX8MM_PCI_MSI_IRQ = 127, }; #endif /* FSL_IMX8MM_H */ -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Enabled GPIO controller emulation Also updated the GPIO IRQ lines of iMX8MM Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 54 +++++++++++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 14 ++++++++++ 2 files changed, 68 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { + g_autofree char *name = g_strdup_printf("gpio%d", i + 1); + object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); + } + for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { g_autofree char *name = g_strdup_printf("usdhc%d", i + 1); object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* GPIOs */ + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { + static const struct { + hwaddr addr; + unsigned int irq_low; + unsigned int irq_high; + } gpio_table[FSL_IMX8MM_NUM_GPIOS] = { + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO1].addr, + FSL_IMX8MM_GPIO1_LOW_IRQ, + FSL_IMX8MM_GPIO1_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO2].addr, + FSL_IMX8MM_GPIO2_LOW_IRQ, + FSL_IMX8MM_GPIO2_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO3].addr, + FSL_IMX8MM_GPIO3_LOW_IRQ, + FSL_IMX8MM_GPIO3_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO4].addr, + FSL_IMX8MM_GPIO4_LOW_IRQ, + FSL_IMX8MM_GPIO4_HIGH_IRQ + }, + { + fsl_imx8mm_memmap[FSL_IMX8MM_GPIO5].addr, + FSL_IMX8MM_GPIO5_LOW_IRQ, + FSL_IMX8MM_GPIO5_HIGH_IRQ + }, + }; + object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true, + &error_abort); + object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq", + true, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, + qdev_get_gpio_in(gicdev, gpio_table[i].irq_low)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1, + qdev_get_gpio_in(gicdev, gpio_table[i].irq_high)); + } + /* USDHCs */ for (i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_CCM: case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: + case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" +#include "hw/gpio/imx_gpio.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_GPIOS = 5, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMXGPIOState gpio[FSL_IMX8MM_NUM_GPIOS]; IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, + FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, + FSL_IMX8MM_GPIO2_LOW_IRQ = 66, + FSL_IMX8MM_GPIO2_HIGH_IRQ = 67, + FSL_IMX8MM_GPIO3_LOW_IRQ = 68, + FSL_IMX8MM_GPIO3_HIGH_IRQ = 69, + FSL_IMX8MM_GPIO4_LOW_IRQ = 70, + FSL_IMX8MM_GPIO4_HIGH_IRQ = 71, + FSL_IMX8MM_GPIO5_LOW_IRQ = 72, + FSL_IMX8MM_GPIO5_HIGH_IRQ = 73, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> This can be used to test and debug I2C device drivers. Added I2C interrupts Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 2 ++ hw/arm/fsl-imx8mm.c | 27 +++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 8 ++++++++ 3 files changed, 37 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP_EVK config FSL_IMX8MM bool imply PCI_DEVICES + imply I2C_DEVICES select ARM_GIC select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select IMX_I2C select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { + g_autofree char *name = g_strdup_printf("i2c%d", i + 1); + object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); + } + for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { g_autofree char *name = g_strdup_printf("gpio%d", i + 1); object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* I2Cs */ + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } i2c_table[FSL_IMX8MM_NUM_I2CS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C1].addr, FSL_IMX8MM_I2C1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C2].addr, FSL_IMX8MM_I2C2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C3].addr, FSL_IMX8MM_I2C3_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_I2C4].addr, FSL_IMX8MM_I2C4_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, + qdev_get_gpio_in(gicdev, i2c_table[i].irq)); + } + /* GPIOs */ for (i = 0; i < FSL_IMX8MM_NUM_GPIOS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: case FSL_IMX8MM_RAM: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "hw/char/imx_serial.h" #include "hw/gpio/imx_gpio.h" +#include "hw/i2c/imx_i2c.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_GPIOS = 5, + FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; + IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_I2C1_IRQ = 35, + FSL_IMX8MM_I2C2_IRQ = 36, + FSL_IMX8MM_I2C3_IRQ = 37, + FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, FSL_IMX8MM_GPIO2_LOW_IRQ = 66, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of ECSPI in iMX8MM Added SPI IRQ lines Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/fsl-imx8mm.c | 26 ++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 2 files changed, 33 insertions(+) diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { + g_autofree char *name = g_strdup_printf("spi%d", i + 1); + object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); + } + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); } + /* ECSPIs */ + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } spi_table[FSL_IMX8MM_NUM_ECSPIS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI1].addr, FSL_IMX8MM_ECSPI1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI2].addr, FSL_IMX8MM_ECSPI2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_ECSPI3].addr, FSL_IMX8MM_ECSPI3_IRQ }, + }; + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, + qdev_get_gpio_in(gicdev, spi_table[i].irq)); + } + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" +#include "hw/ssi/imx_spi.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mmState, FSL_IMX8MM) enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, + FSL_IMX8MM_NUM_ECSPIS = 3, FSL_IMX8MM_NUM_GPIOS = 5, FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX8MPCCMState ccm; IMX8MPAnalogState analog; IMX7SNVSState snvs; + IMXSPIState spi[FSL_IMX8MM_NUM_ECSPIS]; IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_UART3_IRQ = 28, FSL_IMX8MM_UART4_IRQ = 29, + FSL_IMX8MM_ECSPI1_IRQ = 31, + FSL_IMX8MM_ECSPI2_IRQ = 32, + FSL_IMX8MM_ECSPI3_IRQ = 33, + FSL_IMX8MM_I2C1_IRQ = 35, FSL_IMX8MM_I2C2_IRQ = 36, FSL_IMX8MM_I2C3_IRQ = 37, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of WDT in iMX8MM Added WDT IRQ lines Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 28 ++++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 7 +++++++ 3 files changed, 36 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY + select WDT_IMX2 config FSL_IMX8MM_EVK bool diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } + for (i = 0; i < FSL_IMX8MM_NUM_WDTS; i++) { + g_autofree char *name = g_strdup_printf("wdt%d", i); + object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); + } + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, fsl_imx8mm_memmap[FSL_IMX8MM_SNVS_HP].addr); + /* Watchdogs */ + for (i = 0; i < FSL_IMX8MM_NUM_WDTS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } wdog_table[FSL_IMX8MM_NUM_WDTS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG1].addr, FSL_IMX8MM_WDOG1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG2].addr, FSL_IMX8MM_WDOG2_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_WDOG3].addr, FSL_IMX8MM_WDOG3_IRQ }, + }; + + object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support", + true, &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0, + qdev_get_gpio_in(gicdev, wdog_table[i].irq)); + } + /* PCIe */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: + case FSL_IMX8MM_WDOG1 ... FSL_IMX8MM_WDOG3: /* device implemented and treated above */ break; diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" +#include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, FSL_IMX8MM_NUM_USDHCS = 3, + FSL_IMX8MM_NUM_WDTS = 3, }; struct FslImx8mmState { @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; + IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; }; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_GPIO5_LOW_IRQ = 72, FSL_IMX8MM_GPIO5_HIGH_IRQ = 73, + FSL_IMX8MM_WDOG1_IRQ = 78, + FSL_IMX8MM_WDOG2_IRQ = 79, + FSL_IMX8MM_WDOG3_IRQ = 10, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of GPT in iMX8MM Added GPT IRQ lines Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 54 +++++++++++++++++++++++++++++++++++++ hw/timer/imx_gpt.c | 26 ++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 11 ++++++++ include/hw/timer/imx_gpt.h | 2 ++ 5 files changed, 94 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_CCM select IMX select IMX_I2C + select OR_IRQ select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL); } + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) { + g_autofree char *name = g_strdup_printf("gpt%d", i + 1); + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MM_GPT); + } + object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq, + TYPE_OR_IRQ); + for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { g_autofree char *name = g_strdup_printf("i2c%d", i + 1); object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr, &s->ocram); + /* GPTs */ + object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2, + &error_abort); + if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) { + return; + } + + qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_GPT5_GPT6_IRQ)); + + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) { + hwaddr gpt_addrs[FSL_IMX8MM_NUM_GPTS] = { + fsl_imx8mm_memmap[FSL_IMX8MM_GPT1].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT2].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT3].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT4].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT5].addr, + fsl_imx8mm_memmap[FSL_IMX8MM_GPT6].addr, + }; + + s->gpt[i].ccm = IMX_CCM(&s->ccm); + + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) { + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]); + + if (i < FSL_IMX8MM_NUM_GPTS - 2) { + static const unsigned int gpt_irqs[FSL_IMX8MM_NUM_GPTS - 2] = { + FSL_IMX8MM_GPT1_IRQ, + FSL_IMX8MM_GPT2_IRQ, + FSL_IMX8MM_GPT3_IRQ, + FSL_IMX8MM_GPT4_IRQ, + }; + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(gicdev, gpt_irqs[i])); + } else { + int irq = i - FSL_IMX8MM_NUM_GPTS + 2; + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0, + qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq)); + } + } + /* I2Cs */ for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GIC_DIST: case FSL_IMX8MM_GIC_REDIST: case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: + case FSL_IMX8MM_GPT1 ... FSL_IMX8MM_GPT6: case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -XXX,XX +XXX,XX @@ * Originally written by Hans Jiang * Updated by Peter Chubb * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com> * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. @@ -XXX,XX +XXX,XX @@ static const IMXClk imx8mp_gpt_clocks[] = { CLK_NONE, /* 111 not defined */ }; +static const IMXClk imx8mm_gpt_clocks[] = { + CLK_NONE, /* 000 No clock source */ + CLK_IPG, /* 001 ipg_clk, 532MHz */ + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ + CLK_EXT, /* 011 External clock */ + CLK_32k, /* 100 ipg_clk_32k */ + CLK_HIGH, /* 101 ipg_clk_16M */ + CLK_NONE, /* 110 not defined */ + CLK_NONE, /* 111 not defined */ +}; + /* Must be called from within ptimer_transaction_begin/commit block */ static void imx_gpt_set_freq(IMXGPTState *s) { @@ -XXX,XX +XXX,XX @@ static void imx8mp_gpt_init(Object *obj) s->clocks = imx8mp_gpt_clocks; } +static void imx8mm_gpt_init(Object *obj) +{ + IMXGPTState *s = IMX_GPT(obj); + + s->clocks = imx8mm_gpt_clocks; +} + static const TypeInfo imx25_gpt_info = { .name = TYPE_IMX25_GPT, .parent = TYPE_SYS_BUS_DEVICE, @@ -XXX,XX +XXX,XX @@ static const TypeInfo imx8mp_gpt_info = { .instance_init = imx8mp_gpt_init, }; +static const TypeInfo imx8mm_gpt_info = { + .name = TYPE_IMX8MM_GPT, + .parent = TYPE_IMX25_GPT, + .instance_init = imx8mm_gpt_init, +}; + static void imx_gpt_register_types(void) { type_register_static(&imx25_gpt_info); @@ -XXX,XX +XXX,XX @@ static void imx_gpt_register_types(void) type_register_static(&imx6ul_gpt_info); type_register_static(&imx7_gpt_info); type_register_static(&imx8mp_gpt_info); + type_register_static(&imx8mm_gpt_info); } type_init(imx_gpt_register_types) diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" +#include "hw/or-irq.h" #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" +#include "hw/timer/imx_gpt.h" #include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_CPUS = 4, FSL_IMX8MM_NUM_ECSPIS = 3, FSL_IMX8MM_NUM_GPIOS = 5, + FSL_IMX8MM_NUM_GPTS = 6, FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { ARMCPU cpu[FSL_IMX8MM_NUM_CPUS]; GICv3State gic; + IMXGPTState gpt[FSL_IMX8MM_NUM_GPTS]; IMXGPIOState gpio[FSL_IMX8MM_NUM_GPIOS]; IMX8MPCCMState ccm; IMX8MPAnalogState analog; @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; + OrIRQState gpt5_gpt6_irq; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_I2C3_IRQ = 37, FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_GPT1_IRQ = 55, + FSL_IMX8MM_GPT2_IRQ = 54, + FSL_IMX8MM_GPT3_IRQ = 53, + FSL_IMX8MM_GPT4_IRQ = 52, + FSL_IMX8MM_GPT5_GPT6_IRQ = 51, + FSL_IMX8MM_GPIO1_LOW_IRQ = 64, FSL_IMX8MM_GPIO1_HIGH_IRQ = 65, FSL_IMX8MM_GPIO2_LOW_IRQ = 66, diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/timer/imx_gpt.h +++ b/include/hw/timer/imx_gpt.h @@ -XXX,XX +XXX,XX @@ * Originally written by Hans Jiang * Updated by Peter Chubb * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -XXX,XX +XXX,XX @@ #define TYPE_IMX6UL_GPT "imx6ul.gpt" #define TYPE_IMX7_GPT "imx7.gpt" #define TYPE_IMX8MP_GPT "imx8mp.gpt" +#define TYPE_IMX8MM_GPT "imx8mm.gpt" #define TYPE_IMX_GPT TYPE_IMX25_GPT -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of ENET ethernet controller in iMX8MM Enables testing and debugging of network dependent drivers Added ENET MAC IRQ lines Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 24 ++++++++++++++++++++++++ hw/arm/imx8mm-evk.c | 1 + include/hw/arm/fsl-imx8mm.h | 10 +++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select FSL_IMX8MP_ANALOG select FSL_IMX8MP_CCM select IMX + select IMX_FEC select IMX_I2C select OR_IRQ select SDHCI diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT); } + object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET); + object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); object_initialize_child(obj, "pcie_phy", &s->pcie_phy, TYPE_FSL_IMX8M_PCIE_PHY); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, spi_table[i].irq)); } + /* ENET1 */ + object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num, + &error_abort); + object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort); + qemu_configure_nic_device(DEVICE(&s->enet), true, NULL); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0, + fsl_imx8mm_memmap[FSL_IMX8MM_ENET1].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0, + qdev_get_gpio_in(gicdev, FSL_IMX8MM_ENET1_MAC_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1, + qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ)); + /* SNVS */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) { return; @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5: case FSL_IMX8MM_GPT1 ... FSL_IMX8MM_GPT6: case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3: + case FSL_IMX8MM_ENET1: case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4: case FSL_IMX8MM_PCIE1: case FSL_IMX8MM_PCIE_PHY1: @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) } } +static const Property fsl_imx8mm_properties[] = { + DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mmState, phy_num, 0), + DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mmState, phy_connected, true), +}; + static void fsl_imx8mm_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + device_class_set_props(dc, fsl_imx8mm_properties); dc->realize = fsl_imx8mm_realize; dc->desc = "i.MX 8MM SoC"; diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/imx8mm-evk.c +++ b/hw/arm/imx8mm-evk.c @@ -XXX,XX +XXX,XX @@ static void imx8mm_evk_init(MachineState *machine) s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine), "soc", &error_fatal, NULL)); + object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal); memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START, diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx8mp_analog.h" #include "hw/misc/imx8mp_ccm.h" -#include "hw/or-irq.h" +#include "hw/net/imx_fec.h" +#include "hw/core/or-irq.h" #include "hw/pci-host/designware.h" #include "hw/pci-host/fsl_imx8m_phy.h" #include "hw/sd/sdhci.h" @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXI2CState i2c[FSL_IMX8MM_NUM_I2CS]; IMXSerialState uart[FSL_IMX8MM_NUM_UARTS]; MemoryRegion ocram; + IMXFECState enet; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; OrIRQState gpt5_gpt6_irq; + + uint32_t phy_num; + bool phy_connected; }; enum FslImx8mmMemoryRegions { @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_WDOG2_IRQ = 79, FSL_IMX8MM_WDOG3_IRQ = 10, + FSL_IMX8MM_ENET1_MAC_IRQ = 118, + FSL_IMX6_ENET1_MAC_1588_IRQ = 121, + FSL_IMX8MM_PCI_INTA_IRQ = 122, FSL_IMX8MM_PCI_INTB_IRQ = 123, FSL_IMX8MM_PCI_INTC_IRQ = 124, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> It enables emulation of USB on iMX8MM Enables testing and debugging of USB drivers Reviewed-by: Philippe Mathieu-Daude <philmd@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx8mm.c | 27 +++++++++++++++++++++++++++ include/hw/arm/fsl-imx8mm.h | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX8MM select SDHCI select PCI_EXPRESS_DESIGNWARE select PCI_EXPRESS_FSL_IMX8M_PHY + select USB_DWC3 select WDT_IMX2 config FSL_IMX8MM_EVK diff --git a/hw/arm/fsl-imx8mm.c b/hw/arm/fsl-imx8mm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx8mm.c +++ b/hw/arm/fsl-imx8mm.c @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_init(Object *obj) object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC); } + for (i = 0; i < FSL_IMX8MM_NUM_USBS; i++) { + g_autofree char *name = g_strdup_printf("usb%d", i); + object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3); + } + for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { g_autofree char *name = g_strdup_printf("spi%d", i + 1); object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(gicdev, usdhc_table[i].irq)); } + /* USBs */ + for (i = 0; i < FSL_IMX8MM_NUM_USBS; i++) { + static const struct { + hwaddr addr; + unsigned int irq; + } usb_table[FSL_IMX8MM_NUM_USBS] = { + { fsl_imx8mm_memmap[FSL_IMX8MM_USB1].addr, FSL_IMX8MM_USB1_IRQ }, + { fsl_imx8mm_memmap[FSL_IMX8MM_USB2].addr, FSL_IMX8MM_USB2_IRQ }, + }; + + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1); + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1); + qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0, + qdev_get_gpio_in(gicdev, usb_table[i].irq)); + } + /* ECSPIs */ for (i = 0; i < FSL_IMX8MM_NUM_ECSPIS; i++) { static const struct { @@ -XXX,XX +XXX,XX @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp) case FSL_IMX8MM_OCRAM: case FSL_IMX8MM_SNVS_HP: case FSL_IMX8MM_UART1 ... FSL_IMX8MM_UART4: + case FSL_IMX8MM_USB1 ... FSL_IMX8MM_USB2: case FSL_IMX8MM_USDHC1 ... FSL_IMX8MM_USDHC3: case FSL_IMX8MM_WDOG1 ... FSL_IMX8MM_WDOG3: /* device implemented and treated above */ diff --git a/include/hw/arm/fsl-imx8mm.h b/include/hw/arm/fsl-imx8mm.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx8mm.h +++ b/include/hw/arm/fsl-imx8mm.h @@ -XXX,XX +XXX,XX @@ #include "hw/sd/sdhci.h" #include "hw/ssi/imx_spi.h" #include "hw/timer/imx_gpt.h" +#include "hw/usb/hcd-dwc3.h" #include "hw/watchdog/wdt_imx2.h" #include "qom/object.h" #include "qemu/units.h" @@ -XXX,XX +XXX,XX @@ enum FslImx8mmConfiguration { FSL_IMX8MM_NUM_I2CS = 4, FSL_IMX8MM_NUM_IRQS = 128, FSL_IMX8MM_NUM_UARTS = 4, + FSL_IMX8MM_NUM_USBS = 2, FSL_IMX8MM_NUM_USDHCS = 3, FSL_IMX8MM_NUM_WDTS = 3, }; @@ -XXX,XX +XXX,XX @@ struct FslImx8mmState { IMXFECState enet; SDHCIState usdhc[FSL_IMX8MM_NUM_USDHCS]; IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS]; + USBDWC3 usb[FSL_IMX8MM_NUM_USBS]; DesignwarePCIEHost pcie; FslImx8mPciePhyState pcie_phy; OrIRQState gpt5_gpt6_irq; @@ -XXX,XX +XXX,XX @@ enum FslImx8mmIrqs { FSL_IMX8MM_I2C3_IRQ = 37, FSL_IMX8MM_I2C4_IRQ = 38, + FSL_IMX8MM_USB1_IRQ = 40, + FSL_IMX8MM_USB2_IRQ = 41, + FSL_IMX8MM_GPT1_IRQ = 55, FSL_IMX8MM_GPT2_IRQ = 54, FSL_IMX8MM_GPT3_IRQ = 53, -- 2.43.0
From: Gaurav Sharma <gaurav.sharma_7@nxp.com> Added script that would validate the iMX8MM emulation by checking the linux console log. If it succeeds, it will return:- ok 1 test_imx8mm_evk.Imx8mmEvkMachine.test_aarch64_imx8mm_evk_usdhc Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Bernhard Beschow <shentey@gmail.com> [PMM: Add missing blank lines that flake8 wants] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 1 + tests/functional/aarch64/meson.build | 2 + tests/functional/aarch64/test_imx8mm_evk.py | 69 +++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100755 tests/functional/aarch64/test_imx8mm_evk.py diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/arm/fsl-imx8mm.c F: hw/arm/imx8mm-evk.c F: include/hw/arm/fsl-imx8mm.h F: docs/system/arm/imx8m.rst +F: tests/functional/aarch64/test_imx8mm_evk.py MCIMX8MP-EVK / i.MX8MP M: Bernhard Beschow <shentey@gmail.com> diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/aarch64/meson.build +++ b/tests/functional/aarch64/meson.build @@ -XXX,XX +XXX,XX @@ test_aarch64_timeouts = { 'aspeed_ast2700a2' : 600, 'aspeed_ast2700fc' : 600, 'device_passthrough' : 720, + 'imx8mm_evk' : 240, 'imx8mp_evk' : 240, 'raspi4' : 480, 'reverse_debug' : 180, @@ -XXX,XX +XXX,XX @@ tests_aarch64_system_thorough = [ 'aspeed_ast2700fc', 'device_passthrough', 'hotplug_pci', + 'imx8mm_evk', 'imx8mp_evk', 'kvm', 'multiprocess', diff --git a/tests/functional/aarch64/test_imx8mm_evk.py b/tests/functional/aarch64/test_imx8mm_evk.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/aarch64/test_imx8mm_evk.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots a Linux kernel and checks the console +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import LinuxKernelTest, Asset + + +class Imx8mmEvkMachine(LinuxKernelTest): + + ASSET_IMAGE = Asset( + ('https://cloud.debian.org/images/cloud/bookworm/20231210-1590/' + 'debian-12-generic-arm64-20231210-1590.tar.xz'), + '7ebf1577b32d5af6204df74b54ca2e4675de9b5a9fa14f3ff70b88eeb7b3b359') + + KERNEL_OFFSET = 0x51000000 + KERNEL_SIZE = 32622528 + INITRD_OFFSET = 0x76000000 + INITRD_SIZE = 30987766 + DTB_OFFSET = 0x64DB5000 + DTB_SIZE = 36812 + + def extract(self, in_path, out_path, offset, size): + try: + with open(in_path, "rb") as source: + source.seek(offset) + data = source.read(size) + with open(out_path, "wb") as target: + target.write(data) + except (IOError, ValueError) as e: + self.log.error(f"Failed to extract {out_path}: {e}") + raise + + def setUp(self): + super().setUp() + + self.image_path = self.scratch_file("disk.raw") + self.kernel_path = self.scratch_file("linux") + self.initrd_path = self.scratch_file("initrd.zstd") + self.dtb_path = self.scratch_file("imx8mm-evk.dtb") + + self.archive_extract(self.ASSET_IMAGE) + self.extract(self.image_path, self.kernel_path, + self.KERNEL_OFFSET, self.KERNEL_SIZE) + self.extract(self.image_path, self.initrd_path, + self.INITRD_OFFSET, self.INITRD_SIZE) + self.extract(self.image_path, self.dtb_path, + self.DTB_OFFSET, self.DTB_SIZE) + + def test_aarch64_imx8mm_evk_usdhc(self): + self.require_accelerator("tcg") + self.set_machine('imx8mm-evk') + self.vm.set_console(console_index=1) + self.vm.add_args('-m', '2G', + '-smp', '4', + '-kernel', self.kernel_path, + '-initrd', self.initrd_path, + '-dtb', self.dtb_path, + '-append', 'root=/dev/mmcblk2p1', + '-drive', f'file={self.image_path},if=sd,bus=2,' + 'format=raw,id=mmcblk2,snapshot=on') + + self.vm.launch() + self.wait_for_console_pattern('Welcome to ') + + +if __name__ == '__main__': + LinuxKernelTest.main() -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> As mentioned by Richard in [*]: We don't actually need any specific endianness here, because every byte has the same value. So we could simply drop MO_TE. That would produce a store in host-endianness, which will be fractionally more efficient on some hosts. [*] https://lore.kernel.org/qemu-devel/d64d3576-9188-4e74-afdc-3492c9feb8e0@linaro.org/ Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260414005348.4767-2-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -XXX,XX +XXX,XX @@ static uint64_t set_step_tags(CPUARMState *env, uint64_t toaddr, * the page dirty and will use the fast path. */ uint64_t repldata = data * 0x0101010101010101ULL; - MemOpIdx oi16 = make_memop_idx(MO_TE | MO_128, memidx); + MemOpIdx oi16 = make_memop_idx(MO_128, memidx); cpu_st16_mmu(env, toaddr, int128_make128(repldata, repldata), oi16, ra); mte_mops_set_tags(env, toaddr, 16, *mtedesc); return 16; -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Extract the implicit MO_TE definition in order to replace it in the next commit. Mechanical change using: $ for n in UW UL UQ UO SW SL SQ; do \ sed -i -e "s/MO_TE$n/MO_TE | MO_$n/" \ $(git grep -l MO_TE$n target/arm); \ done Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-3-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 6 +-- target/arm/tcg/mve_helper.c | 79 ++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) /* Note that these stores can throw exceptions on MPU faults */ ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); cpu_stl_mmu(env, sp, nextinst, oi, GETPC()); cpu_stl_mmu(env, sp + 4, saved_psr, oi, GETPC()); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); assert(env->v7m.secure); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) ARMCPU *cpu = env_archcpu(env); uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); /* fptr is the value of Rn, the frame pointer we load the FP regs from */ diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) } DO_VLDR(vldrb, MO_UB, 1, uint8_t, ldb, 1, uint8_t) -DO_VLDR(vldrh, MO_TEUW, 2, uint16_t, ldw, 2, uint16_t) -DO_VLDR(vldrw, MO_TEUL, 4, uint32_t, ldl, 4, uint32_t) +DO_VLDR(vldrh, MO_TE | MO_UW, 2, uint16_t, ldw, 2, uint16_t) +DO_VLDR(vldrw, MO_TE | MO_UL, 4, uint32_t, ldl, 4, uint32_t) DO_VSTR(vstrb, MO_UB, 1, stb, 1, uint8_t) -DO_VSTR(vstrh, MO_TEUW, 2, stw, 2, uint16_t) -DO_VSTR(vstrw, MO_TEUL, 4, stl, 4, uint32_t) +DO_VSTR(vstrh, MO_TE | MO_UW, 2, stw, 2, uint16_t) +DO_VSTR(vstrw, MO_TE | MO_UL, 4, stl, 4, uint32_t) DO_VLDR(vldrb_sh, MO_SB, 1, int8_t, ldb, 2, int16_t) DO_VLDR(vldrb_sw, MO_SB, 1, int8_t, ldb, 4, int32_t) DO_VLDR(vldrb_uh, MO_UB, 1, uint8_t, ldb, 2, uint16_t) DO_VLDR(vldrb_uw, MO_UB, 1, uint8_t, ldb, 4, uint32_t) -DO_VLDR(vldrh_sw, MO_TESW, 2, int16_t, ldw, 4, int32_t) -DO_VLDR(vldrh_uw, MO_TEUW, 2, uint16_t, ldw, 4, uint32_t) +DO_VLDR(vldrh_sw, MO_TE | MO_SW, 2, int16_t, ldw, 4, int32_t) +DO_VLDR(vldrh_uw, MO_TE | MO_UW, 2, uint16_t, ldw, 4, uint32_t) DO_VSTR(vstrb_h, MO_UB, 1, stb, 2, int16_t) DO_VSTR(vstrb_w, MO_UB, 1, stb, 4, int32_t) -DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) +DO_VSTR(vstrh_w, MO_TE | MO_UW, 2, stw, 4, int32_t) #undef DO_VLDR #undef DO_VSTR @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_TEUW, 2, stw, 4, int32_t) DO_VLDR_SG(vldrb_sg_sh, MO_SB, int8_t, ldb, 2, int16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_sw, MO_SB, int8_t, ldb, 4, int32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_sw, MO_TESW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_sw, MO_TE | MO_SW, int16_t, ldw, 4, + int32_t, uint32_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_ub, MO_UB, uint8_t, ldb, 1, uint8_t, uint8_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uh, MO_UB, uint8_t, ldb, 2, uint16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uw, MO_UB, uint8_t, ldb, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uh, MO_TEUW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uw, MO_TEUW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrw_sg_uw, MO_TEUL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uh, MO_TE | MO_UW, uint16_t, ldw, 2, + uint16_t, uint16_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uw, MO_TE | MO_UW, uint16_t, ldw, 4, + uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrw_sg_uw, MO_TE | MO_UL, uint32_t, ldl, 4, + uint32_t, uint32_t, ADDR_ADD, false) DO_VLDR64_SG(vldrd_sg_ud, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_os_sw, MO_TESW, int16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_sw, MO_TE | MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uh, MO_TEUW, uint16_t, ldw, 2, +DO_VLDR_SG(vldrh_sg_os_uh, MO_TE | MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uw, MO_TEUW, uint16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_uw, MO_TE | MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrw_sg_os_uw, MO_TEUL, uint32_t, ldl, 4, +DO_VLDR_SG(vldrw_sg_os_uw, MO_TE | MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD_OSW, false) DO_VLDR64_SG(vldrd_sg_os_ud, ADDR_ADD_OSD, false) DO_VSTR_SG(vstrb_sg_ub, MO_UB, stb, 1, uint8_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uh, MO_UB, stb, 2, uint16_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uw, MO_UB, stb, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uh, MO_TEUW, stw, 2, uint16_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uw, MO_TEUW, stw, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrw_sg_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrw_sg_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, false) DO_VSTR64_SG(vstrd_sg_ud, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_os_uh, MO_TEUW, stw, 2, uint16_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrh_sg_os_uw, MO_TEUW, stw, 4, uint32_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrw_sg_os_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD_OSW, false) +DO_VSTR_SG(vstrh_sg_os_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrh_sg_os_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrw_sg_os_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) DO_VSTR64_SG(vstrd_sg_os_ud, ADDR_ADD_OSD, false) -DO_VLDR_SG(vldrw_sg_wb_uw, MO_TEUL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, true) +DO_VLDR_SG(vldrw_sg_wb_uw, MO_TE | MO_UL, uint32_t, ldl, 4, + uint32_t, uint32_t, ADDR_ADD, true) DO_VLDR64_SG(vldrd_sg_wb_ud, ADDR_ADD, true) -DO_VSTR_SG(vstrw_sg_wb_uw, MO_TEUL, stl, 4, uint32_t, ADDR_ADD, true) +DO_VSTR_SG(vstrw_sg_wb_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, true) DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) /* @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-4-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t eci_mask = mve_eci_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ /* \ * R_SXTM allows the dest reg to become UNKNOWN for abandoned \ * beats so we don't care if we update part of the dest and \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t mask = mve_element_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (b = 0, e = 0; b < 16; b += ESIZE, e++) { \ if (mask & (1 << b)) { \ cpu_##STTYPE##_mmu(env, addr, d[H##ESIZE(e)], oi, GETPC()); \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) } DO_VLDR(vldrb, MO_UB, 1, uint8_t, ldb, 1, uint8_t) -DO_VLDR(vldrh, MO_TE | MO_UW, 2, uint16_t, ldw, 2, uint16_t) -DO_VLDR(vldrw, MO_TE | MO_UL, 4, uint32_t, ldl, 4, uint32_t) +DO_VLDR(vldrh, MO_UW, 2, uint16_t, ldw, 2, uint16_t) +DO_VLDR(vldrw, MO_UL, 4, uint32_t, ldl, 4, uint32_t) DO_VSTR(vstrb, MO_UB, 1, stb, 1, uint8_t) -DO_VSTR(vstrh, MO_TE | MO_UW, 2, stw, 2, uint16_t) -DO_VSTR(vstrw, MO_TE | MO_UL, 4, stl, 4, uint32_t) +DO_VSTR(vstrh, MO_UW, 2, stw, 2, uint16_t) +DO_VSTR(vstrw, MO_UL, 4, stl, 4, uint32_t) DO_VLDR(vldrb_sh, MO_SB, 1, int8_t, ldb, 2, int16_t) DO_VLDR(vldrb_sw, MO_SB, 1, int8_t, ldb, 4, int32_t) DO_VLDR(vldrb_uh, MO_UB, 1, uint8_t, ldb, 2, uint16_t) DO_VLDR(vldrb_uw, MO_UB, 1, uint8_t, ldb, 4, uint32_t) -DO_VLDR(vldrh_sw, MO_TE | MO_SW, 2, int16_t, ldw, 4, int32_t) -DO_VLDR(vldrh_uw, MO_TE | MO_UW, 2, uint16_t, ldw, 4, uint32_t) +DO_VLDR(vldrh_sw, MO_SW, 2, int16_t, ldw, 4, int32_t) +DO_VLDR(vldrh_uw, MO_UW, 2, uint16_t, ldw, 4, uint32_t) DO_VSTR(vstrb_h, MO_UB, 1, stb, 2, int16_t) DO_VSTR(vstrb_w, MO_UB, 1, stb, 4, int32_t) -DO_VSTR(vstrh_w, MO_TE | MO_UW, 2, stw, 4, int32_t) +DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) #undef DO_VLDR #undef DO_VSTR -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-5-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 43 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MFLAG | MO_ALIGN, mmu_idx); \ + MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) DO_VLDR_SG(vldrb_sg_sh, MO_SB, int8_t, ldb, 2, int16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_sw, MO_SB, int8_t, ldb, 4, int32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_sw, MO_TE | MO_SW, int16_t, ldw, 4, - int32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_sw, MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_ub, MO_UB, uint8_t, ldb, 1, uint8_t, uint8_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uh, MO_UB, uint8_t, ldb, 2, uint16_t, uint16_t, ADDR_ADD, false) DO_VLDR_SG(vldrb_sg_uw, MO_UB, uint8_t, ldb, 4, uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uh, MO_TE | MO_UW, uint16_t, ldw, 2, - uint16_t, uint16_t, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_uw, MO_TE | MO_UW, uint16_t, ldw, 4, - uint32_t, uint32_t, ADDR_ADD, false) -DO_VLDR_SG(vldrw_sg_uw, MO_TE | MO_UL, uint32_t, ldl, 4, - uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uh, MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD, false) +DO_VLDR_SG(vldrh_sg_uw, MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD, false) +DO_VLDR_SG(vldrw_sg_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, false) DO_VLDR64_SG(vldrd_sg_ud, ADDR_ADD, false) -DO_VLDR_SG(vldrh_sg_os_sw, MO_TE | MO_SW, int16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_sw, MO_SW, int16_t, ldw, 4, int32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uh, MO_TE | MO_UW, uint16_t, ldw, 2, +DO_VLDR_SG(vldrh_sg_os_uh, MO_UW, uint16_t, ldw, 2, uint16_t, uint16_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrh_sg_os_uw, MO_TE | MO_UW, uint16_t, ldw, 4, +DO_VLDR_SG(vldrh_sg_os_uw, MO_UW, uint16_t, ldw, 4, uint32_t, uint32_t, ADDR_ADD_OSH, false) -DO_VLDR_SG(vldrw_sg_os_uw, MO_TE | MO_UL, uint32_t, ldl, 4, +DO_VLDR_SG(vldrw_sg_os_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD_OSW, false) DO_VLDR64_SG(vldrd_sg_os_ud, ADDR_ADD_OSD, false) DO_VSTR_SG(vstrb_sg_ub, MO_UB, stb, 1, uint8_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uh, MO_UB, stb, 2, uint16_t, ADDR_ADD, false) DO_VSTR_SG(vstrb_sg_uw, MO_UB, stb, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD, false) -DO_VSTR_SG(vstrw_sg_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uh, MO_UW, stw, 2, uint16_t, ADDR_ADD, false) +DO_VSTR_SG(vstrh_sg_uw, MO_UW, stw, 4, uint32_t, ADDR_ADD, false) +DO_VSTR_SG(vstrw_sg_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD, false) DO_VSTR64_SG(vstrd_sg_ud, ADDR_ADD, false) -DO_VSTR_SG(vstrh_sg_os_uh, MO_TE | MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrh_sg_os_uw, MO_TE | MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) -DO_VSTR_SG(vstrw_sg_os_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) +DO_VSTR_SG(vstrh_sg_os_uh, MO_UW, stw, 2, uint16_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrh_sg_os_uw, MO_UW, stw, 4, uint32_t, ADDR_ADD_OSH, false) +DO_VSTR_SG(vstrw_sg_os_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD_OSW, false) DO_VSTR64_SG(vstrd_sg_os_ud, ADDR_ADD_OSD, false) -DO_VLDR_SG(vldrw_sg_wb_uw, MO_TE | MO_UL, uint32_t, ldl, 4, - uint32_t, uint32_t, ADDR_ADD, true) +DO_VLDR_SG(vldrw_sg_wb_uw, MO_UL, uint32_t, ldl, 4, uint32_t, uint32_t, ADDR_ADD, true) DO_VLDR64_SG(vldrd_sg_wb_ud, ADDR_ADD, true) -DO_VSTR_SG(vstrw_sg_wb_uw, MO_TE | MO_UL, stl, 4, uint32_t, ADDR_ADD, true) +DO_VSTR_SG(vstrw_sg_wb_uw, MO_UL, stl, 4, uint32_t, ADDR_ADD, true) DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) /* -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Suggested-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-6-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/internals.h | 6 ++++++ target/arm/tcg/mve_helper.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) 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 @@ #include "exec/hwaddr.h" #include "exec/vaddr.h" #include "exec/breakpoint.h" +#include "exec/memop.h" #include "accel/tcg/tb-cpu-state.h" #include "hw/core/registerfields.h" #include "tcg/tcg-gvec-desc.h" @@ -XXX,XX +XXX,XX @@ #define BANK_HYP 6 #define BANK_MON 7 +static inline MemOp mo_endian(CPUARMState *env) +{ + return EX_TBFLAG_ANY(env->hflags, BE_DATA) ? MO_BE : MO_LE; +} + static inline int arm_env_mmu_index(CPUARMState *env) { return EX_TBFLAG_ANY(env->hflags, MMUIDX); diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-7-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/mve_helper.c | 47 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t eci_mask = mve_eci_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ /* \ * R_SXTM allows the dest reg to become UNKNOWN for abandoned \ @@ -XXX,XX +XXX,XX @@ static void mve_advance_vpt(CPUARMState *env) uint16_t mask = mve_element_mask(env); \ unsigned b, e; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (b = 0, e = 0; b < 16; b += ESIZE, e++) { \ if (mask & (1 << b)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MFLAG | MO_ALIGN, \ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MFLAG | MO_ALIGN, \ mmu_idx); \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE, eci_mask >>= ESIZE) { \ if (!(eci_mask & 1)) { \ @@ -XXX,XX +XXX,XX @@ DO_VSTR(vstrh_w, MO_UW, 2, stw, 4, int32_t) unsigned e; \ uint32_t addr; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (e = 0; e < 16 / 4; e++, mask >>= 4, eci_mask >>= 4) { \ if (!(eci_mask & 1)) { \ continue; \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VSTR64_SG(vstrd_sg_wb_ud, ADDR_ADD, true) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD4W(vld43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) static const uint8_t off[4] = { O1, O2, O3, O4 }; \ uint32_t addr, data; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) int y; /* y counts 0 2 0 2 */ \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0, y = 0; beat < 4; beat++, mask >>= 4, y ^= 2) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VLD2W(vld21w, 8, 12, 16, 20) uint32_t *qd; \ int y; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint8_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) int e; \ uint16_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ @@ -XXX,XX +XXX,XX @@ DO_VST4W(vst43w, 6, 7, 8, 9) uint32_t addr, data; \ uint32_t *qd; \ int mmu_idx = arm_to_core_mmu_idx(arm_mmu_idx(env)); \ - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, mmu_idx);\ + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, \ + mmu_idx); \ for (beat = 0; beat < 4; beat++, mask >>= 4) { \ if ((mask & 1) == 0) { \ /* ECI says skip this beat */ \ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-8-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/meson.build | 3 ++- target/arm/tcg/mve_helper.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_false: files('stubs32.c')) arm_ss.add(files( 'cpu32.c', 'm_helper.c', - 'mve_helper.c', )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( @@ -XXX,XX +XXX,XX @@ arm_common_system_ss.add( 'debug.c', 'hflags.c', 'gengvec.c', + 'mve_helper.c', 'neon_helper.c', 'op_helper.c', 'psci.c', @@ -XXX,XX +XXX,XX @@ arm_user_ss.add( 'debug.c', 'gengvec.c', 'hflags.c', + 'mve_helper.c', 'neon_helper.c', 'op_helper.c', 'tlb_helper.c', diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -XXX,XX +XXX,XX @@ #include "helper-mve.h" #include "internals.h" #include "vec_internal.h" -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" #include "tcg/tcg.h" #include "fpu/softfloat.h" #include "crypto/clmul.h" -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-9-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) /* Note that these stores can throw exceptions on MPU faults */ ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); cpu_stl_mmu(env, sp, nextinst, oi, GETPC()); cpu_stl_mmu(env, sp + 4, saved_psr, oi, GETPC()); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr) bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK; uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); assert(env->v7m.secure); @@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr) ARMCPU *cpu = env_archcpu(env); uintptr_t ra = GETPC(); ARMMMUIdx mmu_idx = arm_mmu_idx(env); - MemOpIdx oi = make_memop_idx(MO_TE | MO_UL | MO_ALIGN, + MemOpIdx oi = make_memop_idx(mo_endian(env) | MO_UL | MO_ALIGN, arm_to_core_mmu_idx(mmu_idx)); /* fptr is the value of Rn, the frame pointer we load the FP regs from */ -- 2.43.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260414005348.4767-10-philmd@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/m_helper.c | 2 +- target/arm/tcg/meson.build | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -XXX,XX +XXX,XX @@ #include "qemu/log.h" #include "exec/page-protection.h" #ifdef CONFIG_TCG -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" #include "semihosting/common-semi.h" #endif #if !defined(CONFIG_USER_ONLY) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_false: files('stubs32.c')) arm_ss.add(files( 'cpu32.c', - 'm_helper.c', )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( @@ -XXX,XX +XXX,XX @@ arm_common_system_ss.add( 'debug.c', 'hflags.c', 'gengvec.c', + 'm_helper.c', 'mve_helper.c', 'neon_helper.c', 'op_helper.c', @@ -XXX,XX +XXX,XX @@ arm_user_ss.add( 'debug.c', 'gengvec.c', 'hflags.c', + 'm_helper.c', 'mve_helper.c', 'neon_helper.c', 'op_helper.c', -- 2.43.0
From: Thomas Huth <thuth@redhat.com> When writing to this register, QEMU currently aborts: $ echo "readl 0x10000018" | ./qemu-system-arm -audiodev none,id=snd0 \ -M integratorcp,accel=qtest,audiodev=snd0 -display none -qtest stdio [I 0.000000] OPENED [R +0.001907] readl 0x10000018 qemu: hardware error: integratorcm_read: CM_LMBUSCNT [...] Aborted (core dumped) This is bad, a guest should ideally never be able to kill QEMU like this. Now, according to the "Intergrator/CP User Guide" from: https://developer.arm.com/documentation/dui0159/b/porting-integrator-ap-and-im-pd1/registers "The Integrator/AP CM_LMBUSCNT has been removed." That means this register does not seem to be implemented on real CP boards at all, only for older AP boards. Thus it should be fine if we simply ignore this register in QEMU and handle it like all other unimplemented registers in the "default" handler of the case statement. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3407 Signed-off-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260420064933.64765-1-thuth@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/integratorcp.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -XXX,XX +XXX,XX @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, } else { return s->cm_lock; } - case 6: /* CM_LMBUSCNT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_LMBUSCNT"); case 7: /* CM_AUXOSC */ return s->cm_auxosc; case 8: /* CM_SDRAM */ -- 2.43.0
include/hw/arm/primecell.h used to be more expansive, but now the only thing it defines is the ARM_SYSCTL_GPIO_* constants for the GPIO lines for the arm-sysctl system-control device used on the Realview, Versatile and Versatile Express boards. Replace it with a header file specific to that device. virt.c and vmapple.c included primecell.h despite not using the constants it defined; there we can simply drop the include entirely. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416172627.690396-1-peter.maydell@linaro.org --- MAINTAINERS | 2 +- hw/arm/realview.c | 2 +- hw/arm/vexpress.c | 2 +- hw/arm/virt.c | 1 - hw/misc/arm_sysctl.c | 2 +- hw/vmapple/vmapple.c | 1 - include/hw/arm/primecell.h | 12 ------------ include/hw/misc/arm_sysctl.h | 16 ++++++++++++++++ 8 files changed, 20 insertions(+), 18 deletions(-) delete mode 100644 include/hw/arm/primecell.h create mode 100644 include/hw/misc/arm_sysctl.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/ssi/pl022.c F: include/hw/ssi/pl022.h F: hw/rtc/pl031.c F: include/hw/rtc/pl031.h -F: include/hw/arm/primecell.h F: hw/timer/cmsdk-apb-timer.c F: include/hw/timer/cmsdk-apb-timer.h F: tests/qtest/cmsdk-apb-timer-test.c @@ -XXX,XX +XXX,XX @@ F: hw/*/versatile* F: hw/i2c/arm_sbcon_i2c.c F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c +F: include/hw/misc/arm_sysctl.h F: docs/system/arm/versatile.rst Virt diff --git a/hw/arm/realview.c b/hw/arm/realview.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -XXX,XX +XXX,XX @@ #include "target/arm/cpu.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/machines-qom.h" #include "hw/core/split-irq.h" +#include "hw/misc/arm_sysctl.h" #include "hw/net/lan9118.h" #include "hw/net/smc91c111.h" #include "hw/pci/pci.h" diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -XXX,XX +XXX,XX @@ #include "qemu/datadir.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/machines-qom.h" +#include "hw/misc/arm_sysctl.h" #include "hw/net/lan9118.h" #include "hw/i2c/i2c.h" #include "net/net.h" 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 @@ #include "monitor/qdev.h" #include "hw/core/sysbus.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/arm/virt.h" #include "hw/arm/machines-qom.h" #include "hw/block/flash.h" diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -XXX,XX +XXX,XX @@ #include "system/runstate.h" #include "qemu/bitops.h" #include "hw/core/sysbus.h" +#include "hw/misc/arm_sysctl.h" #include "migration/vmstate.h" -#include "hw/arm/primecell.h" #include "qemu/log.h" #include "qemu/module.h" #include "qom/object.h" diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c index XXXXXXX..XXXXXXX 100644 --- a/hw/vmapple/vmapple.c +++ b/hw/vmapple/vmapple.c @@ -XXX,XX +XXX,XX @@ #include "hw/core/sysbus.h" #include "hw/usb/usb.h" #include "hw/arm/boot.h" -#include "hw/arm/primecell.h" #include "hw/char/pl011.h" #include "hw/intc/arm_gic.h" #include "hw/intc/arm_gicv3_common.h" diff --git a/include/hw/arm/primecell.h b/include/hw/arm/primecell.h deleted file mode 100644 index XXXXXXX..XXXXXXX --- a/include/hw/arm/primecell.h +++ /dev/null @@ -XXX,XX +XXX,XX @@ -#ifndef PRIMECELL_H -#define PRIMECELL_H - -/* Declarations for ARM PrimeCell based periperals. */ -/* Also includes some devices that are currently only used by the - ARM boards. */ - -/* arm_sysctl GPIO lines */ -#define ARM_SYSCTL_GPIO_MMC_WPROT 0 -#define ARM_SYSCTL_GPIO_MMC_CARDIN 1 - -#endif diff --git a/include/hw/misc/arm_sysctl.h b/include/hw/misc/arm_sysctl.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/misc/arm_sysctl.h @@ -XXX,XX +XXX,XX @@ +/* + * Status and system control registers for ARM RealView/Versatile boards. + * + * Copyright (c) Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_ARM_SYSCTL_H +#define HW_MISC_ARM_SYSCTL_H + +/* arm_sysctl inbound GPIO lines */ +#define ARM_SYSCTL_GPIO_MMC_WPROT 0 +#define ARM_SYSCTL_GPIO_MMC_CARDIN 1 + +#endif -- 2.43.0
If we create a normally-AArch64 CPU and configure it with aarch64=off, this will by default leave all the AArch64 ID register values in its ARMISARegisters struct untouched. That in turn means that tests of cpu_isar_feature(aa64_something, cpu) will return true. Until now we have had a design policy that you shouldn't check an aa64_ feature unless you know that the CPU has AArch64; but this is quite fragile as it's easy to forget and only causes a problem in the corner case where AArch64 was turned off. In particular, when we extend the ability to disable AArch64 from only KVM to also TCG there are many more aa64 feature check points which we would otherwise have to audit for whether they needed to be guarded with a check on ARM_FEATURE_AARCH64. Instead, make the CPU realize function zero out all the 64-bit ID registers if a TCG CPU doesn't have AArch64; this will make aa64_ feature tests generally return false. We only do this for TCG because only TCG really needs it, and for KVM it might be confusing to have QEMU's idea of the ID registers be different from KVM's. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260416165353.589569-2-peter.maydell@linaro.org --- target/arm/cpu.c | 35 +++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 3 ++- 2 files changed, 37 insertions(+), 1 deletion(-) 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_cpu_finalize_features(ARMCPU *cpu, Error **errp) } } +static void arm_clear_aarch64_idregs(ARMCPU *cpu) +{ + /* Zero out all the AArch64 ID registers in ARMISARegisters */ + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0); + SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0); + SET_IDREG(&cpu->isar, ID_AA64ISAR2, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64PFR2, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR2, 0); + SET_IDREG(&cpu->isar, ID_AA64MMFR3, 0); + SET_IDREG(&cpu->isar, ID_AA64DFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64DFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64AFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64AFR1, 0); + SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0); + SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0); +} + static void arm_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #endif + /* + * A TCG aarch64=off CPU has no AArch64 at all, so we clear out the + * ID registers to avoid cpu_isar_feature(aa64_something, cpu) tests + * incorrectly returning true. We don't do this for other accelerators + * (which in practice means "for KVM", since no others have AArch32 + * guest support) because from KVM's point of view the AArch64 ID + * registers still exist and must have their correct values. So we + * avoid clearing them out so that we don't have QEMU and KVM with + * different ideas of the ID registers. + */ + if (tcg_enabled() && !arm_feature(env, ARM_FEATURE_AARCH64)) { + arm_clear_aarch64_idregs(cpu); + } + #ifdef CONFIG_USER_ONLY /* * User mode relies on IC IVAU instructions to catch modification of 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 { * Note that if you add an ID register to the ARMISARegisters struct * you need to also update the 32-bit and 64-bit versions of the * kvm_arm_get_host_cpu_features() function to correctly populate the - * field by reading the value from the KVM vCPU. + * field by reading the value from the KVM vCPU. If it is an AArch64 + * ID register then you also must update arm_clear_aarch64_idregs(). */ struct ARMISARegisters { uint32_t mvfr0; -- 2.43.0
Allow the 'aarch64=off' property, which is currently KVM-only, to be set for TCG CPUs also. Note that we don't permit it on the qemu-aarch64 user-mode binary: this makes no sense as that executable can only handle AArch64 syscalls (and it would also assert at startup since it doesn't compile in the A32-specific GDB xml files like arm-neon.xml). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Clément Chigot <chigot@adacore.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416165353.589569-3-peter.maydell@linaro.org --- docs/system/arm/cpu-features.rst | 10 +++++---- target/arm/cpu-features.h | 5 +++++ target/arm/cpu.c | 36 ++++++++++++++++++++++++++++---- tests/qtest/arm-cpu-features.c | 8 ++----- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -XXX,XX +XXX,XX @@ not implement ARMv8-A, will not have the ``aarch64`` CPU property. QEMU's support may be limited for some CPU features, only partially supporting the feature or only supporting the feature under certain configurations. For example, the ``aarch64`` CPU feature, which, when -disabled, enables the optional AArch32 CPU feature, is only supported -when using the KVM accelerator and when running on a host CPU type that -supports the feature. While ``aarch64`` currently only works with KVM, -it could work with TCG. CPU features that are specific to KVM are +disabled, enables the optional AArch32 CPU feature, can only be set to +``off`` on the TCG and KVM accelerators, and it cannot be set to +``off`` under KVM unless running on a host CPU type that supports +running guests in AArch32. + +CPU features that are inherently specific to KVM are prefixed with "kvm-" and are described in "KVM VCPU Features". CPU Feature Probing 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_aa32_el2(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL2) >= 2; } +static inline bool isar_feature_aa64_aa32_el3(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL3) >= 2; +} + static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR0, RAS) != 0; 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 aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) * uniform execution state like do_interrupt. */ if (value == false) { - if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { - error_setg(errp, "'aarch64' feature cannot be disabled " - "unless KVM is enabled and 32-bit EL1 " - "is supported"); + if (kvm_enabled()) { + if (!kvm_arm_aarch32_supported()) { + error_setg(errp, "'aarch64' feature cannot be disabled for KVM " + "because this host does not support 32-bit EL1"); + return; + } + } else if (tcg_enabled()) { +#ifdef CONFIG_USER_ONLY + error_setg(errp, "'aarch64' feature cannot be disabled for " + "usermode emulator qemu-aarch64; use qemu-arm instead"); + return; +#else + bool aa32_at_highest_el; + if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el3, cpu); + } else if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el2, cpu); + } else { + aa32_at_highest_el = cpu_isar_feature(aa64_aa32_el1, cpu); + } + + if (!aa32_at_highest_el) { + error_setg(errp, "'aarch64' feature cannot be disabled for " + "this TCG CPU because it does not support 32-bit " + "execution at its highest implemented exception " + "level"); + return; + } +#endif + } else { + error_setg(errp, "'aarch64' feature cannot be disabled for " + "this accelerator"); return; } unset_feature(&cpu->env, ARM_FEATURE_AARCH64); diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -XXX,XX +XXX,XX @@ static void test_query_cpu_model_expansion(const void *data) sve_tests_default(qts, "max"); pauth_tests_default(qts, "max"); - /* Test that features that depend on KVM generate errors without. */ - assert_error(qts, "max", - "'aarch64' feature cannot be disabled " - "unless KVM is enabled and 32-bit EL1 " - "is supported", - "{ 'aarch64': false }"); + /* TCG allows us to turn off AArch64 on the 'max' CPU type */ + assert_set_feature(qts, "max", "aarch64", false); } qtest_quit(qts); -- 2.43.0
Add a basic test of the TCG 'aarch64=off' functionality; this is the same as our existing arm/test_virt test, but it runs the AArch32 guest kernel on qemu-system-aarch64 with -cpu max,aarch64=off. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260416165353.589569-4-peter.maydell@linaro.org --- tests/functional/aarch64/meson.build | 1 + .../aarch64/test_virt_aarch64_off.py | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100755 tests/functional/aarch64/test_virt_aarch64_off.py diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/functional/aarch64/meson.build +++ b/tests/functional/aarch64/meson.build @@ -XXX,XX +XXX,XX @@ tests_aarch64_system_thorough = [ 'tcg_plugins', 'tuxrun', 'virt', + 'virt_aarch64_off', 'virt_gpu', 'virt_vbsa', 'xen', diff --git a/tests/functional/aarch64/test_virt_aarch64_off.py b/tests/functional/aarch64/test_virt_aarch64_off.py new file mode 100755 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/functional/aarch64/test_virt_aarch64_off.py @@ -XXX,XX +XXX,XX @@ +#!/usr/bin/env python3 +# +# Functional test that boots an AArch32 Linux kernel and checks the console +# on a TCG aarch64 CPU with aarch64=off. This is the same image etc +# as we use in tests/functional/arm/test_virt.py. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import LinuxKernelTest, Asset + +class ArmVirtMachine(LinuxKernelTest): + + ASSET_KERNEL = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz'), + '18dd5f1a9a28bd539f9d047f7c0677211bae528e8712b40ca5a229a4ad8e2591') + + def test_arm_virt(self): + self.set_machine('virt') + # KVM aarch64=off requires a host CPU that supports it, so + # restrict the test to TCG only + self.require_accelerator('tcg') + self.vm.add_args('-cpu', 'max,aarch64=off') + + kernel_path = self.ASSET_KERNEL.fetch() + + self.vm.set_console() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyAMA0') + self.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line) + self.vm.launch() + console_pattern = 'Kernel command line: %s' % kernel_command_line + self.wait_for_console_pattern(console_pattern) + +if __name__ == '__main__': + LinuxKernelTest.main() -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> We introduce a datatype for a tolerance with respect to a given cpreg migration issue. The tolerance applies to a given cpreg kvm index, and can be of different types: a) mismatch in cpreg indexes - ToleranceNotOnBothEnds (cpreg index is allowed to be only present on one end) - ToleranceOnlySrcTestValue (cpreg index is allowed to be only present in source if its value @mask field matches @value) b) mismatch in cpreg values - ToleranceDiffInMask (value differences are allowed only within a mask) - ToleranceFieldLT (incoming field value must be less than a given value) - ToleranceFieldGT (incoming field value must be greater than a given value) A QLIST of such tolerances can be populated using a new helper: arm_register_cpreg_mig_tolerance() and arm_cpu_match_cpreg_mig_tolerance() allows to check whether a tolerance exists for a given kvm index and its criterion is matched. callers for those helpers will be introduced in subsequent patches. Only registration of migration tolerances related to cpreg index mismatch is currently allowed. Signed-off-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260420140552.104369-2-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 82 ++++++++++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 1 + target/arm/internals.h | 54 ++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) 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_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node); } +static ARMCPRegMigTolerance *find_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx) +{ + ARMCPRegMigTolerance *t; + QLIST_FOREACH(t, &cpu->cpreg_mig_tolerances, node) { + if (t->kvmidx == kvmidx) { + return t; + } + } + return NULL; +} + +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t mask, uint64_t value, + ARMCPRegMigToleranceType type) +{ + ARMCPRegMigTolerance *entry; + + /* make sure the kvmidx has not tolerance already registered */ + assert(!find_mig_tolerance(cpu, kvmidx)); + + assert(type == ToleranceNotOnBothEnds || + type == ToleranceOnlySrcTestValue); + + entry = g_new0(ARMCPRegMigTolerance, 1); + + entry->kvmidx = kvmidx; + entry->mask = mask; + entry->value = value; + entry->type = type; + + QLIST_INSERT_HEAD(&cpu->cpreg_mig_tolerances, entry, node); +} + +bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t vmstate_value, uint64_t local_value, + ARMCPRegMigToleranceType type) +{ + ARMCPRegMigTolerance *t = find_mig_tolerance(cpu, kvmidx); + uint64_t diff, diff_outside_mask, field; + + if (!t || t->type != type) { + return false; + } + + if (type == ToleranceNotOnBothEnds) { + return true; + } + + if (type == ToleranceOnlySrcTestValue && + ((vmstate_value & t->mask) == t->value)) { + return true; + } + + /* Need to check the mask */ + diff = vmstate_value ^ local_value; + diff_outside_mask = diff & ~t->mask; + + if (diff_outside_mask) { + /* there are differences outside of the mask */ + return false; + } + if (type == ToleranceDiffInMask) { + /* differences only in the field, tolerance matched */ + return true; + } + /* need to compare field value against authorized ones */ + field = vmstate_value & t->mask; + if (type == ToleranceFieldLT && (field < t->value)) { + return true; + } + if (type == ToleranceFieldGT && (field > t->value)) { + return true; + } + return false; +} + static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) { /* Reset a single ARMCPRegInfo register */ @@ -XXX,XX +XXX,XX @@ static void arm_cpu_initfn(Object *obj) QLIST_INIT(&cpu->pre_el_change_hooks); QLIST_INIT(&cpu->el_change_hooks); + QLIST_INIT(&cpu->cpreg_mig_tolerances); #ifdef CONFIG_USER_ONLY # ifdef TARGET_AARCH64 @@ -XXX,XX +XXX,XX @@ static void arm_cpu_finalizefn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); ARMELChangeHook *hook, *next; + ARMCPRegMigTolerance *t, *n; g_hash_table_destroy(cpu->cp_regs); @@ -XXX,XX +XXX,XX @@ static void arm_cpu_finalizefn(Object *obj) QLIST_REMOVE(hook, node); g_free(hook); } + QLIST_FOREACH_SAFE(t, &cpu->cpreg_mig_tolerances, node, n) { + QLIST_REMOVE(t, node); + g_free(t); + } #ifndef CONFIG_USER_ONLY if (cpu->pmu_timer) { timer_free(cpu->pmu_timer); 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 { QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks; QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + QLIST_HEAD(, ARMCPRegMigTolerance) cpreg_mig_tolerances; int32_t node_id; /* NUMA node this CPU belongs to */ 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 @@ int compare_u64(const void *a, const void *b); /* Used in FEAT_MEC to set the MECIDWidthm1 field in the MECIDR_EL2 register. */ #define MECID_WIDTH 16 +typedef enum { + ToleranceNotOnBothEnds, + ToleranceOnlySrcTestValue, + ToleranceDiffInMask, + ToleranceFieldLT, + ToleranceFieldGT, +} ARMCPRegMigToleranceType; + +typedef struct ARMCPRegMigTolerance { + uint64_t kvmidx; + uint64_t mask; + uint64_t value; + ARMCPRegMigToleranceType type; + QLIST_ENTRY(ARMCPRegMigTolerance) node; +} ARMCPRegMigTolerance; + +/** + * arm_register_cpreg_mig_tolerance: + * Register a migration tolerance wrt one given cpreg identified by its + * @kvmidx. Calling this function twice for the same @kvmidx is a + * programming error and will cause an assertion failure. + * + * @cpu: vcpu to apply the migration tolerance on + * @kvmidx: kvm index of the cpreg the tolerance applies to + * @mask: bitmask where a difference is tolerated + * (relevant with ToleranceDiffInMask) + * @value: value the bitmask field is compared with + * (relevant with ToleranceFieldLT and ToleranceFieldGT) + * @type: type of the migration tolerance: + * - ToleranceNotOnBothEnds (cpreg index is allowed to be only present + * on one end) + * - ToleranceOnlySrcTestValue (cpreg index is allowed to be only + * present in source if its value @mask field matches @value) + * - ToleranceDiffInMask (mismatch in cpreg values are only tolerated + * if differences are within @mask) + * - ToleranceFieldLT (mismatch in cpreg values are only tolerated + * if incoming @bitmask field value is less than @value) + * - ToleranceFieldGT (mismatch in cpreg values are only tolerated + * if incoming @bitmask field value is greater than @value) + */ +void arm_register_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t mask, uint64_t value, + ARMCPRegMigToleranceType type); + +/** + * arm_cpu_match_cpreg_mig_tolerance: + * Check whether a tolerance of type @type exists for a given @kvmidx + * and the tolerance criterion is satisfied + */ +bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, + uint64_t vmstate_value, uint64_t local_value, + ARMCPRegMigToleranceType type); + + #endif -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> If there is a mismatch between the cpreg indexes found on both ends, check whether a tolerance was registered for the given kvmidx. If any, silence warning/errors. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-3-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/machine.c | 21 +++++++++++++++------ target/arm/trace-events | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -XXX,XX +XXX,XX @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx { g_autofree gchar *name = print_register_name(kvmidx); + if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + 0, 0, ToleranceNotOnBothEnds)) { + trace_tolerate_cpreg_missing_in_incoming_stream(name); + return; + } warn_report("%s: %s " "expected by the destination but not in the incoming stream: " "skip it", __func__, name); } /* - * Handle the situation where @kvmidx is in the incoming stream - * but not on destination. This currently fails the migration but - * we plan to accomodate some exceptions, hence the boolean returned value. + * Handle the situation where @kvmidx is in the incoming + * stream but not on destination. This fails the migration if + * no cpreg mig tolerance is matched for this @kvmidx + * Return true if the migration should eventually fail */ static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx) { g_autofree gchar *name = print_register_name(kvmidx); - bool fail = true; + if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + 0, 0, ToleranceNotOnBothEnds)) { + trace_tolerate_cpreg_only_in_incoming_stream(name); + return false; + } error_report("%s: %s in the incoming stream but unknown on the " "destination: fail migration", __func__, name); - - return fail; + return true; } static int cpu_post_load(void *opaque, int version_id) diff --git a/target/arm/trace-events b/target/arm/trace-events index XXXXXXX..XXXXXXX 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -XXX,XX +XXX,XX @@ arm_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid # machine.c cpu_post_load(uint32_t cpreg_vmstate_array_len, uint32_t cpreg_array_len) "cpreg_vmstate_array_len=%d cpreg_array_len=%d" +tolerate_cpreg_missing_in_incoming_stream(char *name) "%s is missing in incoming stream but this is explicitly tolerated" +tolerate_cpreg_only_in_incoming_stream(char *name) "%s is in incoming stream but not on destination but this is explicitly tolerated" -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> Pass the value of the incoming register to handle_cpreg_only_in_incoming_stream and check whether there is a matching ToleranceOnlySrcTestValue tolerance. Signed-off-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260420140552.104369-4-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/machine.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -XXX,XX +XXX,XX @@ static void handle_cpreg_missing_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx * no cpreg mig tolerance is matched for this @kvmidx * Return true if the migration should eventually fail */ -static bool handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx) +static bool +handle_cpreg_only_in_incoming_stream(ARMCPU *cpu, uint64_t kvmidx, uint64_t value) { g_autofree gchar *name = print_register_name(kvmidx); if (arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, - 0, 0, ToleranceNotOnBothEnds)) { + 0, 0, ToleranceNotOnBothEnds) || + arm_cpu_match_cpreg_mig_tolerance(cpu, kvmidx, + value, 0, ToleranceOnlySrcTestValue)) { trace_tolerate_cpreg_only_in_incoming_stream(name); return false; } @@ -XXX,XX +XXX,XX @@ static int cpu_post_load(void *opaque, int version_id) } if (cpu->cpreg_vmstate_indexes[v] < cpu->cpreg_indexes[i]) { fail = handle_cpreg_only_in_incoming_stream(cpu, - cpu->cpreg_vmstate_indexes[v++]); + cpu->cpreg_vmstate_indexes[v], + cpu->cpreg_vmstate_values[v]); + v++; continue; } /* matching register, copy the value over */ @@ -XXX,XX +XXX,XX @@ static int cpu_post_load(void *opaque, int version_id) */ for ( ; v < cpu->cpreg_vmstate_array_len; v++) { fail = handle_cpreg_only_in_incoming_stream(cpu, - cpu->cpreg_vmstate_indexes[v]); + cpu->cpreg_vmstate_indexes[v], + cpu->cpreg_vmstate_values[v]); } if (fail) { return -1; -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> Before linux v6.13 those registers were erroneously unconditionally exposed and this was fixed by commits: - 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace when disabled for guests") - a68cddbe47ef ("KVM: arm64: Hide S1PIE registers from userspace when disabled for guests") in v6.13. This means if we migrate from an old kernel host to a >= 6.13 kernel host, migration currently fails. Declare cpreg migration tolerance for those registers. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-5-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu64.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -XXX,XX +XXX,XX @@ static void aarch64_a53_initfn(Object *obj) define_cortex_a72_a57_a53_cp_reginfo(cpu); } +#if defined(CONFIG_KVM) +static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu) +{ + /* + * Registers that may be in the incoming stream and not exposed + * on the destination + */ + + /* + * TCR_EL1 was erroneously unconditionnally exposed before linux v6.13. + * See commit 0fcb4eea5345 ("KVM: arm64: Hide TCR2_EL1 from userspace + * when disabled for guests") + */ + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 2, 0, 3), + 0, 0, ToleranceNotOnBothEnds); + /* + * PIRE0_EL1 and PIR_EL1 were erroneously unconditionnally exposed + * before linux v6.13. See commit a68cddbe47ef ("KVM: arm64: Hide + * S1PIE registers from userspace when disabled for guests") + */ + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 2), + 0, 0, ToleranceNotOnBothEnds); + arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3), + 0, 0, ToleranceNotOnBothEnds); +} +#endif + static void aarch64_host_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -XXX,XX +XXX,XX @@ static void aarch64_host_initfn(Object *obj) #endif #if defined(CONFIG_KVM) + kvm_arm_set_cpreg_mig_tolerances(cpu); kvm_arm_set_cpu_features_from_host(cpu); aarch64_add_sve_properties(obj); #elif defined(CONFIG_HVF) -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed from v6.15 onwards. Backward migration from a >= v6.15 to an older kernel would fail without cpreg migration tolerance definition for this register. If the register is present on source but not on destination, its value must be checked to make sure it matches the reset value, ie. 0, meaning no service is exposed to the guest, hence the choice of a ToleranceOnlySrcTestValue migration tolerance. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-6-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu64.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -XXX,XX +XXX,XX @@ static void kvm_arm_set_cpreg_mig_tolerances(ARMCPU *cpu) 0, 0, ToleranceNotOnBothEnds); arm_register_cpreg_mig_tolerance(cpu, ARM64_SYS_REG(3, 0, 10, 2, 3), 0, 0, ToleranceNotOnBothEnds); + + /* + * KVM_REG_ARM_VENDOR_HYP_BMAP_2 pseudo FW register is exposed + * from v6.15 onwards. Backward migration from a >= v6.15 to an older + * kernel would fail without cpreg migration tolerance definition. + * If the register is present on source but not on destination, make + * sure it has its reset value, ie. 0, meaning no service is exposed + * to the guest. + */ + arm_register_cpreg_mig_tolerance(cpu, KVM_REG_ARM_FW_FEAT_BMAP_REG(3), + UINT64_MAX, 0, ToleranceOnlySrcTestValue); } #endif -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> We want to remove AArch32 DBGDTRTX which was erroneously exposed. This was attempted by 655659a74a36b ("target/arm: Correct encoding of Debug Communications Channel registers") but it was discovered that the removal of this debug register broke forward migration on TCG. Now we have the cpreg migration tolerance infrastructure, we can declare one for the DBGDTRTX. This allow to revert the reinstate patch. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-7-eric.auger@redhat.com [PMM: revised comment, included note about when we can drop the workaround] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) 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 @@ void register_cp_regs_for_features(ARMCPU *cpu) .fgt = FGT_CLIDR_EL1, .resetvalue = GET_IDREG(isar, CLIDR) }; + uint64_t dbgtr_el0_kvmidx = + cpreg_to_kvm_id(ENCODE_CP_REG(14, 0, 1, 0, 5, 3, 0)); + define_one_arm_cp_reg(cpu, &clidr); define_arm_cp_regs(cpu, v7_cp_reginfo); define_debug_regs(cpu); + /* + * We used to incorrectly expose a non-existent AArch32 "DBGDTRTX" + * register with this encoding. This has been fixed by commit + * 655659a74a36 ("target/arm: Correct encoding of Debug + * Communications Channel registers") by the introduction of correct + * separate cpreg definitions for AA64 and AA32 versions. However, + * the old cpreg definition couldn't be removed without breaking + * migration, so commit 4f2b82f604 reinstated the bogus encoding + * for migration data only. + * + * Now that we have migration tolerance infrastructure, we can use + * this to allow forward migration from the buggy QEMU versions, + * accepting and ignoring the bogus register if it is in the + * source data. QEMU 11.0 was the last version that sent the + * bogus encoding, so this workaround can be removed at the point + * where we no longer care about migration from that version + * (i.e. when we remove the "virt-11.0" machine type). + */ + arm_register_cpreg_mig_tolerance(cpu, dbgtr_el0_kvmidx, + 0, 0, ToleranceNotOnBothEnds); } else { define_arm_cp_regs(cpu, not_v7_cp_reginfo); } -- 2.43.0
From: Eric Auger <eric.auger@redhat.com> This reverts commit 4f2b82f60431 ("target/arm: Reinstate bogus AArch32 DBGDTRTX register for migration compat). We don't need that commit anymore as the AArch32 DBGDTRTX register is declared to be safe to ignore in the incoming migration stream. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Sebastian Ott <sebott@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260420140552.104369-8-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/debug_helper.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -XXX,XX +XXX,XX @@ static void dbgclaimclr_write(CPUARMState *env, const ARMCPRegInfo *ri, env->cp15.dbgclaim &= ~(value & 0xFF); } -static CPAccessResult access_bogus(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - /* Always UNDEF, as if this cpreg didn't exist */ - return CP_ACCESS_UNDEFINED; -} - static const ARMCPRegInfo debug_cp_reginfo[] = { /* * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 4, .opc2 = 0, .access = PL0_RW, .accessfn = access_tdcc, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* - * This is not a real AArch32 register. We used to incorrectly expose - * this due to a QEMU bug; to avoid breaking migration compatibility we - * need to continue to provide it so that we don't fail the inbound - * migration when it tells us about a sysreg that we don't have. - * We set an always-fails .accessfn, which means that the guest doesn't - * actually see this register (it will always UNDEF, identically to if - * there were no cpreg definition for it other than that we won't print - * a LOG_UNIMP message about it), and we set the ARM_CP_NO_GDB flag so the - * gdbstub won't see it either. - * (We can't just set .access = 0, because add_cpreg_to_hashtable() - * helpfully ignores cpregs which aren't accessible to the highest - * implemented EL.) - * - * TODO: implement a system for being able to describe "this register - * can be ignored if it appears in the inbound stream"; then we can - * remove this temporary hack. - */ - { .name = "BOGUS_DBGDTR_EL0", .state = ARM_CP_STATE_AA32, - .cp = 14, .opc1 = 3, .crn = 0, .crm = 5, .opc2 = 0, - .access = PL0_RW, .accessfn = access_bogus, - .type = ARM_CP_CONST | ARM_CP_NO_GDB, .resetvalue = 0 }, /* * OSECCR_EL1 provides a mechanism for an operating system * to access the contents of EDECCR. EDECCR is not implemented though, -- 2.43.0
From: Osama Abdelkader <osama.abdelkader@gmail.com> fdt_node_offset_by_compatible(fdt, -1, compat) only finds the first match. If the blob has more than one node with the same compatible string, extra nodes will remain active. Remove all the matching nodes, using the same loop as imx8mp-evk.c does for this purpose. Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com> Message-id: 20260420162114.308519-1-osama.abdelkader@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/raspi4b.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -XXX,XX +XXX,XX @@ static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt) for (int i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) { const char *dev_str = nodes_to_remove[i]; + int offset; - int offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); - if (offset >= 0) { - if (!fdt_nop_node(fdt, offset)) { - warn_report("bcm2711 dtc: %s has been disabled!", dev_str); + offset = fdt_node_offset_by_compatible(fdt, -1, dev_str); + while (offset >= 0) { + if (fdt_nop_node(fdt, offset) == 0) { + warn_report("bcm2711 dtb: %s has been disabled!", dev_str); } + offset = fdt_node_offset_by_compatible(fdt, offset, dev_str); } } -- 2.43.0
From: Yucai Liu <1486344514@qq.com> Implement a basic i.MX6UL LCDIF controller model with MMIO registers, frame-done interrupt behavior, and framebuffer-backed display updates for RGB565 and XRGB8888 input formats. Place the LCDIF device under hw/display and build it via a dedicated CONFIG_IMX6UL_LCDIF symbol. Model register fields with registerfields.h helpers and provide migration support via vmstate. Signed-off-by: Yucai Liu <1486344514@qq.com> Message-id: 20260412110240.93116-2-yangyanglan718@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- MAINTAINERS | 2 + hw/display/Kconfig | 4 + hw/display/imx6ul_lcdif.c | 453 ++++++++++++++++++++++++++++++ hw/display/meson.build | 1 + include/hw/display/imx6ul_lcdif.h | 37 +++ 5 files changed, 497 insertions(+) create mode 100644 hw/display/imx6ul_lcdif.c create mode 100644 include/hw/display/imx6ul_lcdif.h diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org S: Odd Fixes F: hw/arm/mcimx6ul-evk.c F: hw/arm/fsl-imx6ul.c +F: hw/display/imx6ul_lcdif.c F: hw/misc/imx6ul_ccm.c F: include/hw/arm/fsl-imx6ul.h +F: include/hw/display/imx6ul_lcdif.h F: include/hw/misc/imx6ul_ccm.h F: docs/system/arm/mcimx6ul-evk.rst diff --git a/hw/display/Kconfig b/hw/display/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -XXX,XX +XXX,XX @@ config PL110 bool select FRAMEBUFFER +config IMX6UL_LCDIF + bool + select FRAMEBUFFER + config SII9022 bool depends on I2C diff --git a/hw/display/imx6ul_lcdif.c b/hw/display/imx6ul_lcdif.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/display/imx6ul_lcdif.c @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * i.MX6UL LCDIF controller + * + * Copyright (c) 2026 Yucai Liu <1486344514@qq.com> + */ + +#include "qemu/osdep.h" +#include "hw/display/imx6ul_lcdif.h" +#include "hw/core/irq.h" +#include "hw/core/registerfields.h" +#include "hw/display/framebuffer.h" +#include "migration/vmstate.h" +#include "system/address-spaces.h" +#include "qemu/module.h" +#include "qemu/units.h" +#include "ui/pixel_ops.h" + +#define LCDIF_MMIO_SIZE (16 * KiB) +#define LCDIF_RESET_CTRL1 0x000f0000 + +REG32(CTRL, 0x00) + FIELD(CTRL, RUN, 0, 1) + FIELD(CTRL, WORD_LENGTH, 8, 2) +REG32(CTRL1, 0x10) + FIELD(CTRL1, CUR_FRAME_DONE_IRQ, 9, 1) + FIELD(CTRL1, CUR_FRAME_DONE_IRQ_EN, 13, 1) + FIELD(CTRL1, BYTE_PACKING_FORMAT, 16, 4) +REG32(V4_TRANSFER_COUNT, 0x30) + FIELD(V4_TRANSFER_COUNT, H_COUNT, 0, 16) + FIELD(V4_TRANSFER_COUNT, V_COUNT, 16, 16) +REG32(V4_CUR_BUF, 0x40) +REG32(V4_NEXT_BUF, 0x50) +REG32(AS_NEXT_BUF, 0x230) + +#define REG_SET 0x4 +#define REG_CLR 0x8 +#define REG_TOG 0xc + +#define CTRL_WORD_LENGTH_16 0 +#define CTRL_WORD_LENGTH_24 3 + +#define FRAME_PERIOD_NS (16 * 1000 * 1000ULL) + +enum IMX6ULLCDIFReg { + IMX6UL_LCDIF_REG_CTRL = A_CTRL >> 4, + IMX6UL_LCDIF_REG_CTRL1 = A_CTRL1 >> 4, + IMX6UL_LCDIF_REG_V4_TRANSFER_COUNT = A_V4_TRANSFER_COUNT >> 4, + IMX6UL_LCDIF_REG_V4_CUR_BUF = A_V4_CUR_BUF >> 4, + IMX6UL_LCDIF_REG_V4_NEXT_BUF = A_V4_NEXT_BUF >> 4, + IMX6UL_LCDIF_REG_AS_NEXT_BUF = A_AS_NEXT_BUF >> 4, +}; + +static inline bool imx6ul_lcdif_reg_exists(hwaddr reg) +{ + return (reg >> 4) < IMX6UL_LCDIF_REGS_NUM; +} + +static inline bool imx6ul_lcdif_reg_has_setclr(hwaddr reg) +{ + switch (reg) { + case A_CTRL: + case A_CTRL1: + return true; + default: + return false; + } +} + +static inline bool imx6ul_lcdif_is_running(IMX6ULLCDIFState *s) +{ + uint32_t ctrl = s->regs[IMX6UL_LCDIF_REG_CTRL]; + + return FIELD_EX32(ctrl, CTRL, RUN); +} + +static inline bool imx6ul_lcdif_frame_done_pending(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + + return FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ); +} + +static void imx6ul_lcdif_schedule_frame(IMX6ULLCDIFState *s) +{ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + + timer_mod(s->frame_timer, now + FRAME_PERIOD_NS); +} + +static void imx6ul_lcdif_maybe_schedule_frame(IMX6ULLCDIFState *s) +{ + if (imx6ul_lcdif_is_running(s) && !imx6ul_lcdif_frame_done_pending(s)) { + imx6ul_lcdif_schedule_frame(s); + } else { + timer_del(s->frame_timer); + } +} + +static void imx6ul_lcdif_update_irq(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + bool level = FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ_EN) && + FIELD_EX32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ); + + qemu_set_irq(s->irq, level); +} + +static void imx6ul_lcdif_frame_done(IMX6ULLCDIFState *s) +{ + uint32_t ctrl1 = s->regs[IMX6UL_LCDIF_REG_CTRL1]; + + ctrl1 = FIELD_DP32(ctrl1, CTRL1, CUR_FRAME_DONE_IRQ, 1); + s->regs[IMX6UL_LCDIF_REG_CTRL1] = ctrl1; + imx6ul_lcdif_update_irq(s); +} + +static void imx6ul_lcdif_draw_line_rgb565(void *opaque, uint8_t *dst, + const uint8_t *src, int width, + int dststep) +{ + uint32_t *dst32 = (uint32_t *)dst; + int i; + + for (i = 0; i < width; i++) { + uint16_t pixel = lduw_le_p(src); + uint8_t r = ((pixel >> 11) & 0x1f) << 3; + uint8_t g = ((pixel >> 5) & 0x3f) << 2; + uint8_t b = (pixel & 0x1f) << 3; + + *dst32++ = rgb_to_pixel32(r, g, b); + src += 2; + } +} + +static void imx6ul_lcdif_draw_line_xrgb8888(void *opaque, uint8_t *dst, + const uint8_t *src, int width, + int dststep) +{ + uint32_t *dst32 = (uint32_t *)dst; + int i; + + for (i = 0; i < width; i++) { + uint32_t pixel = ldl_le_p(src); + uint8_t r = (pixel >> 16) & 0xff; + uint8_t g = (pixel >> 8) & 0xff; + uint8_t b = pixel & 0xff; + + *dst32++ = rgb_to_pixel32(r, g, b); + src += 4; + } +} + +static void imx6ul_lcdif_update_display(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); + uint32_t transfer_count = s->regs[IMX6UL_LCDIF_REG_V4_TRANSFER_COUNT]; + uint32_t width = FIELD_EX32(transfer_count, V4_TRANSFER_COUNT, H_COUNT); + uint32_t height = FIELD_EX32(transfer_count, V4_TRANSFER_COUNT, V_COUNT); + uint32_t ctrl = s->regs[IMX6UL_LCDIF_REG_CTRL]; + uint32_t frame_base = s->regs[IMX6UL_LCDIF_REG_V4_CUR_BUF]; + drawfn fn; + int first = 0; + int last = 0; + int src_width; + + if (!imx6ul_lcdif_is_running(s) || width == 0 || height == 0) { + return; + } + + switch (FIELD_EX32(ctrl, CTRL, WORD_LENGTH)) { + case CTRL_WORD_LENGTH_16: + s->src_bpp = 2; + fn = imx6ul_lcdif_draw_line_rgb565; + break; + case CTRL_WORD_LENGTH_24: + s->src_bpp = 4; + fn = imx6ul_lcdif_draw_line_xrgb8888; + break; + default: + return; + } + + if (surface_width(surface) != width || surface_height(surface) != height) { + qemu_console_resize(s->con, width, height); + surface = qemu_console_surface(s->con); + s->invalidate = true; + } + + src_width = width * s->src_bpp; + if (s->invalidate || s->fb_base != frame_base || + s->src_width != src_width || s->rows != height) { + framebuffer_update_memory_section(&s->fbsection, get_system_memory(), + frame_base, height, src_width); + s->fb_base = frame_base; + s->src_width = src_width; + s->rows = height; + } + + framebuffer_update_display(surface, &s->fbsection, width, height, + src_width, surface_stride(surface), 0, + s->invalidate, fn, s, &first, &last); + if (first >= 0) { + dpy_gfx_update(s->con, 0, first, width, last - first + 1); + } + + s->invalidate = false; +} + +static void imx6ul_lcdif_invalidate_display(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + + s->invalidate = true; +} + +static const GraphicHwOps imx6ul_lcdif_graphic_ops = { + .invalidate = imx6ul_lcdif_invalidate_display, + .gfx_update = imx6ul_lcdif_update_display, +}; + +static void imx6ul_lcdif_frame_timer_cb(void *opaque) +{ + IMX6ULLCDIFState *s = opaque; + + if (!imx6ul_lcdif_is_running(s) || imx6ul_lcdif_frame_done_pending(s)) { + return; + } + + imx6ul_lcdif_frame_done(s); +} + +static uint64_t imx6ul_lcdif_read(void *opaque, hwaddr offset, unsigned size) +{ + IMX6ULLCDIFState *s = opaque; + hwaddr reg = offset & ~0xf; + uint32_t idx; + + assert(size == 4); + assert(!(offset & 0x3)); + assert(offset < LCDIF_MMIO_SIZE); + + idx = reg >> 4; + if (idx >= ARRAY_SIZE(s->regs)) { + return 0; + } + + return s->regs[idx]; +} + +static void imx6ul_lcdif_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + IMX6ULLCDIFState *s = opaque; + hwaddr reg = offset & ~0xf; + uint32_t idx; + uint32_t oldv; + + assert(size == 4); + assert(!(offset & 0x3)); + assert(offset < LCDIF_MMIO_SIZE); + + if (!imx6ul_lcdif_reg_exists(reg)) { + return; + } + + idx = reg >> 4; + oldv = s->regs[idx]; + + switch (offset & 0xf) { + case 0: + s->regs[idx] = (uint32_t)value; + break; + case REG_SET: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv | (uint32_t)value; + break; + case REG_CLR: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv & ~(uint32_t)value; + break; + case REG_TOG: + if (!imx6ul_lcdif_reg_has_setclr(reg)) { + return; + } + s->regs[idx] = oldv ^ (uint32_t)value; + break; + default: + g_assert_not_reached(); + } + + switch (reg) { + case A_CTRL: + if (!FIELD_EX32(oldv, CTRL, RUN) && + FIELD_EX32(s->regs[idx], CTRL, RUN)) { + s->invalidate = true; + graphic_hw_invalidate(s->con); + imx6ul_lcdif_maybe_schedule_frame(s); + break; + } + if (FIELD_EX32(oldv, CTRL, RUN) && + !FIELD_EX32(s->regs[idx], CTRL, RUN)) { + timer_del(s->frame_timer); + } + break; + case A_CTRL1: + if (FIELD_EX32(oldv, CTRL1, CUR_FRAME_DONE_IRQ) && + !FIELD_EX32(s->regs[idx], CTRL1, CUR_FRAME_DONE_IRQ)) { + imx6ul_lcdif_maybe_schedule_frame(s); + } + break; + case A_V4_TRANSFER_COUNT: + s->invalidate = true; + graphic_hw_invalidate(s->con); + break; + case A_V4_CUR_BUF: + s->invalidate = true; + graphic_hw_invalidate(s->con); + break; + case A_V4_NEXT_BUF: + s->regs[IMX6UL_LCDIF_REG_V4_CUR_BUF] = s->regs[idx]; + imx6ul_lcdif_frame_done(s); + s->invalidate = true; + graphic_hw_invalidate(s->con); + imx6ul_lcdif_maybe_schedule_frame(s); + return; + case A_AS_NEXT_BUF: + imx6ul_lcdif_frame_done(s); + imx6ul_lcdif_maybe_schedule_frame(s); + return; + default: + break; + } + + imx6ul_lcdif_update_irq(s); +} + +static const MemoryRegionOps imx6ul_lcdif_ops = { + .read = imx6ul_lcdif_read, + .write = imx6ul_lcdif_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx6ul_lcdif_reset(DeviceState *dev) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + memset(s->regs, 0, sizeof(s->regs)); + s->regs[IMX6UL_LCDIF_REG_CTRL1] = LCDIF_RESET_CTRL1; + s->fb_base = 0; + s->src_width = 0; + s->rows = 0; + s->src_bpp = 0; + s->invalidate = true; + timer_del(s->frame_timer); + imx6ul_lcdif_update_irq(s); +} + +static int imx6ul_lcdif_post_load(void *opaque, int version_id) +{ + IMX6ULLCDIFState *s = opaque; + + s->fb_base = 0; + s->src_width = 0; + s->rows = 0; + s->src_bpp = 0; + s->invalidate = true; + + imx6ul_lcdif_update_irq(s); + if (imx6ul_lcdif_is_running(s) && + !imx6ul_lcdif_frame_done_pending(s) && + !timer_pending(s->frame_timer)) { + imx6ul_lcdif_schedule_frame(s); + } + + return 0; +} + +static const VMStateDescription vmstate_imx6ul_lcdif = { + .name = TYPE_IMX6UL_LCDIF, + .version_id = 1, + .minimum_version_id = 1, + .post_load = imx6ul_lcdif_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IMX6ULLCDIFState, IMX6UL_LCDIF_REGS_NUM), + VMSTATE_TIMER_PTR(frame_timer, IMX6ULLCDIFState), + VMSTATE_END_OF_LIST() + }, +}; + +static void imx6ul_lcdif_realize(DeviceState *dev, Error **errp) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + imx6ul_lcdif_frame_timer_cb, s); + s->invalidate = true; + memory_region_init_io(&s->iomem, OBJECT(dev), &imx6ul_lcdif_ops, s, + TYPE_IMX6UL_LCDIF, LCDIF_MMIO_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + s->con = graphic_console_init(dev, 0, &imx6ul_lcdif_graphic_ops, s); +} + +static void imx6ul_lcdif_unrealize(DeviceState *dev) +{ + IMX6ULLCDIFState *s = IMX6UL_LCDIF(dev); + + timer_del(s->frame_timer); + timer_free(s->frame_timer); + s->frame_timer = NULL; + + if (s->con) { + graphic_console_close(s->con); + s->con = NULL; + } +} + +static void imx6ul_lcdif_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = imx6ul_lcdif_realize; + dc->unrealize = imx6ul_lcdif_unrealize; + dc->vmsd = &vmstate_imx6ul_lcdif; + device_class_set_legacy_reset(dc, imx6ul_lcdif_reset); + dc->desc = "i.MX6UL LCDIF"; +} + +static const TypeInfo imx6ul_lcdif_info = { + .name = TYPE_IMX6UL_LCDIF, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX6ULLCDIFState), + .class_init = imx6ul_lcdif_class_init, +}; + +static void imx6ul_lcdif_register_types(void) +{ + type_register_static(&imx6ul_lcdif_info); +} + +type_init(imx6ul_lcdif_register_types) diff --git a/hw/display/meson.build b/hw/display/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -XXX,XX +XXX,XX @@ system_ss.add(when: ['CONFIG_VGA_CIRRUS', 'CONFIG_VGA_ISA'], if_true: files('cir system_ss.add(when: 'CONFIG_G364FB', if_true: files('g364fb.c')) system_ss.add(when: 'CONFIG_JAZZ_LED', if_true: files('jazz_led.c')) system_ss.add(when: 'CONFIG_PL110', if_true: files('pl110.c')) +system_ss.add(when: 'CONFIG_IMX6UL_LCDIF', if_true: files('imx6ul_lcdif.c')) system_ss.add(when: 'CONFIG_SII9022', if_true: files('sii9022.c')) system_ss.add(when: 'CONFIG_SSD0303', if_true: files('ssd0303.c')) system_ss.add(when: 'CONFIG_SSD0323', if_true: files('ssd0323.c')) diff --git a/include/hw/display/imx6ul_lcdif.h b/include/hw/display/imx6ul_lcdif.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/display/imx6ul_lcdif.h @@ -XXX,XX +XXX,XX @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * i.MX6UL LCDIF controller + * + * Copyright (c) 2026 Yucai Liu <1486344514@qq.com> + */ + +#ifndef IMX6UL_LCDIF_H +#define IMX6UL_LCDIF_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" +#include "qemu/timer.h" +#include "ui/console.h" + +#define TYPE_IMX6UL_LCDIF "imx6ul-lcdif" +#define IMX6UL_LCDIF_REGS_NUM ((0x230 >> 4) + 1) +OBJECT_DECLARE_SIMPLE_TYPE(IMX6ULLCDIFState, IMX6UL_LCDIF) + +struct IMX6ULLCDIFState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegionSection fbsection; + qemu_irq irq; + QemuConsole *con; + QEMUTimer *frame_timer; + uint32_t fb_base; + uint32_t src_width; + uint32_t rows; + uint8_t src_bpp; + bool invalidate; + uint32_t regs[IMX6UL_LCDIF_REGS_NUM]; +}; + +#endif /* IMX6UL_LCDIF_H */ -- 2.43.0
From: Yucai Liu <1486344514@qq.com> Instantiate LCDIF as a child object of the i.MX6UL SoC in init and realize it in the SoC realize path before MMIO/IRQ hookup. Also make FSL_IMX6UL select CONFIG_IMX6UL_LCDIF and map the LCDIF region with a 16 KiB size to match the SoC memory map. Signed-off-by: Yucai Liu <1486344514@qq.com> Message-id: 20260412110240.93116-3-yangyanglan718@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/Kconfig | 1 + hw/arm/fsl-imx6ul.c | 12 ++++++++++-- include/hw/arm/fsl-imx6ul.h | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config FSL_IMX6UL imply I2C_DEVICES select A15MPCORE select IMX + select IMX6UL_LCDIF select IMX_FEC select IMX_I2C select IMX_USBPHY diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -XXX,XX +XXX,XX @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/arm/fsl-imx6ul.h" +#include "hw/display/imx6ul_lcdif.h" #include "hw/misc/unimp.h" #include "hw/usb/imx-usb-phy.h" #include "hw/core/boards.h" @@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_init(Object *obj) object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } + /* + * LCDIF + */ + object_initialize_child(obj, "lcdif", &s->lcdif, TYPE_IMX6UL_LCDIF); + /* * SDHCIs */ @@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * LCD */ - create_unimplemented_device("lcdif", FSL_IMX6UL_LCDIF_ADDR, - FSL_IMX6UL_LCDIF_SIZE); + sysbus_realize(SYS_BUS_DEVICE(&s->lcdif), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->lcdif), 0, FSL_IMX6UL_LCDIF_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->lcdif), 0, + qdev_get_gpio_in(gic, FSL_IMX6UL_LCDIF_IRQ)); /* * CSU diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -XXX,XX +XXX,XX @@ #include "hw/net/imx_fec.h" #include "hw/usb/chipidea.h" #include "hw/usb/imx-usb-phy.h" +#include "hw/display/imx6ul_lcdif.h" #include "system/memory.h" #include "target/arm/cpu.h" #include "qom/object.h" @@ -XXX,XX +XXX,XX @@ struct FslIMX6ULState { IMX2WdtState wdt[FSL_IMX6UL_NUM_WDTS]; IMXUSBPHYState usbphy[FSL_IMX6UL_NUM_USB_PHYS]; ChipideaState usb[FSL_IMX6UL_NUM_USBS]; + IMX6ULLCDIFState lcdif; MemoryRegion rom; MemoryRegion caam; MemoryRegion ocram; @@ -XXX,XX +XXX,XX @@ enum FslIMX6ULMemoryMap { FSL_IMX6UL_PXP_SIZE = (16 * KiB), FSL_IMX6UL_LCDIF_ADDR = 0x021C8000, - FSL_IMX6UL_LCDIF_SIZE = 0x100, + FSL_IMX6UL_LCDIF_SIZE = (16 * KiB), FSL_IMX6UL_CSI_ADDR = 0x021C4000, FSL_IMX6UL_CSI_SIZE = 0x100, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> We have a registerfields interface which we can use for defining fields alongside helpers to access them. Define the basic syndrome layout and convert the helpers that take the imm16 data directly. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-2-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 75 ++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 18 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 @@ #ifndef TARGET_ARM_SYNDROME_H #define TARGET_ARM_SYNDROME_H -#include "qemu/bitops.h" +#include "hw/core/registerfields.h" /* Valid Syndrome Register EC field values */ enum arm_exception_class { @@ -XXX,XX +XXX,XX @@ enum arm_exception_class { EC_AA64_BKPT = 0x3c, }; +/* Generic syndrome encoding layout for HSR and lower 32 bits of ESR_EL2 */ +FIELD(SYNDROME, EC, 26, 6) +FIELD(SYNDROME, IL, 25, 1) +FIELD(SYNDROME, ISS, 0, 25) + typedef enum { SME_ET_AccessTrap, SME_ET_Streaming, @@ -XXX,XX +XXX,XX @@ typedef enum { static inline uint32_t syn_get_ec(uint32_t syn) { - return syn >> ARM_EL_EC_SHIFT; + return FIELD_EX32(syn, SYNDROME, EC); } static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec) { - return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec); + return FIELD_DP32(syn, SYNDROME, EC, ec); } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec) */ static inline uint32_t syn_uncategorized(void) { - return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_UNCATEGORIZED); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } +FIELD(ISS_IMM16, IMM16, 0, 16) + static inline uint32_t syn_aa64_svc(uint32_t imm16) { - return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_SVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_hvc(uint32_t imm16) { - return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_HVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_smc(uint32_t imm16) { - return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_SMC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit) { - return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_16bit ? 0 : ARM_EL_IL); + uint32_t res = syn_set_ec(0, EC_AA32_SVC); + res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_hvc(uint32_t imm16) { - return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA32_HVC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_smc(void) { - return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_AA32_SMC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_aa64_bkpt(uint32_t imm16) { - return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); + uint32_t res = syn_set_ec(0, EC_AA64_BKPT); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit) { - return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_16bit ? 0 : ARM_EL_IL); + uint32_t res = syn_set_ec(0, EC_AA32_BKPT); + res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); + return res; } static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit) static inline uint32_t syn_sve_access_trap(void) { - return (EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_SVEACCESSTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) static inline uint32_t syn_illegalstate(void) { - return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_ILLEGALSTATE); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_pcalignment(void) { - return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_PCALIGNMENT); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn) @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_gcs_gcsstr(int ra, int rn) static inline uint32_t syn_serror(uint32_t extra) { - return (EC_SERROR << ARM_EL_EC_SHIFT) | ARM_EL_IL | extra; + uint32_t res = syn_set_ec(0, EC_SERROR); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, SYNDROME, ISS, extra); + return res; } static inline uint32_t syn_mop(bool is_set, bool is_setg, int options, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_aa64_sysregtrap and co-processor register trap syndromes to the registerfields API. The co-processor syndromes are split between single and duel register moves. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-3-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 124 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 22 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 @@ enum arm_exception_class { /* Generic syndrome encoding layout for HSR and lower 32 bits of ESR_EL2 */ FIELD(SYNDROME, EC, 26, 6) -FIELD(SYNDROME, IL, 25, 1) +FIELD(SYNDROME, IL, 25, 1) /* IL=1 for 32 bit instructions */ FIELD(SYNDROME, ISS, 0, 25) typedef enum { @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_aa64_smc(uint32_t imm16) static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_AA32_SVC); - res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); return res; } @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_aa64_bkpt(uint32_t imm16) static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_AA32_BKPT); - res = FIELD_DP32(res, SYNDROME, IL, is_16bit ? 0 : 1); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); res = FIELD_DP32(res, ISS_IMM16, IMM16, imm16); return res; } +/* + * ISS encoding for an exception from MSR, MRS, or System instruction + * in AArch64 state. + */ +FIELD(SYSREG_ISS, ISREAD, 0, 1) /* Direction, 1 is read */ +FIELD(SYSREG_ISS, CRM, 1, 4) +FIELD(SYSREG_ISS, RT, 5, 5) +FIELD(SYSREG_ISS, CRN, 10, 4) +FIELD(SYSREG_ISS, OP1, 14, 3) +FIELD(SYSREG_ISS, OP2, 17, 3) +FIELD(SYSREG_ISS, OP0, 20, 2) + static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, int crn, int crm, int rt, int isread) { - return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL - | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5) - | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_SYSTEMREGISTERTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, SYSREG_ISS, OP0, op0); + res = FIELD_DP32(res, SYSREG_ISS, OP2, op2); + res = FIELD_DP32(res, SYSREG_ISS, OP1, op1); + res = FIELD_DP32(res, SYSREG_ISS, CRN, crn); + res = FIELD_DP32(res, SYSREG_ISS, RT, rt); + res = FIELD_DP32(res, SYSREG_ISS, CRM, crm); + res = FIELD_DP32(res, SYSREG_ISS, ISREAD, isread); + + return res; } +/* + * ISS encoding for an exception from an MCR or MRC access + * (move to/from co-processor) + */ +FIELD(COPROC_ISS, ISREAD, 0, 1) +FIELD(COPROC_ISS, CRM, 1, 4) +FIELD(COPROC_ISS, RT, 5, 5) +FIELD(COPROC_ISS, CRN, 10, 4) +FIELD(COPROC_ISS, OP1, 14, 3) +FIELD(COPROC_ISS, OP2, 17, 3) +FIELD(COPROC_ISS, COND, 20, 4) +FIELD(COPROC_ISS, CV, 24, 1) + static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) { - return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) - | (crn << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP14RTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP2, opc2); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) { - return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) - | (crn << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP15RTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP2, opc2); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; } +/* + * ISS encoding for an exception from an MCRR or MRRC access + * (move to/from co-processor with 2 regs) + */ +FIELD(COPROC_R2_ISS, ISREAD, 0, 1) +FIELD(COPROC_R2_ISS, CRM, 1, 4) +FIELD(COPROC_R2_ISS, RT, 5, 5) +FIELD(COPROC_R2_ISS, RT2, 10, 5) +FIELD(COPROC_R2_ISS, OP1, 16, 4) +FIELD(COPROC_R2_ISS, COND, 20, 4) +FIELD(COPROC_R2_ISS, CV, 24, 1) + static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, bool is_16bit) { - return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc1 << 16) - | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP14RRTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2); + res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, bool is_16bit) { - return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (opc1 << 16) - | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; + uint32_t res = syn_set_ec(0, EC_CP15RRTTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, COPROC_R2_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_R2_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_R2_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_R2_ISS, RT2, rt2); + res = FIELD_DP32(res, COPROC_R2_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_R2_ISS, CRM, crm); + res = FIELD_DP32(res, COPROC_R2_ISS, ISREAD, isread); + + return res; } static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> The syn_simd_access trap was never used so remove it. We should only see the COPROC encoding on v7 architectures. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-4-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 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, return res; } +/* + * ISS encoding for an exception from an access to a register of + * instruction resulting from the FPEN or TFP traps. + */ +FIELD(FP_ISS, COPROC, 0, 4) /* ARMv7 only */ +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) { /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 */ - return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | coproc; -} + uint32_t res = syn_set_ec(0, EC_ADVSIMDFPACCESSTRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); -static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit) -{ - /* AArch32 SIMD trap: TA == 1 coproc == 0 */ - return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | (cv << 24) | (cond << 20) | (1 << 5); + res = FIELD_DP32(res, FP_ISS, CV, cv); + res = FIELD_DP32(res, FP_ISS, COND, cond); + res = FIELD_DP32(res, FP_ISS, COPROC, coproc); + + return res; } static inline uint32_t syn_sve_access_trap(void) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> For simplicity keep the OP as a two bit field rather than the two interlinked fields in the docs (ERET/ERETA). Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-5-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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_sve_access_trap(void) } /* + * ISS encoding for an exception from an ERET, ERETAA or ERETAB + * instructions. + * * eret_op is bits [1:0] of the ERET instruction, so: * 0 for ERET, 2 for ERETAA, 3 for ERETAB. */ +FIELD(ERET_ISS, OP, 0, 2) + static inline uint32_t syn_erettrap(int eret_op) { - return (EC_ERETTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | eret_op; + uint32_t res = syn_set_ec(0, EC_ERETTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, ERET_ISS, OP, eret_op); + + return res; } static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-6-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 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_erettrap(int eret_op) return res; } +/* + * ISS encoding for an exception due to SME functionality + */ +FIELD(SME_ISS, SMTC, 0, 2) + static inline uint32_t syn_smetrap(SMEExceptionType etype, bool is_16bit) { - return (EC_SMETRAP << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) | etype; + uint32_t res = syn_set_ec(0, EC_SMETRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + res = FIELD_DP32(res, SME_ISS, SMTC, etype); + + return res; } static inline uint32_t syn_pacfail(bool data, int keynumber) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> syn_pactrap is fairly simple as the ISS is all RES0. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-7-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 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_smetrap(SMEExceptionType etype, bool is_16bit) return res; } +/* + * ISS encoding for a PAC Fail exceptions + */ +FIELD(PACFAIL_ISS, BnA, 0, 1) /* B key or A key */ +FIELD(PACFAIL_ISS, DnI, 1, 1) /* Data or Instruction */ + static inline uint32_t syn_pacfail(bool data, int keynumber) { - int error_code = (data << 1) | keynumber; - return (EC_PACFAIL << ARM_EL_EC_SHIFT) | ARM_EL_IL | error_code; + uint32_t res = syn_set_ec(0, EC_PACFAIL); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, PACFAIL_ISS, DnI, data); + res = FIELD_DP32(res, PACFAIL_ISS, BnA, keynumber); + + return res; } +/* + * ISS encoding for an exception from a trapped Pointer + * Authentication instruction is RES0 + */ static inline uint32_t syn_pactrap(void) { - return (EC_PACTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL; + uint32_t res = syn_set_ec(0, EC_PACTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + return res; } static inline uint32_t syn_btitrap(int btype) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-8-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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_pactrap(void) return res; } +/* + * ISS encoding for an exception from a Branch Target Identification + * instruction. + */ +FIELD(BTI_ISS, BTYPE, 0, 2) + static inline uint32_t syn_btitrap(int btype) { - return (EC_BTITRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | btype; + uint32_t res = syn_set_ec(0, EC_BTITRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, BTI_ISS, BTYPE, btype); + return res; } static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This is an Armv7 specific syndrome for chips with Jazelle functionality. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-9-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 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_btitrap(int btype) return res; } +/* + * ISS encoding for trapped BXJ execution + * + * This is an Armv7 encoding. + */ +FIELD(BXJ_ISS, RM, 0, 4) +/* bits 4:19 are Reserved, UNK/SBZP */ +FIELD(BXJ_ISS, COND, 20, 4) +FIELD(BXJ_ISS, CV, 24, 1) + static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) { - return (EC_BXJTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (cv << 24) | (cond << 20) | rm; + uint32_t res = syn_set_ec(0, EC_BXJTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, BXJ_ISS, CV, cv); + res = FIELD_DP32(res, BXJ_ISS, COND, cond); + res = FIELD_DP32(res, BXJ_ISS, RM, rm); + + return res; } static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-10-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 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_bxjtrap(int cv, int cond, int rm) return res; } +/* + * ISS encoding for a Granule Protection Check exception + * + * These are only reported to EL3 + */ +FIELD(GPC_ISS, xFSC, 0, 6) +FIELD(GPC_ISS, WnR, 6, 1) /* Write not Read */ +FIELD(GPC_ISS, S1PTW, 7, 1) +FIELD(GPC_ISS, CM, 8, 1) +FIELD(GPC_ISS, VNCR, 13, 1) +FIELD(GPC_ISS, GPCSC, 14, 6) +FIELD(GPC_ISS, InD, 20, 1) /* Instruction not Data access */ +FIELD(GPC_ISS, S2PTW, 21, 1) + static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, int vncr, int cm, int s1ptw, int wnr, int fsc) { - return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21) - | (ind << 20) | (gpcsc << 14) | (vncr << 13) | (cm << 8) - | (s1ptw << 7) | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_GPC); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GPC_ISS, S2PTW, s2ptw); + res = FIELD_DP32(res, GPC_ISS, InD, ind); + res = FIELD_DP32(res, GPC_ISS, GPCSC, gpcsc); + res = FIELD_DP32(res, GPC_ISS, VNCR, vncr); + res = FIELD_DP32(res, GPC_ISS, CM, cm); + res = FIELD_DP32(res, GPC_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, GPC_ISS, WnR, wnr); + res = FIELD_DP32(res, GPC_ISS, xFSC, fsc); + + return res; } static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_insn_abort and syn_data_abort_* to the registerfields API. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260422125250.1303100-11-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 87 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 13 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_gpc(int s2ptw, int ind, int gpcsc, int vncr, return res; } +/* + * ISS encoding for an exception from an Instruction Abort + * + * (aka instruction abort) + */ +FIELD(IABORT_ISS, IFSC, 0, 6) +FIELD(IABORT_ISS, S1PTW, 7, 1) +FIELD(IABORT_ISS, EA, 9, 1) +FIELD(IABORT_ISS, FnV, 10, 1) /* FAR not Valid */ +FIELD(IABORT_ISS, SET, 11, 2) +FIELD(IABORT_ISS, PFV, 14, 1) +FIELD(IABORT_ISS, TopLevel, 21, 1) /* FEAT_THE */ + static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) { - return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc; + uint32_t res = syn_set_ec(0, EC_INSNABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, IABORT_ISS, EA, ea); + res = FIELD_DP32(res, IABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, IABORT_ISS, IFSC, fsc); + + return res; } +/* + * ISS encoding for an exception from a Data Abort + */ +FIELD(DABORT_ISS, DFSC, 0, 6) +FIELD(DABORT_ISS, WNR, 6, 1) +FIELD(DABORT_ISS, S1PTW, 7, 1) +FIELD(DABORT_ISS, CM, 8, 1) +FIELD(DABORT_ISS, EA, 9, 1) +FIELD(DABORT_ISS, FnV, 10, 1) +FIELD(DABORT_ISS, LST, 11, 2) +FIELD(DABORT_ISS, VNCR, 13, 1) +FIELD(DABORT_ISS, AR, 14, 1) +FIELD(DABORT_ISS, SF, 15, 1) +FIELD(DABORT_ISS, SRT, 16, 5) +FIELD(DABORT_ISS, SSE, 21, 1) +FIELD(DABORT_ISS, SAS, 22, 2) +FIELD(DABORT_ISS, ISV, 24, 1) + static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv, int ea, int cm, int s1ptw, int wnr, int fsc) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL - | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7) - | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, DABORT_ISS, FnV, fnv); + res = FIELD_DP32(res, DABORT_ISS, EA, ea); + res = FIELD_DP32(res, DABORT_ISS, CM, cm); + res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } static inline uint32_t syn_data_abort_with_iss(int same_el, @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_with_iss(int same_el, int wnr, int fsc, bool is_16bit) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | (is_16bit ? 0 : ARM_EL_IL) - | ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16) - | (sf << 15) | (ar << 14) - | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, DABORT_ISS, ISV, 1); + res = FIELD_DP32(res, DABORT_ISS, SAS, sas); + res = FIELD_DP32(res, DABORT_ISS, SSE, sse); + res = FIELD_DP32(res, DABORT_ISS, SRT, srt); + res = FIELD_DP32(res, DABORT_ISS, SF, sf); + res = FIELD_DP32(res, DABORT_ISS, AR, ar); + res = FIELD_DP32(res, DABORT_ISS, EA, ea); + res = FIELD_DP32(res, DABORT_ISS, CM, cm); + res = FIELD_DP32(res, DABORT_ISS, S1PTW, s1ptw); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } /* @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_data_abort_with_iss(int same_el, */ static inline uint32_t syn_data_abort_vncr(int ea, int wnr, int fsc) { - return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (1 << ARM_EL_EC_SHIFT) - | ARM_EL_IL | ARM_EL_VNCR | (wnr << 6) | fsc; + uint32_t res = syn_set_ec(0, EC_DATAABORT_SAME_EL); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, DABORT_ISS, VNCR, 1); + res = FIELD_DP32(res, DABORT_ISS, WNR, wnr); + res = FIELD_DP32(res, DABORT_ISS, DFSC, fsc); + + return res; } static inline uint32_t syn_swstep(int same_el, int isv, int ex) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Migrate syn_swstep, syn_watchpoint and syn_breakpoint to the registerfields API. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-12-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 54 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 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_data_abort_vncr(int ea, int wnr, int fsc) return res; } +/* + * ISS encoding for an exception from a Software Step exception. + */ +FIELD(SOFTSTEP_ISS, IFSC, 0, 6) +FIELD(SOFTSTEP_ISS, EX, 6, 1) +FIELD(SOFTSTEP_ISS, ISV, 24, 1) + static inline uint32_t syn_swstep(int same_el, int isv, int ex) { - return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22; + uint32_t res = syn_set_ec(0, EC_SOFTWARESTEP + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, SOFTSTEP_ISS, ISV, isv); + res = FIELD_DP32(res, SOFTSTEP_ISS, EX, ex); + res = FIELD_DP32(res, SOFTSTEP_ISS, IFSC, 0x22); + + return res; } +/* + * ISS encoding for an exception from a Watchpoint exception + */ +FIELD(WATCHPOINT_ISS, DFSC, 0, 6) +FIELD(WATCHPOINT_ISS, WNR, 6, 1) +FIELD(WATCHPOINT_ISS, CM, 8, 1) +FIELD(WATCHPOINT_ISS, FnV, 10, 1) +FIELD(WATCHPOINT_ISS, VNCR, 13, 1) /* FEAT_NV2 */ +FIELD(WATCHPOINT_ISS, FnP, 15, 1) +FIELD(WATCHPOINT_ISS, WPF, 16, 1) +/* bellow mandatory from FEAT_Debugv8p9 */ +FIELD(WATCHPOINT_ISS, WPTV, 17, 1) /* FEAT_Debugv8p2 - WPT valid */ +FIELD(WATCHPOINT_ISS, WPT, 18, 6) /* FEAT_Debugv8p2 - missing WP number */ + static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr) { - return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22; + uint32_t res = syn_set_ec(0, EC_WATCHPOINT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, WATCHPOINT_ISS, CM, cm); + res = FIELD_DP32(res, WATCHPOINT_ISS, WNR, wnr); + res = FIELD_DP32(res, WATCHPOINT_ISS, DFSC, 0x22); + + return res; } +/* + * ISS encoding for an exception from a Breakpoint or a Vector Catch + * debug exception. + */ +FIELD(BREAKPOINT_ISS, IFSC, 0, 6) + static inline uint32_t syn_breakpoint(int same_el) { - return (EC_BREAKPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | ARM_EL_IL | 0x22; + uint32_t res = syn_set_ec(0, EC_BREAKPOINT + same_el); + res = FIELD_DP32(res, SYNDROME, IL, 1); + res = FIELD_DP32(res, BREAKPOINT_ISS, IFSC, 0x22); + + return res; } static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This will help later when we expand the fields we report. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-13-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 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_breakpoint(int same_el) return res; } +/* + * ISS encoding for an exception from a WF* instruction + */ +FIELD(WFX_ISS, TI, 0, 2) +FIELD(WFX_ISS, RV, 2, 1) +FIELD(WFX_ISS, RN, 5, 5) +FIELD(WFX_ISS, COND, 20, 4) +FIELD(WFX_ISS, CV, 24, 1) + static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) { - return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) | - (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) | - (cv << 24) | (cond << 20) | ti; + uint32_t res = syn_set_ec(0, EC_WFX_TRAP); + res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); + + res = FIELD_DP32(res, WFX_ISS, CV, cv); + res = FIELD_DP32(res, WFX_ISS, COND, cond); + res = FIELD_DP32(res, WFX_ISS, TI, ti); + + return res; } static inline uint32_t syn_illegalstate(void) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Tweak arg names to make it clear raddr is the data address register number. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-14-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 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_pcalignment(void) return res; } +/* + * ISS encoding for a GCS exception + * + * Field validity depends on EXTYPE + */ +FIELD(GCS_ISS, IT, 0, 5) +FIELD(GCS_ISS, RN, 5, 5) /* only for non EXLOCK exceptions */ +FIELD(GCS_ISS, RADDR, 10, 5) /* only for GCSSTR/GCSSTTR traps */ +FIELD(GCS_ISS, EXTYPE, 20, 4) + static inline uint32_t syn_gcs_data_check(GCSInstructionType it, int rn) { - return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (GCS_ET_DataCheck << 20) | (rn << 5) | it); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_DataCheck); + res = FIELD_DP32(res, GCS_ISS, RN, rn); + res = FIELD_DP32(res, GCS_ISS, IT, it); + + return res; } static inline uint32_t syn_gcs_exlock(void) { - return (EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | (GCS_ET_EXLOCK << 20); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_EXLOCK); + + return res; } -static inline uint32_t syn_gcs_gcsstr(int ra, int rn) +static inline uint32_t syn_gcs_gcsstr(int raddr, int rn) { - return ((EC_GCS << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (GCS_ET_GCSSTR_GCSSTTR << 20) | (ra << 10) | (rn << 5)); + uint32_t res = syn_set_ec(0, EC_GCS); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, GCS_ISS, EXTYPE, GCS_ET_GCSSTR_GCSSTTR); + res = FIELD_DP32(res, GCS_ISS, RADDR, raddr); + res = FIELD_DP32(res, GCS_ISS, RN, rn); + + return res; } static inline uint32_t syn_serror(uint32_t extra) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-15-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 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_serror(uint32_t extra) return res; } +/* + * ISS encoding for an exception from the Memory Copy and Memory Set + * instructions. + */ +FIELD(MOP_ISS, SIZEREG, 0, 5) +FIELD(MOP_ISS, SRCREG, 5, 5) +FIELD(MOP_ISS, DESTREG, 10, 5) +FIELD(MOP_ISS, FORMATOPT, 16, 2) +FIELD(MOP_ISS, OPT_A, 16, 1) +FIELD(MOP_ISS, WRONG_OPT, 17, 1) +FIELD(MOP_ISS, EPILOGUE, 18, 1) +FIELD(MOP_ISS, OPTIONS, 19, 4) +FIELD(MOP_ISS, IS_SETG, 23, 1) +FIELD(MOP_ISS, MEMINST, 24, 1) + static inline uint32_t syn_mop(bool is_set, bool is_setg, int options, bool epilogue, bool wrong_option, bool option_a, int destreg, int srcreg, int sizereg) { - return (EC_MOP << ARM_EL_EC_SHIFT) | ARM_EL_IL | - (is_set << 24) | (is_setg << 23) | (options << 19) | - (epilogue << 18) | (wrong_option << 17) | (option_a << 16) | - (destreg << 10) | (srcreg << 5) | sizereg; + uint32_t res = syn_set_ec(0, EC_MOP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, MOP_ISS, MEMINST, is_set); + res = FIELD_DP32(res, MOP_ISS, IS_SETG, is_setg); + res = FIELD_DP32(res, MOP_ISS, OPTIONS, options); + res = FIELD_DP32(res, MOP_ISS, EPILOGUE, epilogue); + res = FIELD_DP32(res, MOP_ISS, WRONG_OPT, wrong_option); + res = FIELD_DP32(res, MOP_ISS, OPT_A, option_a); + res = FIELD_DP32(res, MOP_ISS, DESTREG, destreg); + res = FIELD_DP32(res, MOP_ISS, SRCREG, srcreg); + res = FIELD_DP32(res, MOP_ISS, SIZEREG, sizereg); + + return res; } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> It shares the same COPROC_ISS encoding as the other CP traps although not all the fields are used. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-16-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 16 ++++++++++++++++ target/arm/tcg/vfp_helper.c | 5 +---- 2 files changed, 17 insertions(+), 4 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 @@ FIELD(COPROC_ISS, OP2, 17, 3) FIELD(COPROC_ISS, COND, 20, 4) FIELD(COPROC_ISS, CV, 24, 1) +static inline uint32_t syn_cp10_rt_trap(int cv, int cond, int opc1, + int crn, int rt, int isread) +{ + uint32_t res = syn_set_ec(0, EC_FPIDTRAP); + res = FIELD_DP32(res, SYNDROME, IL, 1); + + res = FIELD_DP32(res, COPROC_ISS, CV, cv); + res = FIELD_DP32(res, COPROC_ISS, COND, cond); + res = FIELD_DP32(res, COPROC_ISS, OP1, opc1); + res = FIELD_DP32(res, COPROC_ISS, CRN, crn); + res = FIELD_DP32(res, COPROC_ISS, RT, rt); + res = FIELD_DP32(res, COPROC_ISS, ISREAD, isread); + + return res; +} + static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, bool is_16bit) diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg) g_assert_not_reached(); } - syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT) - | ARM_EL_IL - | (1 << 24) | (0xe << 20) | (7 << 14) - | (reg << 10) | (rt << 5) | 1); + syndrome = syn_cp10_rt_trap(1, 0xe, 7, reg, rt, 1); raise_exception(env, EXCP_HYP_TRAP, syndrome, 2); } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> One more step towards dropping the old #defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-17-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs) */ if (cs->exception_index == EXCP_PREFETCH_ABORT || (cs->exception_index == EXCP_DATA_ABORT && - !(env->exception.syndrome & ARM_EL_ISV)) || + !FIELD_EX32(env->exception.syndrome, SYNDROME, IL)) || syn_get_ec(env->exception.syndrome) == EC_UNCATEGORIZED) { - env->exception.syndrome &= ~ARM_EL_IL; + env->exception.syndrome = FIELD_DP32(env->exception.syndrome, SYNDROME, IL, 0); } } env->cp15.esr_el[2] = env->exception.syndrome; -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This removes the last use of ARM_EL_EC_SHIFT. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-18-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 1 - target/arm/tcg/debug.c | 2 +- 2 files changed, 1 insertion(+), 2 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 @@ typedef enum { } GCSInstructionType; #define ARM_EL_EC_LENGTH 6 -#define ARM_EL_EC_SHIFT 26 #define ARM_EL_IL_SHIFT 25 #define ARM_EL_ISV_SHIFT 24 #define ARM_EL_IL (1 << ARM_EL_IL_SHIFT) diff --git a/target/arm/tcg/debug.c b/target/arm/tcg/debug.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/debug.c +++ b/target/arm/tcg/debug.c @@ -XXX,XX +XXX,XX @@ raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome) * Similarly for watchpoint and breakpoint matches. */ assert(debug_el >= cur_el); - syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT; + syndrome |= (debug_el == cur_el) << R_SYNDROME_EC_SHIFT; raise_exception(env, excp, syndrome, debug_el); } -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Rather than open coding a bunch of shifts and masks we can use the syndrome definitions. While we are at it assert it really is a EC_DATAABORT. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-19-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/whpx/whpx-all.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/whpx/whpx-all.c +++ b/target/arm/whpx/whpx-all.c @@ -XXX,XX +XXX,XX @@ static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) { uint64_t syndrome = ctx->Syndrome; - bool isv = syndrome & ARM_EL_ISV; - bool iswrite = (syndrome >> 6) & 1; - bool sse = (syndrome >> 21) & 1; - uint32_t sas = (syndrome >> 22) & 3; + bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV); + bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR); + bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE); + uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS); uint32_t len = 1 << sas; - uint32_t srt = (syndrome >> 16) & 0x1f; - uint32_t cm = (syndrome >> 8) & 0x1; + uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT); + uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM); uint64_t val = 0; + assert(syn_get_ec(syndrome) == EC_DATAABORT); assert(!cm); assert(isv); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Rather than open coding a bunch of shifts and masks we can use the syndrome definitions. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260422125250.1303100-20-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/hvf/hvf.c | 14 +++++++------- 1 file changed, 7 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 @@ static int hvf_handle_exception(CPUState *cpu, hv_vcpu_exit_exception_t *excp) break; } case EC_DATAABORT: { - bool isv = syndrome & ARM_EL_ISV; - bool iswrite = (syndrome >> 6) & 1; - bool s1ptw = (syndrome >> 7) & 1; - bool sse = (syndrome >> 21) & 1; - uint32_t sas = (syndrome >> 22) & 3; + bool isv = FIELD_EX32(syndrome, DABORT_ISS, ISV); + bool iswrite = FIELD_EX32(syndrome, DABORT_ISS, WNR); + bool s1ptw = FIELD_EX32(syndrome, DABORT_ISS, S1PTW); + bool sse = FIELD_EX32(syndrome, DABORT_ISS, SSE); + uint32_t sas = FIELD_EX32(syndrome, DABORT_ISS, SAS); uint32_t len = 1 << sas; - uint32_t srt = (syndrome >> 16) & 0x1f; - uint32_t cm = (syndrome >> 8) & 0x1; + uint32_t srt = FIELD_EX32(syndrome, DABORT_ISS, SRT); + uint32_t cm = FIELD_EX32(syndrome, DABORT_ISS, CM); uint64_t val = 0; uint64_t ipa = excp->physical_address; AddressSpace *as = cpu_get_address_space(cpu, ARMASIdx_NS); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> One more step to removing the old defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-21-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/tlb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -XXX,XX +XXX,XX @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn, */ assert(!fi->stage2); syn = syn_data_abort_vncr(fi->ea, is_write, fsc); - } else if (!(template_syn & ARM_EL_ISV) || target_el != 2 + } else if (!FIELD_EX32(template_syn, DABORT_ISS, ISV) || target_el != 2 || fi->s1ptw || !fi->stage2) { syn = syn_data_abort_no_iss(same_el, 0, fi->ea, 0, fi->s1ptw, is_write, fsc); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> These are only valid for data abort syndromes. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-22-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/tlb_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -XXX,XX +XXX,XX @@ static inline uint64_t merge_syn_data_abort(uint32_t template_syn, * ST64BV, or ST64BV0 insns report syndrome info even for stage-1 * faults and regardless of the target EL. */ - if (template_syn & ARM_EL_VNCR) { + if (FIELD_EX32(template_syn, DABORT_ISS, VNCR)) { /* * FEAT_NV2 faults on accesses via VNCR_EL2 are a special case: * they are always reported as "same EL", even though we are going @@ -XXX,XX +XXX,XX @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, * because we masked that out in disas_set_insn_syndrome()) */ bool is_vncr = (access_type != MMU_INST_FETCH) && - (env->exception.syndrome & ARM_EL_VNCR); + FIELD_EX32(env->exception.syndrome, DABORT_ISS, VNCR); if (is_vncr) { /* FEAT_NV2 faults on accesses via VNCR_EL2 go to EL2 */ -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Now everything is defined with registerfields we can drop the old defines. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-23-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 9 --------- 1 file changed, 9 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 @@ typedef enum { GCS_IT_GCSPOPX = 9, } GCSInstructionType; -#define ARM_EL_EC_LENGTH 6 -#define ARM_EL_IL_SHIFT 25 -#define ARM_EL_ISV_SHIFT 24 -#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT) -#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT) - -/* In the Data Abort syndrome */ -#define ARM_EL_VNCR (1 << 13) - static inline uint32_t syn_get_ec(uint32_t syn) { return FIELD_EX32(syn, SYNDROME, EC); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> Pass the register number (rd) to the wfit helper and report it in the syndrome ISS. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260422125250.1303100-24-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 11 ++++++++++- target/arm/tcg/helper-defs.h | 2 +- target/arm/tcg/op_helper.c | 7 ++++--- target/arm/tcg/translate-a64.c | 2 +- 4 files changed, 16 insertions(+), 6 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 @@ FIELD(WFX_ISS, RN, 5, 5) FIELD(WFX_ISS, COND, 20, 4) FIELD(WFX_ISS, CV, 24, 1) -static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) +typedef enum { + WFI = 0b00, + WFE = 0b01, + WFIT = 0b10, + WFET = 0xb11 +} wfx_ti; + +static inline uint32_t syn_wfx(int cv, int cond, int rn, bool rv, wfx_ti ti, bool is_16bit) { uint32_t res = syn_set_ec(0, EC_WFX_TRAP); res = FIELD_DP32(res, SYNDROME, IL, !is_16bit); @@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit) res = FIELD_DP32(res, WFX_ISS, CV, cv); res = FIELD_DP32(res, WFX_ISS, COND, cond); res = FIELD_DP32(res, WFX_ISS, TI, ti); + res = FIELD_DP32(res, WFX_ISS, RN, rn); + res = FIELD_DP32(res, WFX_ISS, RV, rv); return res; } 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_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(wfit, void, env, i64) +DEF_HELPER_2(wfit, 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(wfi)(CPUARMState *env, uint32_t insn_len) env->regs[15] -= insn_len; } - raise_exception(env, excp, syn_wfx(1, 0xe, 0, insn_len == 2), + raise_exception(env, excp, syn_wfx(1, 0xe, 0, false, WFI, insn_len == 2), target_el); } @@ -XXX,XX +XXX,XX @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) #endif } -void HELPER(wfit)(CPUARMState *env, uint64_t timeout) +void HELPER(wfit)(CPUARMState *env, uint32_t rd) { #ifdef CONFIG_USER_ONLY /* @@ -XXX,XX +XXX,XX @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout) int target_el = check_wfx_trap(env, false, &excp); /* The WFIT should time out when CNTVCT_EL0 >= the specified value. */ uint64_t cntval = gt_get_countervalue(env); + uint64_t timeout = env->xregs[rd]; /* * We want the value that we would get if we read CNTVCT_EL0 from * the current exception level, so the direct_access offset, not @@ -XXX,XX +XXX,XX @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout) if (target_el) { env->pc -= 4; - raise_exception(env, excp, syn_wfx(1, 0xe, 2, false), target_el); + raise_exception(env, excp, syn_wfx(1, 0xe, rd, true, WFIT, false), target_el); } if (uadd64_overflow(timeout, offset, &nexttick)) { 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_WFIT(DisasContext *s, arg_WFIT *a) } gen_a64_update_pc(s, 4); - gen_helper_wfit(tcg_env, cpu_reg(s, a->rd)); + gen_helper_wfit(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