From 9e3df3019d21c54df435406fca31b3e145b29702 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 28 Jul 2026 21:20:37 +0200 Subject: [PATCH 001/627] linux-user: Fix msqid_ds struct wrt 32-bit big endian architectures Make sure that the time entries (msg_stime, msg_rtime and msg_ctime) are defined as 64-bit time_t values, since the userspace may access the whole 64-bit value. By this change we fix the word ordering for 32-bit big endian architectures as well. This fixes the msgctl01 LTP testcase on hppa32. Cc: qemu-stable@nongnu.org Signed-off-by: Helge Deller --- linux-user/syscall.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 740142825d..c93b770ced 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4216,21 +4216,15 @@ static inline abi_long do_semtimedop(int semid, } #endif +#define target_time64_t abi_ullong +#define target_swap_time64(x) tswap64(x) + struct target_msqid_ds { struct target_ipc_perm msg_perm; - abi_ulong msg_stime; -#if TARGET_ABI_BITS == 32 - abi_ulong __unused1; -#endif - abi_ulong msg_rtime; -#if TARGET_ABI_BITS == 32 - abi_ulong __unused2; -#endif - abi_ulong msg_ctime; -#if TARGET_ABI_BITS == 32 - abi_ulong __unused3; -#endif + target_time64_t msg_stime; + target_time64_t msg_rtime; + target_time64_t msg_ctime; abi_ulong __msg_cbytes; abi_ulong msg_qnum; abi_ulong msg_qbytes; @@ -4249,9 +4243,9 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, return -TARGET_EFAULT; if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr)) return -TARGET_EFAULT; - host_md->msg_stime = tswapal(target_md->msg_stime); - host_md->msg_rtime = tswapal(target_md->msg_rtime); - host_md->msg_ctime = tswapal(target_md->msg_ctime); + host_md->msg_stime = target_swap_time64(target_md->msg_stime); + host_md->msg_rtime = target_swap_time64(target_md->msg_rtime); + host_md->msg_ctime = target_swap_time64(target_md->msg_ctime); host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes); host_md->msg_qnum = tswapal(target_md->msg_qnum); host_md->msg_qbytes = tswapal(target_md->msg_qbytes); @@ -4270,9 +4264,9 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, return -TARGET_EFAULT; if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm))) return -TARGET_EFAULT; - target_md->msg_stime = tswapal(host_md->msg_stime); - target_md->msg_rtime = tswapal(host_md->msg_rtime); - target_md->msg_ctime = tswapal(host_md->msg_ctime); + target_md->msg_stime = target_swap_time64(host_md->msg_stime); + target_md->msg_rtime = target_swap_time64(host_md->msg_rtime); + target_md->msg_ctime = target_swap_time64(host_md->msg_ctime); target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes); target_md->msg_qnum = tswapal(host_md->msg_qnum); target_md->msg_qbytes = tswapal(host_md->msg_qbytes); From 518a4aa01b88ff814dbf8668016f3ec910426283 Mon Sep 17 00:00:00 2001 From: no92 Date: Fri, 24 Jul 2026 18:01:04 +0200 Subject: [PATCH 002/627] linux-user: fix incorrect msg_l[sr]pid members of target_msqid_ds The members are declared as __kernel_pid_t in Linux UAPI headers. Analogous members in struct target_shmid_ds (shm_[cl]pid) are also declared as abi_int. Cc: qemu-stable@nongnu.org Fixes: 1c54ff97bbde ("linux-user: fix and cleanup IPCOP_msg* ipc calls handling") Signed-off-by: no92 Reviewed-by: Pierrick Bouvier Signed-off-by: Helge Deller --- linux-user/syscall.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c93b770ced..547784d971 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4228,8 +4228,8 @@ struct target_msqid_ds abi_ulong __msg_cbytes; abi_ulong msg_qnum; abi_ulong msg_qbytes; - abi_ulong msg_lspid; - abi_ulong msg_lrpid; + abi_int msg_lspid; + abi_int msg_lrpid; abi_ulong __unused4; abi_ulong __unused5; }; @@ -4249,8 +4249,8 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md, host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes); host_md->msg_qnum = tswapal(target_md->msg_qnum); host_md->msg_qbytes = tswapal(target_md->msg_qbytes); - host_md->msg_lspid = tswapal(target_md->msg_lspid); - host_md->msg_lrpid = tswapal(target_md->msg_lrpid); + host_md->msg_lspid = tswap32(target_md->msg_lspid); + host_md->msg_lrpid = tswap32(target_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 0); return 0; } @@ -4270,8 +4270,8 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr, target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes); target_md->msg_qnum = tswapal(host_md->msg_qnum); target_md->msg_qbytes = tswapal(host_md->msg_qbytes); - target_md->msg_lspid = tswapal(host_md->msg_lspid); - target_md->msg_lrpid = tswapal(host_md->msg_lrpid); + target_md->msg_lspid = tswap32(host_md->msg_lspid); + target_md->msg_lrpid = tswap32(host_md->msg_lrpid); unlock_user_struct(target_md, target_addr, 1); return 0; } From 8d0ac5933aa3476283c14680f165727268103fcd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 29 Jul 2026 12:17:10 -0700 Subject: [PATCH 003/627] linux-user/aarch64: Fix SHADOW_STACK_SET_TOKEN The token is not computed via TARGET_PAGE_SIZE, but via a fixed 12-bit field. Cc: qemu-stable@nongnu.org Fixes: ad1afe433fa ("linux-user/aarch64: Implement map_shadow_stack syscall") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4106 Signed-off-by: Richard Henderson Reviewed-by: Pierrick Bouvier Signed-off-by: Helge Deller --- linux-user/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 547784d971..dc028686f4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6900,7 +6900,8 @@ static abi_long do_map_shadow_stack(CPUArchState *env, abi_ulong addr, /* Leave an extra empty frame at top-of-stack. */ cap_ptr -= 8; } - cap_val = (cap_ptr & TARGET_PAGE_MASK) | 1; + /* Note the 12 bit field is unaffected by current page size. */ + cap_val = deposit64(cap_ptr, 0, 12, 1); if (put_user_u64(cap_val, cap_ptr)) { /* Allocation succeeded above. */ g_assert_not_reached(); From 702252a0dbc3ad9a51e4092a986b2f98e8c6adcb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Jul 2026 11:24:27 +0100 Subject: [PATCH 004/627] target/arm: Fix b16b16 feature test for SME2 BFCLAMP, BFMAX, BFMIN These are controlled by FEAT_SVE_B16B16 not FEAT_SME_B16B16. Cc: qemu-stable@nongnu.org Fixes: bc65d2bd1cb ("target/arm: Implement SME2 Multiple and Single SVE Destructive") Fixes: 930760eb753 ("target/arm: Implement SME2 Multiple Vectors SVE Destructive") Fixes: 8b61eff8e72 ("target/arm: Implement SME2 FCLAMP, SCLAMP, UCLAMP") Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/tcg/translate-sme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index dcc4690fba..0794794e3d 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -756,7 +756,7 @@ static bool do_z2z_n1_fpst(DisasContext *s, arg_z2z_en *a, return false; } /* These insns use MO_8 to encode BFloat16. */ - if (esz == MO_8 && !dc_isar_feature(aa64_sme_b16b16, s)) { + if (esz == MO_8 && !dc_isar_feature(aa64_sve_b16b16, s)) { return false; } if (!sme_sm_enabled_check(s)) { @@ -793,7 +793,7 @@ static bool do_z2z_nn_fpst(DisasContext *s, arg_z2z_en *a, if (fn == NULL) { return false; } - if (esz == MO_8 && !dc_isar_feature(aa64_sme_b16b16, s)) { + if (esz == MO_8 && !dc_isar_feature(aa64_sve_b16b16, s)) { return false; } if (!sme_sm_enabled_check(s)) { @@ -1850,7 +1850,7 @@ static bool trans_FCLAMP(DisasContext *s, arg_zzz_en *a) return false; } /* This insn uses MO_8 to encode BFloat16. */ - if (a->esz == MO_8 && !dc_isar_feature(aa64_sme_b16b16, s)) { + if (a->esz == MO_8 && !dc_isar_feature(aa64_sve_b16b16, s)) { return false; } if (!sme_sm_enabled_check(s)) { From dd0d695306de823c1a782fecdf9744f618afbacb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 31 Jul 2026 11:24:27 +0100 Subject: [PATCH 005/627] target/arm: Don't NOP the SEV insn on v6K CPUs When we implememented SEV to do something on A-profile rather than being a nop, we got the condition slightly wrong, and made it only effective from v7. In fact the instruction's Arm encoding has non-NOP behaviour from ARMv6K. The effect is that a kernel boot may hang on a v6K CPU like the ARM11MPCore. (This wouldn't have been so noticeable if we feature checked the WFE instruction, and had made the same mistake for the condition on both instructions. But we never have done the feature checks that we ought on WFE, so the mistake on SEV meant that we showed the 11mpcore guest a WFE that did something and a SEV that was a NOP.) The v7A Arm ARM is not entirely clear about whether v6K has the Thumb SEV encoding or not: it says "ARMv7 (executes as NOP in ARMv6T2)", leaving v6K not stated. The 11MPCore TRM says it has at least WFI in both Arm and Thumb, and the v7A Arm ARM uses the same condition text for WFI, so I make the assumption that WFI, WFE, and SEV all get their functionality for both Thumb and Arm in v6K. It's possible that this differed between v6K CPUs -- the 1176 TRM says it has the v6K STREXD/STREXH/STREXB etc, but the WFI is the old-style cp15 one. Keeping the condition check the same for both Thumb and Arm encodings is the conservative choice: if guests try to execute the Thumb SEV insn it will be because they want SEV, not because they want a NOP. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4044 Fixes: 60e7ee5bb7cd ("target/arm: implements SEV/SEVL for all modes") Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260728111629.1705308-2-peter.maydell@linaro.org --- target/arm/tcg/translate.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index a1fc050618..6e52ad082e 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -3246,12 +3246,19 @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a) static bool trans_SEV(DisasContext *s, arg_SEV *a) { /* - * SEV is a NOP for user-mode emulation. For v6T2 and earlier - * non-M-profile cores this encoding is a NOP hint. + * SEV is a NOP for user-mode emulation. The instruction is + * also a NOP hint on cores that pre-date the architectural + * feature that adds it: + * - M-profile always has SEV + * - for A/R profile, it exists from v6K onward + * The v7A Arm ARM is not entirely clear about whether v6K has the + * Thumb SEV or not; we make the condition the same, to be + * conservative. (If guests try to execute the Thumb SEV insn it + * will be because they want SEV, not because they want a NOP.) */ #ifndef CONFIG_USER_ONLY if (arm_dc_feature(s, ARM_FEATURE_M) || - arm_dc_feature(s, ARM_FEATURE_V7)) { + arm_dc_feature(s, ARM_FEATURE_V6K)) { gen_helper_sev(tcg_env); } #endif From d88781a4e8881bae032802f2b5440274ceece15a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 31 Jul 2026 11:24:27 +0100 Subject: [PATCH 006/627] target/arm: Make YIELD, WFI and WFE be NOPs on pre-v6K The YIELD, WFI and WFE instructions are in the NOP hint space, and were only defined to actual non-NOP instructions starting in the v6K architecture; they are also present for all M-profile architecture versions. We never did check the architecture version before making these instructions have their special behaviour. Mostly this has not been a problem because a guest won't execute one of these insns unless it is prepared for it to have its usual effect, and because we implemented SEV and WFE as NOPs anyway. Now we have implemented SEV and WFE to be more than just NOPs, it's important that we have the same condition on the SEV as the WFE, so that we either NOP both or else implement both. A guest probably won't try to use SEV/WFE on CPUs that don't implement them, but it is valid for it to do that and rely on them both being NOPs (and so a WFE-loop falls back to a pure busy-wait loop). Add the "only if M profile or v6K or better" check to YIELD, WFE and WFI. This means that all the insns in the NOP-hint space for A32, T32 and T16 have a correct feature check. Fixes: 60e7ee5bb7cd ("target/arm: implements SEV/SEVL for all modes") Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260728111629.1705308-3-peter.maydell@linaro.org --- target/arm/tcg/translate.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 6e52ad082e..055f3c5b40 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -3235,10 +3235,14 @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a) * the next round-robin scheduled vCPU gets a crack. When running in * MTTCG we don't generate jumps to the helper as it won't affect the * scheduling of other vCPUs. + * This is a NOP hint on older architectures. */ - if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_YIELD; + if (arm_dc_feature(s, ARM_FEATURE_M) || + arm_dc_feature(s, ARM_FEATURE_V6K)) { + if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) { + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_YIELD; + } } return true; } @@ -3280,17 +3284,30 @@ static bool trans_SEVL(DisasContext *s, arg_SEV *a) static bool trans_WFE(DisasContext *s, arg_WFE *a) { - /* For WFE, halt the vCPU until an event. */ - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_WFE; + /* + * For WFE, halt the vCPU until an event. This is a NOP + * hint on older architectures, with the same conditions + * as SEV. + */ + if (arm_dc_feature(s, ARM_FEATURE_M) || + arm_dc_feature(s, ARM_FEATURE_V6K)) { + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_WFE; + } return true; } static bool trans_WFI(DisasContext *s, arg_WFI *a) { - /* For WFI, halt the vCPU until an IRQ. */ - gen_update_pc(s, curr_insn_len(s)); - s->base.is_jmp = DISAS_WFI; + /* + * For WFI, halt the vCPU until an IRQ. This is a NOP + * hint on older architectures. + */ + if (arm_dc_feature(s, ARM_FEATURE_M) || + arm_dc_feature(s, ARM_FEATURE_V6K)) { + gen_update_pc(s, curr_insn_len(s)); + s->base.is_jmp = DISAS_WFI; + } return true; } From c490037c1349f503d7986391b24db47362a204eb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 31 Jul 2026 11:24:27 +0100 Subject: [PATCH 007/627] target/arm: Remove stale comment about WFE/SEV implementation We forgot to remove a comment about WFE/SEV only being implemented for M-profile when we added the A-profile support for this; delete the stale text. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260728111629.1705308-4-peter.maydell@linaro.org --- target/arm/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 03a30afcbe..c0492c8dfb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -766,7 +766,6 @@ typedef struct CPUArchState { /* * The event register is shared by all ARM profiles (A/R/M), * so it is stored in the top-level CPU state. - * WFE/SEV handling is currently implemented only for M-profile. */ bool event_register; From c25f69595ad052473463540f4d7944b9b73e94ec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Jun 2026 17:15:21 -0700 Subject: [PATCH 008/627] target/i386: Update cc_op for SAHF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the call to gen_compute_eflags meant we no longer updated cc_op after computing EFLAGS. Cc: qemu-stable@nongnu.org Fixes: da7649c6aeef ("target/i386/tcg: do not compute all flags for SAHF") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3537 Tested-by: Christian Quante Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/tcg/emit.c.inc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index e4ef5a8758..473f415766 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -3780,10 +3780,13 @@ static void gen_SAHF(DisasContext *s, X86DecodedInsn *decode) return gen_illegal_opcode(s); } tcg_gen_shri_tl(s->T0, cpu_regs[R_EAX], 8); - gen_neg_setcc(s, JCC_O << 1, cpu_cc_src); - tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); + gen_neg_setcc(s, JCC_O << 1, s->T1); + tcg_gen_andi_tl(s->T1, s->T1, CC_O); tcg_gen_andi_tl(s->T0, s->T0, CC_S | CC_Z | CC_A | CC_P | CC_C); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, s->T0); + tcg_gen_or_tl(s->T0, s->T0, s->T1); + + decode->cc_src = s->T0; + decode->cc_op = CC_OP_EFLAGS; } static void gen_SALC(DisasContext *s, X86DecodedInsn *decode) From f498c21b3595157d6fff8fb4f546cfecb14bd6dc Mon Sep 17 00:00:00 2001 From: "Tycho Andersen (AMD)" Date: Mon, 27 Jul 2026 09:00:38 -0600 Subject: [PATCH 009/627] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While working on savevm/loadvm for a new vfio device, I encountered the crash below. Since vfio_connect_kvm_msi_virq() didn't check the ->use flag for the vector, it would pass an unused vector down to vfio_cpr_load_vector_fd() which would crash. Fix this by checking the ->use flag along with the virq number to detect whether a vector is valid or not. Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x0000555555a891ef in vfio_cpr_load_vector_fd (vdev=vdev@entry=0x0, name=name@entry=0x555555eeb27e "kvm_interrupt", nr=nr@entry=1) at ../hw/vfio/cpr.c:44 44 g_autofree char *fdname = STRDUP_VECTOR_FD_NAME(vdev, name); (gdb) bt #0 0x0000555555a891ef in vfio_cpr_load_vector_fd (vdev=vdev@entry=0x0, name=name@entry=0x555555eeb27e "kvm_interrupt", nr=nr@entry=1) at ../hw/vfio/cpr.c:44 #1 0x0000555555ce64a1 in vfio_notifier_init (vdev=0x0, e=e@entry=0x5555586971b4, name=name@entry=0x555555eeb27e "kvm_interrupt", nr=nr@entry=1, errp=errp@entry=0x0) at ../hw/vfio/pci.c:79 #2 0x0000555555ce721e in vfio_connect_kvm_msi_virq (vector=0x5555586971a8, nr=nr@entry=1) at ../hw/vfio/pci.c:601 #3 0x0000555555cea5a5 in vfio_connect_kvm_msi_virq (nr=1, vector=) at ../hw/vfio/pci.c:597 #4 vfio_pci_commit_kvm_msi_virq_batch (vdev=0x55555906de40) at ../hw/vfio/pci.c:822 #5 0x0000555555cea9f2 in vfio_msix_enable (vdev=vdev@entry=0x55555906de40) at ../hw/vfio/pci.c:850 #6 0x0000555555ceb152 in vfio_pci_load_config (vbasedev=0x55555906e900, f=) at ../hw/vfio/pci.c:3088 #7 0x0000555555a8c765 in vfio_load_device_config_state (f=0x5555574a43d0, opaque=0x55555906e900) at ../hw/vfio/migration.c:278 #8 0x0000555555b3a522 in vmstate_load (f=f@entry=0x5555574a43d0, se=se@entry=0x5555591edd40, errp=errp@entry=0x7fffffffe130) at ../migration/savevm.c:971 #9 0x0000555555b3ab1a in qemu_loadvm_section_start_full (f=f@entry=0x5555574a43d0, type=type@entry=4 '\004', errp=errp@entry=0x7fffffffe130) at ../migration/savevm.c:2654 #10 0x0000555555b3e1ee in qemu_loadvm_state_main (f=f@entry=0x5555574a43d0, mis=mis@entry=0x5555571de5a0, errp=0x7fffffffe130, errp@entry=0x555557157c10 ) at ../migration/savevm.c:2973 #11 0x0000555555b3f7b7 in qemu_loadvm_state (f=f@entry=0x5555574a43d0, errp=errp@entry=0x555557157c10 ) at ../migration/savevm.c:3058 #12 0x0000555555b40863 in load_snapshot (name=0x7fffffffecc9 "foo", vmstate=vmstate@entry=0x0, has_devices=has_devices@entry=false, devices=devices@entry=0x0, errp=errp@entry=0x555557157c10 ) at ../migration/savevm.c:3452 #13 0x0000555555adc211 in qmp_x_exit_preconfig (errp=0x555557157c10 ) at ../system/vl.c:2817 #14 qmp_x_exit_preconfig (errp=0x555557157c10 ) at ../system/vl.c:2802 #15 0x0000555555adf8ed in qemu_init (argc=, argv=) at ../system/vl.c:3849 #16 0x00005555558903fd in main (argc=, argv=) at ../system/main.c:71 Fixes: 30edcb4d4e7a ("vfio-pci: preserve MSI") Signed-off-by: Tycho Andersen (AMD) Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260727150038.2684512-1-tycho@kernel.org Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 380dd8c15f..b5280c3d2a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -589,7 +589,7 @@ static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector, int nr) { const char *name = "kvm_interrupt"; - if (vector->virq < 0) { + if (!vector->use || vector->virq < 0) { return; } From 338d81b22b4dc6c45299da1114925a4b086d6e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 21 Jul 2026 12:50:26 +0200 Subject: [PATCH 010/627] vfio/pci: Guard accel_irqchip_begin_route_changes() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 49b2dcbd2422 ("accel/accel-irq: add generic begin_route_changes"), accel_irqchip_begin_route_changes() aborts when no accelerator irqchip is available. This causes a fatal error when running VFIO passthrough devices under TCG emulation: qemu-system-aarch64: can't initiate route change, no accel irqchip available The previous kvm_irqchip_begin_route_changes() was a simple inline that did not have a fatal path. The VFIO code already handles the absence of KVM MSI routing gracefully by falling back to userspace handling, but the new generic function aborts before that fallback can take effect. Guard the call sites in hw/vfio/pci.c with accel_msi_via_irqfd_enabled() so that route changes are only initiated when an accelerator irqchip is actually present. Fixes: 49b2dcbd2422 ("accel/accel-irq: add generic begin_route_changes") Cc: Magnus Kulke Link: https://lore.kernel.org/qemu-devel/20260721105026.3932297-1-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b5280c3d2a..428ab2f069 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -699,7 +699,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, if (msg) { if (vdev->defer_kvm_irq_routing) { vfio_pci_add_kvm_msi_virq(vdev, vector, nr, true); - } else { + } else if (accel_msi_via_irqfd_enabled()) { vfio_route_change = accel_irqchip_begin_route_changes(); vfio_pci_add_kvm_msi_virq(vdev, vector, nr, true); accel_irqchip_commit_route_changes(&vfio_route_change); @@ -801,7 +801,9 @@ void vfio_pci_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev) { assert(!vdev->defer_kvm_irq_routing); vdev->defer_kvm_irq_routing = true; - vfio_route_change = accel_irqchip_begin_route_changes(); + if (accel_msi_via_irqfd_enabled()) { + vfio_route_change = accel_irqchip_begin_route_changes(); + } } void vfio_pci_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev) From 0d3db94a886610c5923e52cc23f841ccb9cb546c Mon Sep 17 00:00:00 2001 From: malike Date: Mon, 13 Jul 2026 11:17:50 +0800 Subject: [PATCH 011/627] block/cloop: fix integer overflow in total_sectors calculation The total_sectors is computed as n_blocks * sectors_per_block where both operands are uint32_t. The multiplication is performed in 32-bit arithmetic and can overflow when the product exceeds UINT32_MAX, producing a value much smaller than the true image size. The result is assigned to int64_t total_sectors but the 32-bit multiplication has already wrapped around, and the zero-extension to 64-bit does not recover the correct value. This causes the block layer to reject valid I/O requests (DoS) when the reported total_sectors is smaller than the actual image. Use 64-bit arithmetic by casting one operand to uint64_t so the multiplication is performed in 64-bit precision. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3972 Signed-off-by: Ma Like Message-ID: <20260713031750.58448-1-malike@kylinos.cn> Signed-off-by: Kevin Wolf --- block/cloop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/cloop.c b/block/cloop.c index 443af1444e..a16f08e6ef 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -202,7 +202,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; - bs->total_sectors = s->n_blocks * s->sectors_per_block; + /* Cast to uint64_t to prevent uint32_t overflow */ + bs->total_sectors = (uint64_t)s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; From 5b0ba385a024ad92c63c175317cd9374de2e6165 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 24 Jul 2026 13:13:09 +0200 Subject: [PATCH 012/627] block/accounting: take stats->lock in latency histogram setters block_latency_histogram_set() and block_latency_histograms_clear() replace BlockLatencyHistogram's nbins/boundaries/bins without taking stats->lock, while block_account_one_io() reads those same fields under that lock from whatever iothread completes the I/O. The result is usual use-after-free and qemu crash. Take stats->lock in both setters, matching the lock already held by the reader. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz CC: Vladimir Sementsov-Ogievskiy CC: Andrey Drobyshev Message-ID: <20260724111311.4086859-2-den@openvz.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/accounting.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/block/accounting.c b/block/accounting.c index f00fe99740..6e06c7609e 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -194,6 +194,8 @@ int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type, return -EINVAL; } + qemu_mutex_lock(&stats->lock); + hist->nbins = new_nbins; g_free(hist->boundaries); hist->boundaries = g_new(uint64_t, hist->nbins - 1); @@ -206,6 +208,8 @@ int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type, g_free(hist->bins); hist->bins = g_new0(uint64_t, hist->nbins); + qemu_mutex_unlock(&stats->lock); + return 0; } @@ -213,12 +217,16 @@ void block_latency_histograms_clear(BlockAcctStats *stats) { int i; + qemu_mutex_lock(&stats->lock); + for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { BlockLatencyHistogram *hist = &stats->latency_histogram[i]; g_free(hist->bins); g_free(hist->boundaries); memset(hist, 0, sizeof(*hist)); } + + qemu_mutex_unlock(&stats->lock); } static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie, From 16f94ef4c6ce3e7ca6b02b796580e2cfc41e9789 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 24 Jul 2026 13:13:10 +0200 Subject: [PATCH 013/627] block/qapi: take stats->lock when reading BlockAcctStats for query-blockstats bdrv_query_blk_stats() reads BlockAcctStats's counters, latency histogram, and per-interval TimedAverage stats without stats->lock, while block_account_one_io() updates the same fields under that lock from an iothread. timed_average_min()/max()/avg() make this worse than a stale read: they call check_expirations(), which can reset a window's sum/count/min/max -- a write, not just a read -- so this is a genuine race with a concurrent writer, not merely a slower reader like the scalar counters. Take stats->lock for the whole call, both to close the race and to make the returned snapshot internally consistent (previously each field could reflect a different instant relative to concurrent updates). block_acct_queue_depth() used to take the lock itself on every call; since bdrv_query_blk_stats() is its only caller and now already holds the lock, that would self-deadlock. Make it require the caller to hold stats->lock instead (documented and asserted). Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz CC: Vladimir Sementsov-Ogievskiy CC: Andrey Drobyshev Message-ID: <20260724111311.4086859-3-den@openvz.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/accounting.c | 3 +-- block/qapi.c | 3 +++ include/block/accounting.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/block/accounting.c b/block/accounting.c index 6e06c7609e..038af37017 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -318,10 +318,9 @@ double block_acct_queue_depth(BlockAcctTimedStats *stats, uint64_t sum, elapsed; assert(type < BLOCK_MAX_IOTYPE); + assert(qemu_mutex_trylock(&stats->stats->lock) == -EBUSY); - qemu_mutex_lock(&stats->stats->lock); sum = timed_average_sum(&stats->latency[type], &elapsed); - qemu_mutex_unlock(&stats->stats->lock); return (double) sum / elapsed; } diff --git a/block/qapi.c b/block/qapi.c index eabfbfc258..1dfac51091 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -535,6 +535,8 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) BlockAcctTimedStats *ts = NULL; BlockLatencyHistogram *hgram; + qemu_mutex_lock(&stats->lock); + ds->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ]; ds->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE]; ds->zone_append_bytes = stats->nr_bytes[BLOCK_ACCT_ZONE_APPEND]; @@ -624,6 +626,7 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_ZONE_APPEND]); ds->flush_latency_histogram = bdrv_latency_histogram_stats(&hgram[BLOCK_ACCT_FLUSH]); + qemu_mutex_unlock(&stats->lock); } static BlockStats * GRAPH_RDLOCK diff --git a/include/block/accounting.h b/include/block/accounting.h index b1cf417b57..12d3246092 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -116,6 +116,7 @@ void block_acct_invalid(BlockAcctStats *stats, enum BlockAcctType type); void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type, int num_requests); int64_t block_acct_idle_time_ns(BlockAcctStats *stats); +/* Caller must hold stats->stats->lock. */ double block_acct_queue_depth(BlockAcctTimedStats *stats, enum BlockAcctType type); int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type, From 842c89281a20c3ea783609c5ac9da226e017e490 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 24 Jul 2026 13:13:11 +0200 Subject: [PATCH 014/627] tests/unit: add reproducer for BlockAcctStats histogram locking race block_latency_histogram_set() and block_latency_histograms_clear() replace BlockLatencyHistogram's nbins/boundaries/bins without taking stats->lock, while block_account_one_io() reads those same fields under that lock from whatever iothread completes the I/O. Add a test that races two real threads against block_latency_histogram_set() and block_acct_start()/block_acct_done() on the same BlockAcctStats. Applied here it passes, since the previous two commits already take the lock; reverting them locally reproduces the abort this series fixes, in about a second. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz CC: Vladimir Sementsov-Ogievskiy CC: Andrey Drobyshev Message-ID: <20260724111311.4086859-4-den@openvz.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/unit/meson.build | 1 + tests/unit/test-block-accounting.c | 115 +++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 tests/unit/test-block-accounting.c diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 5ba6b1a230..dc3fb954c0 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -75,6 +75,7 @@ if have_block 'test-blockjob': [testblock], 'test-blockjob-txn': [testblock], 'test-block-backend': [testblock], + 'test-block-accounting': [testblock], 'test-block-iothread': [testblock], 'test-write-threshold': [testblock], 'test-crypto-hash': [crypto], diff --git a/tests/unit/test-block-accounting.c b/tests/unit/test-block-accounting.c new file mode 100644 index 0000000000..7aae491cfc --- /dev/null +++ b/tests/unit/test-block-accounting.c @@ -0,0 +1,115 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * BlockAcctStats latency histogram locking regression test + * + * Copyright (c) 2026 Virtuozzo International GmbH. + * + * Regression test for missing stats->lock in + * block_latency_histogram_set()/block_latency_histograms_clear(), + * racing block_account_one_io() reading the same fields from an + * iothread. Aborts reliably before the fix, passes after it. + */ + +#include "qemu/osdep.h" +#include "block/block.h" +#include "block/accounting.h" +#include "system/block-backend.h" +#include "system/block-backend-io.h" +#include "qapi/error.h" +#include "qemu/main-loop.h" +#include "qemu/thread.h" + +#define RACE_DURATION_MS 2000 +#define NUM_READER_THREADS 8 + +static bool stop_workers; + +/* + * Different bin counts, so the writer's g_free()/g_new() churn can be + * caught mid-update. Values are small enough (nanoseconds) that plain + * back-to-back start/done calls exercise every bin without sleeping. + */ +static uint64List boundaries_a[] = { + { .next = &boundaries_a[1], .value = 1000 }, + { .next = &boundaries_a[2], .value = 5000 }, + { .next = NULL, .value = 50000 }, +}; + +static uint64List boundaries_b[] = { + { .next = &boundaries_b[1], .value = 800 }, + { .next = &boundaries_b[2], .value = 3000 }, + { .next = &boundaries_b[3], .value = 20000 }, + { .next = NULL, .value = 200000 }, +}; + +static void *writer_thread(void *opaque) +{ + BlockAcctStats *stats = opaque; + + while (!qatomic_read(&stop_workers)) { + block_latency_histogram_set(stats, BLOCK_ACCT_READ, boundaries_a); + block_latency_histogram_set(stats, BLOCK_ACCT_READ, boundaries_b); + block_latency_histograms_clear(stats); + } + + return NULL; +} + +static void *reader_thread(void *opaque) +{ + BlockAcctStats *stats = opaque; + + while (!qatomic_read(&stop_workers)) { + BlockAcctCookie cookie; + + block_acct_start(stats, &cookie, 4096, BLOCK_ACCT_READ); + block_acct_done(stats, &cookie); + } + + return NULL; +} + +static void test_latency_histogram_race(void) +{ + BlockBackend *blk = blk_new(qemu_get_aio_context(), + BLK_PERM_ALL, BLK_PERM_ALL); + BlockAcctStats *stats = blk_get_stats(blk); + QemuThread writer, readers[NUM_READER_THREADS]; + int i; + + /* Histogram has to be enabled (bins != NULL) before racing it. */ + g_assert(block_latency_histogram_set(stats, BLOCK_ACCT_READ, + boundaries_a) == 0); + + stop_workers = false; + qemu_thread_create(&writer, "hist-writer", writer_thread, stats, + QEMU_THREAD_JOINABLE); + for (i = 0; i < NUM_READER_THREADS; i++) { + qemu_thread_create(&readers[i], "hist-reader", reader_thread, stats, + QEMU_THREAD_JOINABLE); + } + + g_usleep(RACE_DURATION_MS * 1000); + qatomic_set(&stop_workers, true); + + qemu_thread_join(&writer); + for (i = 0; i < NUM_READER_THREADS; i++) { + qemu_thread_join(&readers[i]); + } + + blk_unref(blk); +} + +int main(int argc, char **argv) +{ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/block-accounting/latency_histogram_race", + test_latency_histogram_race); + + return g_test_run(); +} From 0c43f801c0d7a31ef05bc22914cca0b0e28210a8 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 23 Jul 2026 10:45:17 -0400 Subject: [PATCH 015/627] dmg: fix out-of-bounds load in search_chunk() (CVE-2026-65929) The binary search in search_chunk() uses s->n_chunks as the (inclusive) upper bound. Chunk indices are in the right-open interval [0, s->n_chunks) so it is wrong to search all the way up to s->n_chunks rather than s->n_chunks - 1. The worst case security scenario I can see is convincing a victim to hotplug a malicious DMG file to a running guest, potentially causing QEMU to crash when loading from memory beyond the end of s->sectors[] or s->sectorscounts[]. This could be a denial of service. Fixes: CVE-2026-65929 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3844 Reported-by: boy juju Reported-by: Tristan Madani Signed-off-by: Stefan Hajnoczi Message-ID: <20260723144519.364701-2-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/dmg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/dmg.c b/block/dmg.c index 33dcb3a349..e325127d14 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -609,7 +609,10 @@ static inline int is_sector_in_chunk(BDRVDMGState *s, static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num) { /* binary search */ - uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3; + uint32_t chunk1 = 0, chunk2 = s->n_chunks - 1, chunk3; + if (s->n_chunks == 0) { + goto err; /* should never happen */ + } while (chunk1 <= chunk2) { chunk3 = (chunk1 + chunk2) / 2; if (s->sectors[chunk3] > sector_num) { From ab7b872f0c38ee2a576b93cf37b9945f622d48fb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 23 Jul 2026 10:45:18 -0400 Subject: [PATCH 016/627] dmg: refuse to open files with no chunks The dmg block driver expects the disk image file to contain at least one chunk. Refuse to open such files. This ensures that dmg block driver state always has non-NULL s->sectors[] and related fields. Note that the previous commit fixed the only known way to trigger a crash. This patch is just for defense - let's avoid opening the file and having NULL pointers in dmg block driver state. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4021 Reported-by: Tristan Madani Signed-off-by: Stefan Hajnoczi Message-ID: <20260723144519.364701-3-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/dmg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block/dmg.c b/block/dmg.c index e325127d14..6f8120e033 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -559,6 +559,12 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + /* There must be at least one chunk */ + if (s->n_chunks == 0) { + ret = -EINVAL; + goto fail; + } + /* initialize zlib engine */ s->compressed_chunk = qemu_try_blockalign(bs->file->bs, ds.max_compressed_size + 1); From 370882d0869567e5f21b95229a763171e319d0db Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 23 Jul 2026 10:45:19 -0400 Subject: [PATCH 017/627] dmg: reject inconsistent UDRW chunk sector count and length (CVE-2026-65928) The chunk metadata contains both: - Sector count: number of 512-byte sectors in the virtual disk - Length: number of bytes in the image file The UDRW chunk type indicates uncompressed data that can be accessed directly. The code is missing input validation to verify that sector count is consistent with length. If sector count is larger than length, then read requests can access beyond the end of the s->uncompressed_chunk buffer. This is an out-of-bounds heap access that could lead to a crash or an information leak. While we're at it, also zero the end of the last sector when length is unaligned. This prevents information leaks from the s->uncompressed_chunk buffer. Fixes: CVE-2026-65928 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3846 Reported-by: boy juju Signed-off-by: Stefan Hajnoczi Message-ID: <20260723144519.364701-4-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/dmg.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/block/dmg.c b/block/dmg.c index 6f8120e033..5d7d3b8901 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -312,6 +312,21 @@ static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds, goto fail; } + /* + * Uncompressed chunk length must match sector count. Compressed chunks + * are validated during dmg_read_chunk() since the uncompressed size is + * not known ahead of time. + */ + if (s->types[i] == UDRW) { + if (s->sectorcounts[i] != DIV_ROUND_UP(s->lengths[i], 512)) { + error_report("length %" PRIu64 " for chunk %" PRIu32 + " is inconsistent with sector count %" PRIu64, + s->lengths[i], i, s->sectorcounts[i]); + ret = -EINVAL; + goto fail; + } + } + update_max_chunk_size(s, i, &ds->max_compressed_size, &ds->max_sectors_per_chunk); offset += 40; @@ -722,6 +737,16 @@ dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) if (ret < 0) { return -1; } + + /* + * Zero the unread part of the last sector when chunk length is + * unaligned to avoid exposing uninitialized memory. Valid image + * files may never hit this case, but cover it to be safe. + */ + if (s->lengths[chunk] & 511) { + size_t trailing_bytes = 512 - (s->lengths[chunk] & 511); + memset(s->uncompressed_chunk + s->lengths[chunk], 0, trailing_bytes); + } break; case UDZE: /* zeros */ case UDIG: /* ignore */ From fe0f9e3ab2a8112dd9671bbb91365feba683f755 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 16 Jul 2026 17:35:52 +0200 Subject: [PATCH 018/627] qcow2: do not try to clear the dirty bit on a read-only node qcow2_do_close() -> qcow2_inactivate() clears the dirty bit with a plain write to bs->file, unconditionally. A read-only node can still be dirty, inherited from an earlier writable session, and that write then hits a missing BLK_PERM_WRITE and asserts in bdrv_co_write_req_prepare() (block/io.c) on an entirely ordinary close -- closing is expected, the dirty bit on a read-only node is not. Skip the clear for read-only nodes, same as read access already does. Any other still-dirty node keeps the unguarded write: it is expected to hold write permission, and a missing one there is a bug worth seeing. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz Message-ID: <20260716153552.3376009-1-den@openvz.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qcow2.c | 6 +++++- tests/qemu-iotests/039 | 11 +++++++++++ tests/qemu-iotests/039.out | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index 19271b10a4..7292dd036c 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2870,7 +2870,11 @@ static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs) strerror(-ret)); } - if (result == 0) { + /* + * A read-only node cannot resolve an inherited dirty bit here; + * leave it dirty, same as plain read access already does. + */ + if (result == 0 && !bdrv_is_read_only(bs)) { qcow2_mark_clean(bs); } diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index e43e7026ce..94a8bfe754 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -84,6 +84,17 @@ $QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io # The dirty bit must be set _qcow2_dump_header | grep incompatible_features +echo +echo "== Read-only open must not crash on close ==" + +# We must not try to write the QCOW2 header to a read-only image. +$QEMU_IMG info --image-opts \ + "driver=$IMGFMT,read-only=on,file.driver=file,file.filename=$TEST_IMG,file.read-only=off" \ + > /dev/null + +# The dirty bit must still be set: this open never wrote any guest data +_qcow2_dump_header | grep incompatible_features + echo echo "== Repairing the image file must succeed ==" diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out index 8fdbcc528a..c66361128f 100644 --- a/tests/qemu-iotests/039.out +++ b/tests/qemu-iotests/039.out @@ -24,6 +24,9 @@ read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) incompatible_features [0] +== Read-only open must not crash on close == +incompatible_features [0] + == Repairing the image file must succeed == ERROR cluster 5 refcount=0 reference=1 Rebuilding refcount structure From 43e4791d99ab11c4bd12efaec061b3a43c8cde1c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 15 Jul 2026 12:34:49 +0200 Subject: [PATCH 019/627] iotests: run the test pool with the 'fork' start method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit run_tests_pool() shares the runner via the class attribute TestRunner.shared_self, relying on worker processes to inherit it. That only works with the 'fork' start method. Python 3.14 switched the Linux default to 'forkserver', so workers see shared_self as None and parallel runs abort with: assert runner is not None AssertionError Only reproduces with Python 3.14+ and 'check -jN' (N > 1); meson runs one test per process and never calls run_tests_pool(), so CI is unaffected. Request get_context('fork') explicitly; it is available on all supported Python versions and a no-op before 3.14. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz Message-ID: <20260715103451.1930909-2-den@openvz.org> Reviewed-by: Daniel P. Berrangé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/testrunner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index dbe2dddc32..cc36867719 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -26,7 +26,7 @@ import contextlib import json import shutil import sys -from multiprocessing import Pool +from multiprocessing import get_context from typing import List, Optional, Any, Sequence, Dict from testenv import TestEnv @@ -125,7 +125,7 @@ class TestRunner(contextlib.AbstractContextManager['TestRunner']): assert TestRunner.shared_self is None TestRunner.shared_self = self - with Pool(jobs) as p: + with get_context('fork').Pool(jobs) as p: results = p.starmap(self.proc_run_test, zip(tests, [test_field_width] * len(tests))) From 951227d37554b16a7d0155ad053f348408ddb876 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 15 Jul 2026 12:34:50 +0200 Subject: [PATCH 020/627] iotests: skip FUSE tests when FUSE is not usable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit file-io-error, fuse-allow-other and fuse-mmap-shared skip only when FUSE is not compiled in. When FUSE is built in but unusable at run time (no /dev/fuse access, fusermount lacking permissions), the export fails to mount with "Failed to mount FUSE session to export" and the tests report a spurious failure instead of skipping, like NBD tests already do for missing NBD support. Add _notrun_on_fuse_error() to common.rc and use it in the shell tests. fuse-mmap-shared is Python, so it gets an equivalent inline check. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz Message-ID: <20260715103451.1930909-3-den@openvz.org> Reviewed-by: Daniel P. Berrangé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/common.rc | 14 ++++++++++++++ tests/qemu-iotests/tests/file-io-error | 4 +--- tests/qemu-iotests/tests/fuse-allow-other | 2 ++ tests/qemu-iotests/tests/fuse-mmap-shared | 9 ++++++--- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 298bc483e0..bcb1ec50a9 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -981,6 +981,20 @@ _require_drivers() done } +# Skip if FUSE is unusable: not compiled in, or the export failed to +# mount. $1 is the failing 'block-export-add' reply. +_notrun_on_fuse_error() +{ + case "$1" in + *"Parameter 'type' does not accept value 'fuse'"*) + _notrun "No FUSE support" + ;; + *"Failed to mount FUSE session"*) + _notrun "FUSE not usable in this environment" + ;; + esac +} + # Check that we have a file system that allows huge (but very sparse) files # _require_large_file() diff --git a/tests/qemu-iotests/tests/file-io-error b/tests/qemu-iotests/tests/file-io-error index fb8db73b31..0d970c102f 100755 --- a/tests/qemu-iotests/tests/file-io-error +++ b/tests/qemu-iotests/tests/file-io-error @@ -89,9 +89,7 @@ output=$(_send_qemu_cmd $QEMU_HANDLE \ 'return' \ | grep -v 'option allow_other only allowed if') -if echo "$output" | grep -q "Parameter 'type' does not accept value 'fuse'"; then - _notrun 'No FUSE support' -fi +_notrun_on_fuse_error "$output" echo "$output" echo diff --git a/tests/qemu-iotests/tests/fuse-allow-other b/tests/qemu-iotests/tests/fuse-allow-other index eaa39f8f23..50a36601d7 100755 --- a/tests/qemu-iotests/tests/fuse-allow-other +++ b/tests/qemu-iotests/tests/fuse-allow-other @@ -77,6 +77,8 @@ fuse_export_add() _notrun "allow_other not supported" fi + _notrun_on_fuse_error "$output" + echo "$output" } diff --git a/tests/qemu-iotests/tests/fuse-mmap-shared b/tests/qemu-iotests/tests/fuse-mmap-shared index 52941a3bb6..b190105894 100755 --- a/tests/qemu-iotests/tests/fuse-mmap-shared +++ b/tests/qemu-iotests/tests/fuse-mmap-shared @@ -28,9 +28,12 @@ def test_fuse_support(mount_point): }) test_qsd.stop() if 'error' in res: - assert (res['error']['desc'] == - "Parameter 'type' does not accept value 'fuse'") - iotests.notrun('No FUSE support') + desc = res['error']['desc'] + if desc == "Parameter 'type' does not accept value 'fuse'": + iotests.notrun('No FUSE support') + if 'Failed to mount FUSE session' in desc: + iotests.notrun('FUSE not usable in this environment') + assert False, desc # Shared mmap when using direct IO is only supported for Linux kernels >= 6.6 # with commit e78662e818f94 ("fuse: add a new fuse init flag to relax From 5add514ba36ed2cc2a5aa3be64c4adc72d4d9003 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 15 Jul 2026 12:34:51 +0200 Subject: [PATCH 021/627] iotests/migrate-bitmaps-postcopy-test: replace the timing assertion with a content check `downtime * 10 < postcopy_time` was an unnormalized wall-clock heuristic (commit e80a4150a5) that fails on fast hosts, where the bitmap payload now transfers in under a second. Check the actual invariant instead: right after RESUME, bitmap0's content hash on the destination must not yet match the fully migrated value. Throttle max-bandwidth first, since all-zero chunks skip the payload write and would otherwise let a fast host finish the transfer before the check runs. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Hanna Reitz CC: Vladimir Sementsov-Ogievskiy Message-ID: <20260715103451.1930909-4-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- .../tests/migrate-bitmaps-postcopy-test | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test index c519e6db8c..33ff2b861f 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test @@ -160,12 +160,26 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): self.vm_b.cmd('migrate-set-capabilities', capabilities=caps) + # Throttle so the chunks covering our discards (the only ones + # not skipped by the all-zero fast path) can't outrun the check + # below. + self.vm_a.cmd('migrate-set-parameters', max_bandwidth=16536) + self.vm_a.cmd('migrate', uri='exec:cat>' + fifo) self.vm_a.cmd('migrate-start-postcopy') event_resume = self.vm_b.event_wait('RESUME') self.vm_b_events.append(event_resume) + + # bitmap0 can't already have its final content: that requires + # the bit data to have actually arrived. + result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256', + node='drive0', name='bitmap0') + assert result['return']['sha256'] != all_discards_sha256 + + self.vm_a.cmd('migrate-set-parameters', max_bandwidth=0) + return (event_resume, discards1_sha256, all_discards_sha256) def test_postcopy_success(self): @@ -186,7 +200,6 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase): downtime = event_dist(event_stop, event_resume) postcopy_time = event_dist(event_resume, event_complete) - assert downtime * 10 < postcopy_time if debug: print('downtime:', downtime) print('postcopy_time:', postcopy_time) From e554413bd2b4d6e1f31eebfb499bce5238b91646 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 10 Jun 2026 13:58:50 +0200 Subject: [PATCH 022/627] coroutine: fix lost wakeup in qemu_co_sleep_wake() cache_clean_timer_del_and_wait() cancels the cache-cleaner coroutine by setting s->cache_clean_interval = 0 and calling qemu_co_sleep_wake() to cut short its qemu_co_sleep_ns_wakeable(). qemu_co_sleep_wake() is fire-and-forget: it reads w->to_wake and silently returns when it is NULL. A sleeper that is between two iterations -- has just released s->lock but has not yet set w->to_wake inside qemu_co_sleep() -- loses the wake: iothread0 timer coroutine main thread (qcow2 close) ------------------------- ------------------------- while-body (holding s->lock): read interval = 600 wait_ns = 600 * NS release s->lock take s->lock interval = 0 qemu_co_sleep_wake(w): w->to_wake == NULL -> skip return qemu_co_queue_wait(exit, s->lock): release s->lock yield qemu_co_sleep_ns_wakeable: aio_timer_init(+600 s) qemu_co_sleep: cas scheduled NULL -> "qsns" w->to_wake = co yield [sleeps 600 s] cache_clean_timer_del_and_wait() then blocks on cache_clean_timer_exit until the original 600 s expiry fires, and qcow2_close() holds BQL the whole time so the VM stalls behind it. block_copy_kick() has the same shape. Fix the primitive once instead of working around it in each caller. Use a tri-state for QemuCoSleep::to_wake: NULL - idle co - sleeper parked PENDING - wake delivered, no sleeper yet (sticky) qemu_co_sleep_wake() xchgs PENDING into to_wake: a real sleeper is woken, NULL/PENDING is left untouched so the wake stays sticky. qemu_co_sleep() cmpxchg-publishes itself as the sleeper; if a wake was delivered before it got there or races the publish, the cmpxchg observes PENDING and returns without yielding. On normal resume qemu_co_sleep() clears the PENDING the waker left behind so the next sleep starts clean. A double-fire (real wake plus timer callback) is harmless: the first xchg returns the coroutine and wakes it; the second returns PENDING and is a no-op. Cancellation latency through qemu_co_sleep_wake() is now bounded by aio_co_wake() rather than by the sleep duration. Fixes: f86dde9a15 ("qcow2: Fix cache_clean_timer") Signed-off-by: Denis V. Lunev Cc: Hanna Czenczek Cc: Kevin Wolf Message-ID: <20260610115850.2410566-2-den@openvz.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- include/qemu/coroutine.h | 17 +++++++++--- tests/unit/test-coroutine.c | 53 +++++++++++++++++++++++++++++++++++++ util/qemu-coroutine-sleep.c | 53 ++++++++++++++++++++++++++----------- 3 files changed, 104 insertions(+), 19 deletions(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index e545bbf620..1c31de60f9 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -260,10 +260,19 @@ int coroutine_fn qemu_co_timeout(CoroutineEntry *entry, void *opaque, uint64_t timeout_ns, CleanupFunc clean); /** - * Wake a coroutine if it is sleeping in qemu_co_sleep_ns. The timer will be - * deleted. @sleep_state must be the variable whose address was given to - * qemu_co_sleep_ns() and should be checked to be non-NULL before calling - * qemu_co_sleep_wake(). + * Wake a coroutine sleeping in qemu_co_sleep() or qemu_co_sleep_ns_wakeable(). + * The timer set up by the latter is deleted on wakeup. + * + * The wake is sticky: if no sleeper is parked on @w at the time of the call, + * the wake is recorded on @w and consumed by the next qemu_co_sleep() on the + * same @w, which then returns without yielding. This closes the lost-wakeup + * window between two sleeps and is the documented behavior callers should + * rely on -- e.g. a cancellation signal raised between iterations of a + * sleep/work loop will shorten the next sleep instead of being dropped. + * + * The state persists until consumed: if no further qemu_co_sleep() is ever + * called on @w, the pending wake is harmlessly discarded when @w goes away. + * Multiple wakes coalesce -- the next sleep consumes at most one. */ void qemu_co_sleep_wake(QemuCoSleep *w); diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c index 49d4d9b251..aa1f719b08 100644 --- a/tests/unit/test-coroutine.c +++ b/tests/unit/test-coroutine.c @@ -421,6 +421,57 @@ static void test_co_rwlock_downgrade(void) g_assert(c1_done); } +/* + * Check that a wake delivered before the sleeper parks is not lost. + * + * qemu_co_sleep_wake() is fire-and-forget: a caller cancelling a + * sleep/work loop may call it in the window after the sleeper has + * decided to sleep but before it has published itself inside + * qemu_co_sleep(). The wake must be sticky and shorten the next sleep + * rather than being dropped (which would block until the full sleep + * duration expired). + * + * No threads, timers or AioContext are needed: coroutines are + * cooperative, so ordering the wake before the sleep deterministically + * reproduces the state the racing waker would otherwise produce. + */ + +typedef struct { + QemuCoSleep w; + bool completed; +} CoSleepWakeData; + +static void coroutine_fn co_sleep_wake_entry(void *opaque) +{ + CoSleepWakeData *d = opaque; + + /* + * The wake was already delivered before we got here. qemu_co_sleep() + * must consume it and return without yielding. + */ + qemu_co_sleep(&d->w); + d->completed = true; +} + +static void test_co_sleep_wake_before_sleep(void) +{ + CoSleepWakeData d = { .w = { 0 }, .completed = false }; + Coroutine *co = qemu_coroutine_create(co_sleep_wake_entry, &d); + + /* Waker runs first, while no sleeper is parked on w. */ + qemu_co_sleep_wake(&d.w); + + /* + * Entering runs qemu_co_sleep(), which consumes the pending wake and + * returns without yielding, so the coroutine runs straight to + * completion in this single enter. With the pre-fix primitive the wake + * is dropped, qemu_co_sleep() parks, and completed stays false. + */ + qemu_coroutine_enter(co); + + g_assert(d.completed); +} + /* * Check that creation, enter, and return work */ @@ -660,6 +711,8 @@ int main(int argc, char **argv) g_test_add_func("/locking/co-mutex/lockable", test_co_mutex_lockable); g_test_add_func("/locking/co-rwlock/upgrade", test_co_rwlock_upgrade); g_test_add_func("/locking/co-rwlock/downgrade", test_co_rwlock_downgrade); + g_test_add_func("/locking/co-sleep/wake-before-sleep", + test_co_sleep_wake_before_sleep); if (g_test_perf()) { g_test_add_func("/perf/lifecycle", perf_lifecycle); g_test_add_func("/perf/nesting", perf_nesting); diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index edef117284..19ded0b6fd 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -18,20 +18,29 @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns"; +/* + * Sentinel stored in QemuCoSleep::to_wake by qemu_co_sleep_wake() when no + * sleeper has parked yet. The next qemu_co_sleep() consumes it and returns + * without yielding, so a wake that races the arming of a sleep is never + * lost. + */ +#define QEMU_CO_SLEEP_PENDING ((Coroutine *)(uintptr_t)1) + void qemu_co_sleep_wake(QemuCoSleep *w) { Coroutine *co; - co = w->to_wake; - w->to_wake = NULL; - if (co) { - /* Write of schedule protected by barrier write in aio_co_schedule */ - const char *scheduled = qatomic_cmpxchg(&co->scheduled, - qemu_co_sleep_ns__scheduled, NULL); - - assert(scheduled == qemu_co_sleep_ns__scheduled); - aio_co_wake(co); + co = qatomic_xchg(&w->to_wake, QEMU_CO_SLEEP_PENDING); + if (co == NULL || co == QEMU_CO_SLEEP_PENDING) { + /* No sleeper, or a wake is already pending. */ + return; } + + /* Write of scheduled protected by barrier write in aio_co_schedule */ + const char *scheduled = qatomic_cmpxchg(&co->scheduled, + qemu_co_sleep_ns__scheduled, NULL); + assert(scheduled == qemu_co_sleep_ns__scheduled); + aio_co_wake(co); } static void co_sleep_cb(void *opaque) @@ -43,6 +52,7 @@ static void co_sleep_cb(void *opaque) void coroutine_fn qemu_co_sleep(QemuCoSleep *w) { Coroutine *co = qemu_coroutine_self(); + Coroutine *prev; const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL, qemu_co_sleep_ns__scheduled); @@ -53,11 +63,23 @@ void coroutine_fn qemu_co_sleep(QemuCoSleep *w) abort(); } - w->to_wake = co; + /* + * Publish ourselves as the sleeper. A wake delivered before we got here, + * or one racing this publish, leaves QEMU_CO_SLEEP_PENDING in to_wake; + * the cmpxchg then fails and we consume the wake without yielding. + */ + prev = qatomic_cmpxchg(&w->to_wake, NULL, co); + if (prev == QEMU_CO_SLEEP_PENDING) { + qatomic_set(&w->to_wake, NULL); + qatomic_set(&co->scheduled, NULL); + return; + } + assert(prev == NULL); + qemu_coroutine_yield(); - /* w->to_wake is cleared before resuming this coroutine. */ - assert(w->to_wake == NULL); + /* The waker left QEMU_CO_SLEEP_PENDING; clear it for the next sleep. */ + qatomic_set(&w->to_wake, NULL); } void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, @@ -70,9 +92,10 @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w, timer_mod(&ts, qemu_clock_get_ns(type) + ns); /* - * The timer will fire in the current AiOContext, so the callback - * must happen after qemu_co_sleep yields and there is no race - * between timer_mod and qemu_co_sleep. + * A wake racing with the arming of the sleep -- including the timer + * we just armed firing in another AioContext before qemu_co_sleep() + * publishes itself -- is captured by the sticky PENDING state in + * qemu_co_sleep_wake() and consumed here without yielding. */ qemu_co_sleep(w); timer_del(&ts); From b9ad1c4396e7eb376f0f8dc7d20538980cfa08f2 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 2 Jul 2026 15:22:35 +0200 Subject: [PATCH 023/627] block/export/fuse: fix regression with O_TRUNC when export is not growable Before commit a94a1d7699 ("fuse: Manually process requests (without libfuse)"), the O_TRUNC flag when open()-ing an export would be ignored. This is because libfuse sets FUSE_CAP_ATOMIC_O_TRUNC, so the kernel lets user space handle the O_TRUNC flag, which is ignored by the fuse code for export. After the commit, FUSE_CAP_ATOMIC_O_TRUNC is not set anymore, so the O_TRUNC flag is handled by the kernel, which executes a truncate. For blockdev-based exports, this causes a regression, because opening with O_TRUNC would previously work, but results in an ENOTSUP after commit a94a1d7699. For file-based exports, the fact that truncate is executed can be considered an improvement in general. However, in combination with growable=off, this still results in a practical regression in combination with virt-fw-vars, which opens its output file with O_TRUNC and previously worked with a file-based export with growable=off. After commit a94a1d7699, the file is truncated upon open and then cannot grow, meaning virt-fw-vars won't be able to write the output. To fix these regressions, while keeping the improved behavior for file-based exports with growable=on, set the FUSE_CAP_ATOMIC_O_TRUNC flag again if growable=off. Cc: qemu-stable@nongnu.org Fixes: a94a1d7699 ("fuse: Manually process requests (without libfuse)") Signed-off-by: Fiona Ebner Message-ID: <20260702132256.661429-2-f.ebner@proxmox.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/export/fuse.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/block/export/fuse.c b/block/export/fuse.c index c0e8dfb643..9ae22a2e00 100644 --- a/block/export/fuse.c +++ b/block/export/fuse.c @@ -859,6 +859,18 @@ fuse_co_init(FuseExport *exp, struct fuse_init_out *out, uint32_t supported_flags = FUSE_ASYNC_READ | FUSE_ASYNC_DIO; uint32_t flags2 = 0; + if (!exp->growable) { + /* + * Back when libfuse was used, it would always set this flag and thus + * the kernel did not execute a truncate itself and passed along O_TRUNC + * to user space. Continue setting the flag for backwards compatibility + * when the export is not growable to avoid issues with O_TRUNC, i.e. + * blockdev-based exports running into ENOTSUP and file-based exports + * with growable=off to be truncated and then stuck with size 0. + */ + supported_flags = FUSE_ATOMIC_O_TRUNC; + } + if (in->major != 7) { error_report("FUSE major version mismatch: We have 7, but kernel has %" PRIu32, in->major); From 1d5e53df1674e0e45be50a4a873e6deede2eecd7 Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Wed, 29 Jul 2026 19:34:52 +0900 Subject: [PATCH 024/627] hw/nvme: drop AER requests without aiocb in nvme_del_sq() nvme_del_sq() asserted r->aiocb was always set when canceling a queue's inflight requests. A pending Async Event Request has no aiocb (nvme_aer() parks it without issuing any block I/O), so deleting a queue with an outstanding AER trips the assert instead of just dropping the request. Cc: qemu-stable@nongnu.org Signed-off-by: Minwoo Im Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index bd6ad64b20..e3eadf3d1d 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4862,12 +4862,14 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeRequest *req) sq = n->sq[qid]; while (!QTAILQ_EMPTY(&sq->out_req_list)) { r = QTAILQ_FIRST(&sq->out_req_list); - assert(r->aiocb); r->status = NVME_CMD_ABORT_SQ_DEL; - blk_aio_cancel(r->aiocb); - } - assert(QTAILQ_EMPTY(&sq->out_req_list)); + if (r->aiocb) { + blk_aio_cancel(r->aiocb); + } else { + QTAILQ_REMOVE(&sq->out_req_list, r, entry); + } + } if (!nvme_check_cqid(n, sq->cqid)) { cq = n->cq[sq->cqid]; From 849ea354ddc1c9a4c2af03d57f75acf106ff6b45 Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Wed, 29 Jul 2026 19:34:53 +0900 Subject: [PATCH 025/627] hw/nvme: factor out nvme_sq_cancel_inflight() Factor the cancel-and-wait loop used by nvme_del_sq() into nvme_sq_cancel_inflight(), so it can be reused to drain queues on controller reset. Cc: qemu-stable@nongnu.org Signed-off-by: Minwoo Im Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index e3eadf3d1d..e355c256a5 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -4826,6 +4826,26 @@ static int nvme_init_sq_ioeventfd(NvmeSQueue *sq) return 0; } +/* + * A pending Async Event Request has no aiocb (nvme_aer() parks it without + * issuing any block I/O), so there is nothing to cancel; just drop it. + */ +static void nvme_sq_cancel_inflight(NvmeSQueue *sq, uint16_t status) +{ + NvmeRequest *r; + + while (!QTAILQ_EMPTY(&sq->out_req_list)) { + r = QTAILQ_FIRST(&sq->out_req_list); + r->status = status; + + if (r->aiocb) { + blk_aio_cancel(r->aiocb); + } else { + QTAILQ_REMOVE(&sq->out_req_list, r, entry); + } + } +} + static void nvme_free_sq(NvmeSQueue *sq, NvmeCtrl *n) { uint16_t offset = sq->sqid << 3; @@ -4860,16 +4880,7 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeRequest *req) trace_pci_nvme_del_sq(qid); sq = n->sq[qid]; - while (!QTAILQ_EMPTY(&sq->out_req_list)) { - r = QTAILQ_FIRST(&sq->out_req_list); - r->status = NVME_CMD_ABORT_SQ_DEL; - - if (r->aiocb) { - blk_aio_cancel(r->aiocb); - } else { - QTAILQ_REMOVE(&sq->out_req_list, r, entry); - } - } + nvme_sq_cancel_inflight(sq, NVME_CMD_ABORT_SQ_DEL); if (!nvme_check_cqid(n, sq->cqid)) { cq = n->cq[sq->cqid]; From 86f938333e2faae7c60ca66c0809f5495c59aa4b Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Wed, 29 Jul 2026 19:34:54 +0900 Subject: [PATCH 026/627] hw/nvme: cancel inflight requests on controller reset nvme_ctrl_reset() freed every SQ/CQ right after nvme_ns_drain(), which only waits out requests on a per-namespace BlockBackend. That is safe as long as the guest first tore down I/O queues gracefully (Delete I/O SQ/CQ), since nvme_del_sq() already cancels and waits for anything left on a queue before freeing it. A reset that happens without that graceful sequence first (e.g. an abrupt/asynchronous controller reset) can still have commands inflight on blk_aio_*. Freeing sq/cq before those complete leaves their completion callbacks (nvme_rw_cb() and friends) to run against already-freed NvmeRequest/NvmeSQueue/NvmeCQueue memory via nvme_enqueue_req_completion(), causing a use-after-free/segfault. Run nvme_sq_cancel_inflight() over every queue in nvme_ctrl_reset() before the free loops, so no in-flight blk_aio_* callback can fire after sq/cq memory is freed. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3398 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3883 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4068 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4072 Signed-off-by: Minwoo Im Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index e355c256a5..8461b6fbde 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -8040,6 +8040,18 @@ static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst) nvme_ns_drain(ns); } + /* + * Cancel and wait out every inflight command on every queue first. A + * reset is not required to be preceded by the guest's graceful + * Delete I/O SQ/CQ sequence, so sq/cq must not be freed below while a + * blk_aio_* completion for them could still be in flight. + */ + for (i = 0; i < n->num_queues; i++) { + if (n->sq[i] != NULL) { + nvme_sq_cancel_inflight(n->sq[i], NVME_CMD_ABORT_SQ_DEL); + } + } + for (i = 0; i < n->num_queues; i++) { if (n->sq[i] != NULL) { nvme_free_sq(n->sq[i], n); From 7a34f7b8794b29cd1bd4dfa45f7d8e8daba7cff5 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Fri, 31 Jul 2026 11:21:33 +0200 Subject: [PATCH 027/627] hw/nvme: fix leak on copy ranges The buffer holding the ranges for the copy command is not correctly deallocated. Fix this. Cc: qemu-stable@nongnu.org Link: https://gitlab.com/qemu-project/qemu/-/work_items/4072 Fixes: 796d20681d9b ("hw/nvme: reimplement the copy command to allow aio cancellation") Reviewed-by: Jesper Wendel Devantier Signed-off-by: Klaus Jensen --- hw/nvme/ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index 8461b6fbde..4893cf7e74 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -2811,6 +2811,7 @@ static void nvme_copy_done(NvmeCopyAIOCB *iocb) qemu_iovec_destroy(&iocb->iov); g_free(iocb->bounce); + g_free(iocb->ranges); if (iocb->ret < 0) { block_acct_failed(stats, &iocb->acct.read); From 7d06bbb2d9ba77e45b5a3131c9e7f934df99d5bc Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Thu, 2 Jul 2026 15:22:36 +0200 Subject: [PATCH 028/627] iotests: test O_TRUNC behavior for fuse exports The test cases for the blockdev-based export and for the file-based export with growable=on work before commit a94a1d7699 ("fuse: Manually process requests (without libfuse)"), then are broken until commit "block/export/fuse: fix regression with O_TRUNC when export is growable". The test case for the blockdev-based export requires passwordless sudo for losetup and chmod similar to test 108. Signed-off-by: Fiona Ebner Message-ID: <20260702132256.661429-3-f.ebner@proxmox.com> [kwolf: Catch OSError when probing sudo support] Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/tests/fuse-truncate | 171 +++++++++++++++++++++ tests/qemu-iotests/tests/fuse-truncate.out | 5 + 2 files changed, 176 insertions(+) create mode 100755 tests/qemu-iotests/tests/fuse-truncate create mode 100644 tests/qemu-iotests/tests/fuse-truncate.out diff --git a/tests/qemu-iotests/tests/fuse-truncate b/tests/qemu-iotests/tests/fuse-truncate new file mode 100755 index 0000000000..7eee35111c --- /dev/null +++ b/tests/qemu-iotests/tests/fuse-truncate @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# group: rw +# +# Test how fuse exports behave with regard to O_TRUNC. +# +# Copyright (C) 2026 Proxmox Server Solutions GmbH +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import subprocess +from pathlib import Path + +import iotests +from iotests import qemu_img, QemuStorageDaemon + +fuse_mount_point = os.path.join(iotests.test_dir, 'export.fuse') +image_size = 1 * 1024 * 1024 +image = os.path.join(iotests.test_dir, 'image.' + iotests.imgfmt) + +def check_fuse_support(): + Path(fuse_mount_point).touch() + test_qsd = QemuStorageDaemon('--blockdev', 'null-co,node-name=node0', + qmp=True) + res = test_qsd.qmp('block-export-add', { + 'id': 'exp0', + 'type': 'fuse', + 'node-name': 'node0', + 'mountpoint': fuse_mount_point, + 'allow-other': 'off' + }) + test_qsd.stop() + os.remove(fuse_mount_point) + if 'error' in res: + assert (res['error']['desc'] == + "Parameter 'type' does not accept value 'fuse'") + iotests.notrun('No FUSE support') + +def check_sudo_support(): + try: + subprocess.run(['sudo', '-n', 'losetup', '--version'], + capture_output=True, check=True) + except (OSError, subprocess.CalledProcessError): + return False + try: + subprocess.run(['sudo', '-n', 'chmod', '--version'], + capture_output=True, check=True) + except (OSError, subprocess.CalledProcessError): + return False + return True + +check_fuse_support() + +class TestTruncateBase(iotests.QMPTestCase): + growable = False + supports_preconditions = True + + def evaluate_preconditions(self): + return + + def add_blockdev(self): + qemu_img('create', '-f', iotests.imgfmt, image, str(image_size)) + self.qsd.cmd('blockdev-add', { + 'node-name': 'node0', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'file', + 'filename': image + } + }) + + def cleanup_blockdev(self): + os.remove(image) + + def add_export(self): + self.qsd.cmd('block-export-add', { + 'id': 'exp0', + 'type': 'fuse', + 'node-name': 'node0', + 'mountpoint': fuse_mount_point, + 'growable': self.growable, + 'writable': True, + 'allow-other': 'off' + }) + + def stop_qsd(self): + if self.qsd: + self.qsd.cmd('block-export-del', {'id': 'exp0'}) + self.qsd.stop() + self.qsd = None + + def setUp(self): + self.evaluate_preconditions() + if not self.supports_preconditions: + return + Path(fuse_mount_point).touch() + self.qsd = QemuStorageDaemon(qmp=True) + self.add_blockdev() + self.add_export() + + def tearDown(self): + if not self.supports_preconditions: + return + self.stop_qsd() + self.cleanup_blockdev() + os.remove(fuse_mount_point) + +class TestTruncateFileGrowable(TestTruncateBase): + growable = True + + def test_o_trunc(self): + with open(fuse_mount_point, 'w+b') as file: + file.seek(0, os.SEEK_END) + self.assertEqual(file.tell(), 0) + file.write(b"test") + self.stop_qsd() + +class TestTruncateFileNotGrowable(TestTruncateBase): + growable = False + + def test_o_trunc(self): + with open(fuse_mount_point, 'w+b') as file: + file.seek(0, os.SEEK_END) + self.assertEqual(file.tell(), image_size) + file.seek(0, os.SEEK_SET) + file.write(b"test") + self.stop_qsd() + +class TestTruncateBlockdev(TestTruncateBase): + growable = False + + def evaluate_preconditions(self): + self.supports_preconditions = check_sudo_support() + + def add_blockdev(self): + qemu_img('create', '-f', iotests.imgfmt, image, str(image_size)) + res = subprocess.run(['sudo', '-n', 'losetup', '--show', '-f', image], + check=True, capture_output=True, text=True) + self.loopdev = res.stdout.strip() + subprocess.run(['sudo', '-n', 'chmod', 'go+rw', self.loopdev], + check=True, capture_output=True) + self.qsd.cmd('blockdev-add', { + 'node-name': 'node0', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'host_device', + 'filename': self.loopdev + } + }) + + def cleanup_blockdev(self): + subprocess.run(['sudo', '-n', 'losetup', '--detach', self.loopdev], + check=True, capture_output=True) + os.remove(image) + + def test_o_trunc(self): + if not self.supports_preconditions: + iotests.case_notrun('No passwordless sudo for losetup and chmod') + return + + with open(fuse_mount_point, 'w+b') as file: + file.seek(0, os.SEEK_END) + self.assertEqual(file.tell(), image_size) + file.seek(0, os.SEEK_SET) + file.write(b"test") + self.stop_qsd() + +if __name__ == '__main__': + iotests.main(supported_fmts=['raw'], + supported_protocols=['file'], + supported_platforms=['linux']) diff --git a/tests/qemu-iotests/tests/fuse-truncate.out b/tests/qemu-iotests/tests/fuse-truncate.out new file mode 100644 index 0000000000..8d7e996700 --- /dev/null +++ b/tests/qemu-iotests/tests/fuse-truncate.out @@ -0,0 +1,5 @@ +... +---------------------------------------------------------------------- +Ran 3 tests + +OK From d00567f7fb2312c71bfc65a338c1b046f623df81 Mon Sep 17 00:00:00 2001 From: Christian Quante Date: Tue, 14 Jul 2026 18:40:30 +0200 Subject: [PATCH 029/627] hw/block/fdc: select the drive named by the READ ID command Every other command handler begins by latching the drive from the command byte: SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); fdctrl_handle_readid() does not, so it works on whichever drive happened to be selected last. A guest that issues READ ID for a drive other than the one currently selected gets an answer about the wrong one. It has gone unnoticed because a driver normally writes the DOR to spin up the motor first, and that write selects the drive as a side effect. The controller does not require it, though, and the command carries the drive number for a reason. Reported-by: Kevin Wolf Signed-off-by: Christian Quante Message-ID: <20260714164031.60551-2-christian@quante.one> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- hw/block/fdc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 2c1681b7d0..9b2409cfa4 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -1936,7 +1936,10 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction) static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction) { - FDrive *cur_drv = get_cur_drv(fdctrl); + FDrive *cur_drv; + + SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); + cur_drv = get_cur_drv(fdctrl); cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; timer_mod(fdctrl->result_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + From 431f59a34db5234919262b558880a2d57b64a738 Mon Sep 17 00:00:00 2001 From: Christian Quante Date: Tue, 14 Jul 2026 18:40:31 +0200 Subject: [PATCH 030/627] hw/block/fdc: report a missing address mark on an empty drive READ ID on a drive with no medium terminates normally and returns the made-up sector ID left over from the "Pretend we are spinning" emulation. The only error path is a data rate mismatch, and media_rate is assigned solely by pick_geometry(); it is never reset when the medium is removed. A guest that has just ejected a diskette is therefore told that one is still present. READ, WRITE and FORMAT have a related problem: fd_seek() answers 2 both for "track/head out of range" and for "no medium", so the callers report ST0 = ABNTERM with ST1 = 0x00 either way. Without ST1.MA the guest cannot tell an absent diskette from a transient error. Give fd_seek() a return code of its own for an absent medium, and let both switch statements report the missing address mark for it. The comments on the two switches were swapped: fd_seek() answers 2 for a bad track or head and 3 for a sector past last_sect, but case 2 read "sect too big" and case 3 "track too big". Both now say what they mean. This is a behaviour change for FORMAT TRACK on an empty drive as well, which now answers ST1.MA rather than ST1 = 0x00. None of the guests tested reaches that path -- DOS gives up during media sensing and never issues the command -- but it seemed wrong to leave fdctrl_format_sector() falling through to "default" for a case fd_seek() now reports explicitly. Failing READ ID does not make guests detect the removal: real hardware never completes the command on an empty drive, because there are no index pulses, and OS/2 for one relies on that timeout. It does stop the controller from claiming a diskette that is not there. tests/qtest/fdc-test.c starts QEMU with "-device floppy,id=floppy0" and no medium, and test_read_id asserts a normal termination with a made-up cylinder 8 / head 1. That contradicts its neighbours test_no_media_on_start and test_media_change, which state that DSKCHG signals an absent medium. Insert a medium before READ ID and eject it afterwards -- the rewritten test passes before and after this change -- and add test_read_id_no_media for the empty drive. Guests checked, reading and writing, with and without a medium: Linux 2.0.34 and 7.0, PC-DOS 7, IBM DOS 5.02, Windows for Workgroups 3.11 and OS/2 2.11. None changes behaviour. No version of the Linux floppy driver from 1.2.13 to master issues READ ID at all -- FD_READID is defined in the uapi header for FDRAWCMD users and the driver never sends it -- so Linux detects an empty drive by stepping the head and reading DSKCHG instead. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/3971 Signed-off-by: Christian Quante Message-ID: <20260714164031.60551-3-christian@quante.one> [kwolf: Added fd_seek() comment for new return value 5] Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- hw/block/fdc.c | 50 +++++++++++++++++++++++++----- tests/qtest/fdc-test.c | 70 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 106 insertions(+), 14 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 9b2409cfa4..1178b959a6 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -196,6 +196,12 @@ static void fd_init(FDrive *drv) #define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1) +/* Is a diskette present in the drive? */ +static bool fd_media_present(FDrive *drv) +{ + return drv->blk != NULL && blk_is_inserted(drv->blk); +} + static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect, uint8_t last_sect, uint8_t num_sides) { @@ -222,6 +228,7 @@ static int fd_offset(FDrive *drv) * returns 2 if track is invalid * returns 3 if sector is invalid * returns 4 if seek is disabled + * returns 5 if no floppy is inserted */ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect, int enable_seek) @@ -258,7 +265,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect, #endif drv->head = head; if (drv->track != track) { - if (drv->blk != NULL && blk_is_inserted(drv->blk)) { + if (fd_media_present(drv)) { drv->media_changed = 0; } ret = 1; @@ -267,8 +274,8 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect, drv->sect = sect; } - if (drv->blk == NULL || !blk_is_inserted(drv->blk)) { - ret = 2; + if (!fd_media_present(drv)) { + ret = 5; } return ret; @@ -1476,14 +1483,24 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) NUM_SIDES(cur_drv))); switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) { case 2: - /* sect too big */ + /* track/head out of range */ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; + case 5: + /* + * No medium: there is no address mark to be found. Guests that tell + * an absent diskette from an unreadable one rely on ST1.MA. + */ + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; case 3: - /* track too big */ + /* sector too big */ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; @@ -1791,14 +1808,21 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) NUM_SIDES(cur_drv))); switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) { case 2: - /* sect too big */ + /* track/head out of range */ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; fdctrl->fifo[5] = ks; return; + case 5: + /* no medium */ + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); + fdctrl->fifo[3] = kt; + fdctrl->fifo[4] = kh; + fdctrl->fifo[5] = ks; + return; case 3: - /* track too big */ + /* sector too big */ fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00); fdctrl->fifo[3] = kt; fdctrl->fifo[4] = kh; @@ -2306,6 +2330,18 @@ static void fdctrl_result_timer(void *opaque) FDCtrl *fdctrl = opaque; FDrive *cur_drv = get_cur_drv(fdctrl); + /* + * An empty drive has no address marks to read. Completing READ ID + * successfully, with the made-up sector ID left over from the "spinning" + * emulation below, tells the guest that a diskette is still present after + * it has been ejected. The only error path left was a data rate mismatch, + * and media_rate is never reset when the medium is removed. + */ + if (!fd_media_present(cur_drv)) { + FLOPPY_DPRINTF("read id on empty drive\n"); + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); + return; + } /* Pretend we are spinning. * This is needed for Coherent, which uses READ ID to check for * sector interleaving. diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c index 1b37a8a4d2..1e1dd8659d 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -64,6 +64,12 @@ enum { DSKCHG = 0x80, }; +enum { + ST0_IC_MASK = 0xc0, /* interrupt code */ + ST0_IC_ABNTERM = 0x40, /* abnormal termination */ + + ST1_MA = 0x01, /* missing address mark */ +}; static char *test_image; @@ -270,6 +276,21 @@ static void test_cmos(void) g_assert(cmos == 0x40 || cmos == 0x50); } +static void media_insert(void) +{ + qtest_qmp_assert_success(global_qtest, + "{'execute':'blockdev-change-medium', 'arguments':{" + " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}", + test_image); +} + +static void media_eject(void) +{ + qtest_qmp_assert_success(global_qtest, + "{'execute':'eject', 'arguments':{" + " 'id':'floppy0' }}"); +} + static void test_no_media_on_start(void) { uint8_t dir; @@ -301,10 +322,7 @@ static void test_media_insert(void) /* Insert media in drive. DSKCHK should not be reset until a step pulse * is sent. */ - qtest_qmp_assert_success(global_qtest, - "{'execute':'blockdev-change-medium', 'arguments':{" - " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}", - test_image); + media_insert(); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); @@ -333,9 +351,7 @@ static void test_media_change(void) /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't * reset the bit. */ - qtest_qmp_assert_success(global_qtest, - "{'execute':'eject', 'arguments':{" - " 'id':'floppy0' }}"); + media_eject(); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); @@ -414,6 +430,9 @@ static void test_read_id(void) uint8_t st0; uint8_t msr; + /* READ ID reads an address mark, so it needs a medium in the drive. */ + media_insert(); + /* Seek to track 0 and check with READ ID */ send_seek(0); @@ -491,6 +510,42 @@ static void test_read_id(void) g_assert_cmpint(cyl, ==, 8); g_assert_cmpint(head, ==, 1); g_assert_cmpint(st0, ==, head << 2); + + /* Leave the drive empty, the way the machine starts up. */ + media_eject(); +} + +/* + * An empty drive spins no diskette, so READ ID finds no address mark and must + * terminate abnormally. Reporting success (with a made-up sector ID) would + * tell the guest that a medium is still present after it has been ejected. + */ +static void test_read_id_no_media(void) +{ + uint8_t drive = 0; + uint8_t head = 0; + uint8_t st0, st1; + + floppy_send(CMD_READ_ID); + g_assert(!get_irq(FLOPPY_IRQ)); + floppy_send(head << 2 | drive); + + while (!get_irq(FLOPPY_IRQ)) { + clock_step(1000000000LL / 50); + } + + st0 = floppy_recv(); + st1 = floppy_recv(); + floppy_recv(); /* ST2 */ + floppy_recv(); /* cylinder */ + floppy_recv(); /* head */ + floppy_recv(); /* sector */ + g_assert(get_irq(FLOPPY_IRQ)); + floppy_recv(); /* sector size */ + g_assert(!get_irq(FLOPPY_IRQ)); + + g_assert_cmpint(st0 & ST0_IC_MASK, ==, ST0_IC_ABNTERM); + g_assert_cmpint(st1 & ST1_MA, ==, ST1_MA); } static void test_read_no_dma_1(void) @@ -625,6 +680,7 @@ int main(int argc, char **argv) qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt); qtest_add_func("/fdc/relative_seek", test_relative_seek); qtest_add_func("/fdc/read_id", test_read_id); + qtest_add_func("/fdc/read_id_no_media", test_read_id_no_media); qtest_add_func("/fdc/verify", test_verify); qtest_add_func("/fdc/media_insert", test_media_insert); qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1); From 29922afeae84a6c51f35d569da97c0b8c8fcc165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 23 Jun 2026 17:03:26 +0100 Subject: [PATCH 031/627] iotests: increase timeouts for tests to 5 minutes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we have tests timeout set to 3 minutes, on the basis that they're generally done in less than a minute. I've hit a couple of random failures suggesting that's not sufficiently pessimistic. Increase the timeout to 5 minutes to have a greater safety net in high load scenarios. Signed-off-by: Daniel P. Berrangé Message-ID: <20260623160326.2346255-1-berrange@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- tests/qemu-iotests/meson.build | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build index bc6132a0f7..8857f25f29 100644 --- a/tests/qemu-iotests/meson.build +++ b/tests/qemu-iotests/meson.build @@ -52,16 +52,17 @@ foreach driver, speed: qemu_iotests_drivers '-tap', '-' + driver, item, '--source-dir', meson.current_source_dir(), '--build-dir', meson.current_build_dir()] - # Some individual tests take as long as 45 seconds - # Bump the timeout to 3 minutes for some headroom - # on slow machines to minimize spurious failures + # Some individual tests take as long as 3 minutes + # in high load scenarios. Bump the timeout to 5 + # minutes for some headroom on slow / loaded + # machines to minimize spurious failures test('io-' + driver + '-' + item, python, args: args, depends: qemu_iotests_binaries, env: qemu_iotests_env, protocol: 'tap', - timeout: 180, + timeout: 300, suite: suites) endforeach endif @@ -94,16 +95,14 @@ foreach driver, speed: qemu_iotests_drivers '-tap', '-' + driver, item, '--source-dir', meson.current_source_dir(), '--build-dir', meson.current_build_dir()] - # Some individual tests take as long as 45 seconds - # Bump the timeout to 3 minutes for some headroom - # on slow machines to minimize spurious failures + # See earlier note about timeouts test('io-' + driver + '-' + item, python, args: args, depends: qemu_iotests_binaries, env: qemu_iotests_env, protocol: 'tap', - timeout: 180, + timeout: 300, suite: suites) endforeach endforeach From 241095547a5d87ad6fa68cd674fe524e6596b958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 29 Jul 2026 20:14:31 +0400 Subject: [PATCH 032/627] hw/display/virtio-gpu: validate blob iov size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_gpu_resource_create_blob() stores the guest-controlled blob_size without checking it against the total size of the iov backing entries. Since both values are independently guest-controlled, a malicious guest can set blob_size much larger than the actual iov backing. Subsequent SET_SCANOUT_BLOB checks bounds against the inflated blob_size, allowing a pixman surface to be created over the undersized buffer. Any display refresh then reads past the actual allocation, potentially crashing QEMU or leaking host memory contents depending on the backing type. Validate that the iov backing is at least as large as the declared blob_size in create_blob (when nr_entries > 0, since the spec permits deferred backing), attach_backing (when attaching to a blob resource), and the blob migration load path. Fixes: CVE-2026-66021 Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3945 Reported-by: "sundayjiang(蒋浩天)" Reviewed-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Message-ID: <20260729161431.1180691-1-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 4d46a4eb10..0206910cc3 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -372,6 +372,17 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, return; } + if (res->iov_cnt > 0 && + iov_size(res->iov, res->iov_cnt) < res->blob_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: backing storage smaller than blob size\n", + __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + virtio_gpu_cleanup_mapping(g, res); + g_free(res); + return; + } + virtio_gpu_init_udmabuf(res); QTAILQ_INSERT_HEAD(&g->reslist, res, next); } @@ -993,6 +1004,15 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } + if (iov_size(res->iov, res->iov_cnt) < res->blob_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: backing storage smaller than blob size\n", + __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + virtio_gpu_cleanup_mapping(g, res); + return; + } + if (!res->image) { virtio_gpu_init_udmabuf(res); } @@ -1493,6 +1513,14 @@ static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size, res->iov[i].iov_len = qemu_get_be32(f); } + if (res->iov_cnt > 0 && + iov_size(res->iov, res->iov_cnt) < res->blob_size) { + g_free(res->addrs); + g_free(res->iov); + g_free(res); + return -EINVAL; + } + if (!virtio_gpu_load_restore_mapping(g, res)) { g_free(res); return -EINVAL; From 95687639e647ec917226e6d3a6713a2b373e1ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 28 Jul 2026 19:14:56 +0400 Subject: [PATCH 033/627] hw/display/vga: fix panning_buf OOB after text/graphics switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fields last_width and last_height serve two purposes: the text renderer counts in characters, the graphics renderer in pixels. panning_buf reallocation is guarded by geometry-change check, so the unit mismatch can trick it into thinking nothing changed when the resolution actually grew. A guest can trigger this by switching graphics -> text -> graphics: 1. Enter graphics mode with a small width (CR01=0x00, 8 pixels). The predicate fires and panning_buf is allocated for that width. 2. Switch to text mode with a large width (CR01=0xFF, 256 chars). The text renderer stores 256 into last_width. The text path never touches panning_buf. 3. Switch back to graphics with a width that happens to equal 256 in pixels (CR01=0x1F, 32*8 = 256). The predicate sees 256 == 256 and skips the realloc. With horizontal pel panning enabled, vga_draw_line4() then writes a full 256-pixel scanline into the buffer still sized for 8 pixels -- a 960-byte heap overflow on every scanline, every refresh. Fix it by reallocating unconditionally panning_buf on vga_draw_graphic(). Fixes: CVE-2026-17516 Fixes: 973a724eb006 ("vga: implement horizontal pel panning in graphics modes") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4085 Cc: Paolo Bonzini Signed-off-by: Warisjeet Singh [ Marc- André - drop realloc() resize condition & commit message ] Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Marc-André Lureau Message-ID: <20260728151456.3704099-1-marcandre.lureau@redhat.com> --- hw/display/vga.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/display/vga.c b/hw/display/vga.c index abe3f8e077..da0c331486 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1647,11 +1647,12 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->last_line_offset = s->params.line_offset; s->last_depth = depth; s->last_byteswap = byteswap; - /* 16 extra pixels are needed for double-width planar modes. */ - s->panning_buf = g_realloc(s->panning_buf, - (disp_width + 16) * sizeof(uint32_t)); full_update = 1; } + + /* 16 extra pixels are needed for double-width planar modes. */ + s->panning_buf = g_realloc(s->panning_buf, + (disp_width + 16) * sizeof(uint32_t)); if (surface_data(surface) != s->vram_ptr + (s->params.start_addr * 4) && !surface_is_allocated(surface)) { /* base address changed (page flip) -> shared display surfaces From a113e0c53fb50d78529fd5ea79e3b8313a7ddcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 10 Jul 2026 17:47:19 +0400 Subject: [PATCH 034/627] vhost-user-gpu: fix integer overflow in buffer allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A malicious guest can trigger a heap buffer overflow in the vhost-user-gpu backend by sending a VIRTIO_GPU_CMD_RESOURCE_CREATE_2D with large width and height values (e.g. 65537x65537). The allocation size width * height * 4 silently wraps in uint32_t arithmetic, resulting in a much smaller allocation than expected. Subsequent VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D writes past the heap buffer. The in-tree virtio-gpu device (hw/display/virtio-gpu.c) already handles this via calc_image_hostmem() with uint64_t arithmetic and an overflow check. Apply the same approach to the vhost-user-gpu contrib backend: - Add an overflow check in vugbm_buffer_create() rejecting dimensions where width * height * 4 exceeds UINT32_MAX - Promote the size arithmetic to uint64_t in mem_alloc_bo() and udmabuf_get_size() - Check the return value of vugbm_buffer_create() in vg_resource_create_2d(), which was previously ignored Fixes: CVE-2026-15264 Reported-by: "Vulnerability Report" Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3940 Signed-off-by: Marc-Andre Lureau Acked-by: Philippe Mathieu-Daudé Message-ID: <20260710134720.2317856-1-marcandre.lureau@redhat.com> --- contrib/vhost-user-gpu/vhost-user-gpu.c | 8 +++++++- contrib/vhost-user-gpu/vugbm.c | 11 +++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c index bb41758e34..ee9858c397 100644 --- a/contrib/vhost-user-gpu/vhost-user-gpu.c +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c @@ -388,7 +388,13 @@ vg_resource_create_2d(VuGpu *g, cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; return; } - vugbm_buffer_create(&res->buffer, &g->gdev, c2d.width, c2d.height); + if (!vugbm_buffer_create(&res->buffer, &g->gdev, c2d.width, c2d.height)) { + g_critical("%s: buffer creation failed %d %d %d", + __func__, c2d.resource_id, c2d.width, c2d.height); + g_free(res); + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } res->image = pixman_image_create_bits(pformat, c2d.width, c2d.height, diff --git a/contrib/vhost-user-gpu/vugbm.c b/contrib/vhost-user-gpu/vugbm.c index 503d0a4566..710d545297 100644 --- a/contrib/vhost-user-gpu/vugbm.c +++ b/contrib/vhost-user-gpu/vugbm.c @@ -13,7 +13,7 @@ static bool mem_alloc_bo(struct vugbm_buffer *buf) { - buf->mmap = g_malloc(buf->width * buf->height * 4); + buf->mmap = g_malloc((uint64_t)buf->width * buf->height * 4); buf->stride = buf->width * 4; return true; } @@ -53,7 +53,8 @@ struct udmabuf_create { static size_t udmabuf_get_size(struct vugbm_buffer *buf) { - return ROUND_UP(buf->width * buf->height * 4, qemu_real_host_page_size()); + return ROUND_UP((uint64_t)buf->width * buf->height * 4, + qemu_real_host_page_size()); } static bool @@ -293,6 +294,12 @@ bool vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev, uint32_t width, uint32_t height) { + uint64_t size = (uint64_t)width * height * 4; + if (size > UINT32_MAX) { + g_warning("buffer dimensions too large: %ux%u", width, height); + return false; + } + buffer->dev = dev; buffer->width = width; buffer->height = height; From b8ef970532c30da2f3fa8985867a74f898ce96aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 25 Jul 2026 16:27:34 +0400 Subject: [PATCH 035/627] hw/display/virtio-gpu: fix offset wraparound in scanout_blob_to_fb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_gpu_scanout_blob_to_fb() computes the framebuffer offset from guest-controlled offsets[0], r.x, r.y and stride using uint32_t arithmetic. When the sum exceeds UINT32_MAX, silent wraparound lets the guest steer the scanout to an arbitrary in-bounds region of the blob instead of the intended rectangle. Compute the offset in uint64_t, reject values exceeding UINT32_MAX (the width of fb->offset), and only store into fb->offset once both range checks pass. ("[PATCH] hw/display/virtio-gpu: Remove the bytes_pp field") Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3871 Based-on: <20260719-bpp-v1-1-9b91946d6cf3@rsg.ci.i.u-tokyo.ac.jp> Reported-by: Cyber_black Reviewed-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Message-ID: <20260725122734.1775774-1-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 0206910cc3..51592b49c2 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -777,7 +777,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb, struct virtio_gpu_set_scanout_blob *ss, uint64_t blob_size) { - uint64_t fbend; + uint64_t fbend, offset; uint32_t bytes_pp; fb->format = virtio_gpu_get_pixman_format(ss->format); @@ -807,18 +807,20 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb, return false; } - fb->offset = ss->offsets[0] + ss->r.x * bytes_pp + ss->r.y * fb->stride; + offset = (uint64_t)ss->offsets[0] + (uint64_t)ss->r.x * bytes_pp + + (uint64_t)ss->r.y * fb->stride; - fbend = fb->offset; - fbend += (uint64_t) fb->stride * ss->r.height; + fbend = offset + (uint64_t)fb->stride * ss->r.height; - if (fbend > blob_size) { + if (offset > UINT32_MAX || fbend > blob_size) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: fb end out of range\n", + "%s: invalid fb bounds\n", __func__); return false; } + fb->offset = offset; + return true; } From 555d0a1eba204085e20421cd93a55276a21b8e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 30 Jul 2026 15:47:51 +0400 Subject: [PATCH 036/627] hw/display/virtio-gpu: drop redundant node->value NULL checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QAPI-generated list visitors guarantee that node->value is never NULL: the input visitor allocates it via g_malloc0() in visit_start_struct(), and on failure the entire list parse is aborted and freed. Remove the unnecessary NULL checks from both callsites iterating g->conf.outputs. Resolves: Coverity CID 1664272 Fixes: 8dc8449a678f ("hw/display/virtio-gpu: Avoid leaking migration blocker") Reviewed-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Message-ID: <20260730114751.3515083-1-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu-base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 946e56b42f..270fbaae10 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -69,7 +69,7 @@ virtio_gpu_base_generate_edid(VirtIOGPUBase *g, int scanout, for (output_idx = 0, node = g->conf.outputs; output_idx <= scanout && node; output_idx++, node = node->next) { - if (output_idx == scanout && node->value && node->value->name) { + if (output_idx == scanout && node->value->name) { info.name = node->value->name; break; } @@ -206,7 +206,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev, error_setg(errp, "invalid outputs > %d", g->conf.max_outputs); return false; } - if (node->value && node->value->name && + if (node->value->name && strlen(node->value->name) > EDID_NAME_MAX_LENGTH) { error_setg(errp, "invalid output name '%s' > %d", node->value->name, EDID_NAME_MAX_LENGTH); From 1f24066fc88d33455ee54a20f29994d9e69997ba Mon Sep 17 00:00:00 2001 From: Ankur Saini Date: Mon, 3 Aug 2026 22:39:21 +0530 Subject: [PATCH 037/627] virtio-gpu: reject requests with short/truncated control headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A short control request can leave command data partially initialized. For the common header, guest-controlled flags can then cause stale fence metadata to be returned to the guest. The command fill helpers detect a short copy but only log and return. For the common header this leaves the request without any completion; for type-specific commands the caller still completes the request but reports VIRTIO_GPU_RESP_OK_NODATA, masking the error. Make VIRTIO_GPU_FILL_CMD() clear the partially copied object and complete the request with ERR_INVALID_PARAMETER. Make VUGPU_FILL_CMD() report the same error through the existing vhost-user-gpu dispatcher. This also rejects truncated type-specific commands. The vhost-user-gpu common header is copied outside VUGPU_FILL_CMD(), so clear it and complete the request directly when that copy is short. Fixes: CVE-2026-18054 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4094 Reported-by: Ankur Saini Suggested-by: Akihiko Odaki Signed-off-by: Ankur Saini Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260803-virtio-gpu-short-header-v3-1-936c1daa8e61@gmail.com> --- contrib/vhost-user-gpu/vhost-user-gpu.c | 21 ++++++++++++--------- contrib/vhost-user-gpu/vugpu.h | 1 + include/hw/virtio/virtio-gpu.h | 3 +++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c index ee9858c397..7864881509 100644 --- a/contrib/vhost-user-gpu/vhost-user-gpu.c +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c @@ -930,16 +930,19 @@ vg_handle_ctrl(VuDev *dev, int qidx) if (len != sizeof(cmd->cmd_hdr)) { g_warning("%s: command size incorrect %zu vs %zu\n", __func__, len, sizeof(cmd->cmd_hdr)); - } - - virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); - g_debug("%d %s\n", cmd->cmd_hdr.type, - vg_cmd_to_string(cmd->cmd_hdr.type)); - - if (vg->virgl) { - vg_virgl_process_cmd(vg, cmd); + memset(&cmd->cmd_hdr, 0, sizeof(cmd->cmd_hdr)); + vg_ctrl_response_nodata( + vg, cmd, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER); } else { - vg_process_cmd(vg, cmd); + virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); + g_debug("%d %s\n", cmd->cmd_hdr.type, + vg_cmd_to_string(cmd->cmd_hdr.type)); + + if (vg->virgl) { + vg_virgl_process_cmd(vg, cmd); + } else { + vg_process_cmd(vg, cmd); + } } if (cmd->state != VG_CMD_STATE_FINISHED) { diff --git a/contrib/vhost-user-gpu/vugpu.h b/contrib/vhost-user-gpu/vugpu.h index 2374eb90cb..aaf2870cb2 100644 --- a/contrib/vhost-user-gpu/vugpu.h +++ b/contrib/vhost-user-gpu/vugpu.h @@ -179,6 +179,7 @@ struct virtio_gpu_ctrl_command { if (vugpufillcmd_s_ != sizeof(out)) { \ g_critical("%s: command size incorrect %zu vs %zu", \ __func__, vugpufillcmd_s_, sizeof(out)); \ + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; \ return; \ } \ } while (0) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 2f60c72078..f965defa6b 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -315,6 +315,9 @@ struct VirtIOGPURutabaga { qemu_log_mask(LOG_GUEST_ERROR, \ "%s: command size incorrect %zu vs %zu\n", \ __func__, virtiogpufillcmd_s_, sizeof(out)); \ + memset(&out, 0, sizeof(out)); \ + virtio_gpu_ctrl_response_nodata( \ + g, cmd, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER); \ return; \ } \ } while (0) From d513c644b89361ab645a50a627a1d846aefc3eb2 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 3 Aug 2026 17:45:25 +0900 Subject: [PATCH 038/627] hw/display/virtio-gpu: Always reject invalid scanout bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio-gpu does not consistently check scanout bounds with wraparound handling. In the unchecked virgl SET_SCANOUT path, guest dimensions reach qemu_console_resize(), qemu_create_displaysurface(), and ultimately qemu_pixman_image_new_shareable(..., &error_abort), so an invalid rectangle can terminate QEMU. Implement a check with proper wraparound handling and apply it consistently. Fixes: 9d9e152136bd ("virtio-gpu: add 3d mode and virgl rendering support.") Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob") Fixes: 7c092f17ccee ("virtio-gpu: Handle resource blob commands") Fixes: 1dcc6adbc168 ("gfxstream + rutabaga: add initial support for gfxstream") Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-ID: <20260803-scanout-v1-1-c9831dafdab2@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu-rutabaga.c | 6 ++++++ hw/display/virtio-gpu-virgl.c | 20 ++++++++---------- hw/display/virtio-gpu.c | 36 +++++++++++++++++++------------- include/hw/virtio/virtio-gpu.h | 5 +++++ 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c index e28aad94ee..a054f8117f 100644 --- a/hw/display/virtio-gpu-rutabaga.c +++ b/hw/display/virtio-gpu-rutabaga.c @@ -315,6 +315,12 @@ rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) res = virtio_gpu_find_resource(g, ss.resource_id); CHECK(res, cmd); + if (!virtio_gpu_check_scanout_bounds(ss.scanout_id, ss.resource_id, + res->width, res->height, &ss.r, + &cmd->error)) { + return; + } + if (!res->image) { pixman_format_code_t pformat; pformat = virtio_gpu_get_pixman_format(res->format); diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index d9e5b01104..6e298f997d 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -560,7 +560,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, } g->parent_obj.enable = 1; - if (ss.resource_id && ss.r.width && ss.r.height) { + if (ss.resource_id) { struct virgl_renderer_resource_info info; void *d3d_tex2d = NULL; @@ -581,6 +581,11 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; return; } + if (!virtio_gpu_check_scanout_bounds(ss.scanout_id, ss.resource_id, + info.width, info.height, &ss.r, + &cmd->error)) { + return; + } qemu_console_resize(g->parent_obj.scanout[ss.scanout_id].con, ss.r.width, ss.r.height); virgl_renderer_force_ctx_0(); @@ -987,16 +992,9 @@ static void virgl_cmd_set_scanout_blob(VirtIOGPU *g, return; } - if (ss.width < 16 || - ss.height < 16 || - ss.r.x + ss.r.width > ss.width || - ss.r.y + ss.r.height > ss.height) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" - " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n", - __func__, ss.scanout_id, ss.resource_id, - ss.r.x, ss.r.y, ss.r.width, ss.r.height, - ss.width, ss.height); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + if (!virtio_gpu_check_scanout_bounds(ss.scanout_id, ss.resource_id, + ss.width, ss.height, &ss.r, + &cmd->error)) { return; } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 51592b49c2..c15d4b527d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -633,6 +633,26 @@ static uint32_t virtio_gpu_format_bytes_pp(pixman_format_code_t format) return DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8); } +bool virtio_gpu_check_scanout_bounds(uint32_t scanout_id, uint32_t resource_id, + uint32_t width, uint32_t height, + const struct virtio_gpu_rect *r, + uint32_t *error) +{ + if (r->width < 16 || + r->height < 16 || + (uint64_t)r->x + r->width > width || + (uint64_t)r->y + r->height > height) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" + " resource %d, fb %d %d, rect (%d,%d)+%d,%d\n", + __func__, scanout_id, resource_id, width, height, + r->x, r->y, r->width, r->height); + *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return false; + } + + return true; +} + static bool virtio_gpu_do_set_scanout(VirtIOGPU *g, uint32_t scanout_id, struct virtio_gpu_framebuffer *fb, @@ -646,20 +666,8 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g, scanout = &g->parent_obj.scanout[scanout_id]; - if (r->x > fb->width || - r->y > fb->height || - r->width < 16 || - r->height < 16 || - r->width > fb->width || - r->height > fb->height || - r->x + r->width > fb->width || - r->y + r->height > fb->height) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for" - " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n", - __func__, scanout_id, res->resource_id, - r->x, r->y, r->width, r->height, - fb->width, fb->height); - *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + if (!virtio_gpu_check_scanout_bounds(scanout_id, res->resource_id, + fb->width, fb->height, r, error)) { return false; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index f965defa6b..220231ec9d 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -366,6 +366,11 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id); +bool virtio_gpu_check_scanout_bounds(uint32_t scanout_id, uint32_t resource_id, + uint32_t width, uint32_t height, + const struct virtio_gpu_rect *r, + uint32_t *error); + /** * virtio_gpu_scanout_blob_to_fb() - fill out fb based on scanout data * fb: the frame-buffer descriptor to fill out From 5ce01c92389a422389898df481ed441a80ece3c4 Mon Sep 17 00:00:00 2001 From: Bin Guo Date: Mon, 3 Aug 2026 16:21:58 +0800 Subject: [PATCH 039/627] hw/display/virtio-gpu: Unmap DMA regions on reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_gpu_reset() freed in-flight commands without unmapping the DMA regions acquired by virtqueue_pop(). Call virtqueue_detach_element() before g_free() in both drain loops. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3467 Cc: qemu-stable@nongnu.org Signed-off-by: Bin Guo Reviewed-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260803082158.62998-1-guobin@linux.alibaba.com> --- hw/display/virtio-gpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index c15d4b527d..fbb6fec7a0 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1725,12 +1725,14 @@ void virtio_gpu_reset(VirtIODevice *vdev) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd = QTAILQ_FIRST(&g->cmdq); QTAILQ_REMOVE(&g->cmdq, cmd, next); + virtqueue_detach_element(cmd->vq, &cmd->elem, 0); g_free(cmd); } while (!QTAILQ_EMPTY(&g->fenceq)) { cmd = QTAILQ_FIRST(&g->fenceq); QTAILQ_REMOVE(&g->fenceq, cmd, next); + virtqueue_detach_element(cmd->vq, &cmd->elem, 0); g->inflight--; g_free(cmd); } From dd272c8c87f165d41c945946242c5c8619e7122f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 31 Jul 2026 17:50:01 +0200 Subject: [PATCH 040/627] qapi/dump: add allowed-by-guest feature to win-dmp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1c0e259c5a35 ("dump: make win_dump_available() check vmcoreinfo for a Windows dump header") changed two things in a way that is visible to QMP clients but not to introspection: query-dump-guest-memory-capability now lists win-dmp only for a guest that has published a Windows dump header through the vmcoreinfo device, and dump-guest-memory, which shares win_dump_available(), rejects the format otherwise. Before that, both accepted win-dmp on any x86 machine. A client that wants to select win-dmp automatically therefore cannot trust the capability query on its own: on an older QEMU it reports win-dmp for every x86 guest, Linux ones included, where the resulting dump is useless. libvirt ran into exactly this while picking a format for on_crash and watchdog triggered dumps, and has no way to tell the two behaviours apart. Add an 'allowed-by-guest' feature to the win-dmp member of DumpGuestMemoryFormat so the fixed behaviour becomes discoverable. DumpGuestMemoryFormat is reachable from both query-dump-guest-memory-capability's return type and dump-guest-memory's arguments, so a single flag covers both halves of the change. Where the feature is absent, a reported win-dmp says nothing about the guest, and a client that needs the dump to be loadable afterwards should fall back to elf. CC: Eric Blake CC: Markus Armbruster CC: "Marc-André Lureau" Suggested-by: Daniel P. Berrangé Signed-off-by: Denis V. Lunev Reviewed-by: Daniel P. Berrangé Reviewed-by: Marc-André Lureau Message-ID: <20260731155001.1204103-1-den@openvz.org> --- qapi/dump.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/qapi/dump.json b/qapi/dump.json index 726b520870..690f3963fe 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -38,6 +38,13 @@ # @win-dmp: Windows full crashdump format, can be used instead of ELF # converting (since 2.13) # +# Features: +# +# @allowed-by-guest: If present, @win-dmp is listed by +# `query-dump-guest-memory-capability`, and accepted by +# `dump-guest-memory`, only when the guest has published a Windows +# dump header through the vmcoreinfo device (since 11.1) +# # Since: 2.0 ## { 'enum': 'DumpGuestMemoryFormat', @@ -45,7 +52,7 @@ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy', 'kdump-raw-zlib', 'kdump-raw-lzo', 'kdump-raw-snappy', - 'win-dmp' ] } + { 'name': 'win-dmp', 'features': ['allowed-by-guest'] } ] } ## # @dump-guest-memory: From 9232220004434db1f3be5b2c8b1bba935b043acd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 4 Aug 2026 12:54:14 -0400 Subject: [PATCH 041/627] gitlab: disable provenance attestations to work around CI bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU's CI pipeline involves building container images that will be used to run builds and tests. A recent Docker change triggered the following error: $ docker push "$TAG" ... error from registry: blob unknown to registry - sha256:4401f6f779caf8841cafd5f483e642fcac56a23a4e4a59523231e101c890dad9 https://gitlab.com/qemu-project/qemu/-/jobs/15701875927#L2372 This happens because Docker now pushes out-of-order and the GitLab Container Registry rejects due to an unknown reference: https://forum.gitlab.com/t/started-yesterday-docker-push-error-from-registry-blob-unknown-to-registry/134733/5 It is unclear at this point whether GitLab will modify the behavior of Container Registry or whether Docker will ship a fix. The current workaround is to disable the provenance attestation that is involved in this issue. QEMU's CI pipeline container images are used internally for testing and are not widely distributed. Provenance attestation can be disabled as there are no external consumers of these images. Expect to revert this commit in the future when GitLab or Docker have released their own fixes. Cc: Alex Bennée Cc: Daniel P. Berrangé Cc: Thomas Huth Reviewed-by: Daniel P. Berrangé Message-ID: <20260804165414.480435-1-stefanha@redhat.com> Signed-off-by: Stefan Hajnoczi --- .gitlab-ci.d/container-template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml index 8c7311cca5..88317d650e 100644 --- a/.gitlab-ci.d/container-template.yml +++ b/.gitlab-ci.d/container-template.yml @@ -14,7 +14,7 @@ - echo "TAG:$TAG" - echo "COMMON_TAG:$COMMON_TAG" - docker build --tag "$TAG" --cache-from "$TAG" --cache-from "$COMMON_TAG" - --build-arg BUILDKIT_INLINE_CACHE=1 + --build-arg BUILDKIT_INLINE_CACHE=1 --provenance=false -f "tests/docker/dockerfiles/$NAME.docker" "." - docker push "$TAG" after_script: From 3e3ccab106f879b1512f8e0d51a827dd4de30e22 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 4 Aug 2026 15:36:08 -0400 Subject: [PATCH 042/627] Update version for v11.1.0-rc3 release Signed-off-by: Stefan Hajnoczi --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5399c18e4a..63d29a3de9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -11.0.92 +11.0.93 From 0177efb9b75891717c45667e20efe6d6e64f7c82 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 24 Jul 2026 10:18:44 -0700 Subject: [PATCH 043/627] target/hexagon: accept valid packets rejected by check has_valid_slot_assignment() rejected any packet with two instructions assigned to the same slot. That is too strict. When a memory instruction is encoded before a slot-flexible instruction in a packet, the descending slot assignment places the memory op in slot 1 and the other in slot 0, then the "mem insns to slot 0" fixup moves the memory op to slot 0 as well, leaving both in slot 0. Such a packet is valid and executes correctly, but the uniqueness test flagged it as HEX_CAUSE_INVALID_PACKET, raising SIGILL in linux-user and a precise exception in system mode. For example this packet, with the load encoded first, was wrongly rejected: { r6 = memw(r3+#-4) r7 = #0x4ae6 } Replace the uniqueness test with a slot-exhaustion check: walk the instructions in encoding order handing out slots in strictly decreasing order and fail only if an instruction has no valid slot at or below the running slot. This accepts packets that legally share a slot while still rejecting genuinely unassignable packets, such as a memory instruction grouped with a duplex, or a load followed by an instruction that requires a high slot. Reviewed-by: Matheus Tavares Bernardino Signed-off-by: Brian Cain --- target/hexagon/decode.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 6eddcca26e..e6bb7733be 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -549,21 +549,35 @@ static bool decode_parsebits_is_loopend(uint32_t encoding32) return bits == 0x2; } +/* + * Check that the packet's instructions can be grouped into slots: walk them + * in encoding order handing out slots in strictly decreasing order, and fail + * if an instruction has no valid slot at or below the running slot. Two + * instructions may legally share a slot, so this does not require unique + * slots, only that every instruction fits. + */ static bool has_valid_slot_assignment(Packet *pkt) { - int used_slots = 0; - for (int i = 0; i < pkt->num_insns; i++) { - int slot_mask; - Insn *insn = &pkt->insn[i]; - if (decode_opcode_ends_loop(insn->opcode)) { + int i; + int slot = 3; + + for (i = 0; i < pkt->num_insns; i++) { + SlotMask valid_slots; + if (decode_opcode_ends_loop(pkt->insn[i].opcode)) { /* We overload slot 0 for endloop. */ continue; } - slot_mask = 1 << insn->slot; - if (used_slots & slot_mask) { + if (slot < 0) { return false; } - used_slots |= slot_mask; + valid_slots = get_valid_slots(pkt, i); + while (!(valid_slots & (1 << slot))) { + if (slot <= 0) { + return false; + } + slot--; + } + slot--; } return true; } From d2504d4cea329dcec69af4d590cbaa490c409724 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 24 Jul 2026 10:18:45 -0700 Subject: [PATCH 044/627] tests/tcg/hexagon: add slot-assignment tests valid-slots: packets that legally share a slot and were wrongly rejected before the fix (load and transfer, load encoded first; dczeroa packed last with three transfers). invalid-slots: unassignable packets that must still be rejected: store + duplex, load + indirect jump, three logical ops competing for slots 2 and 3, and five ops for four slots. Reviewed-by: Matheus Tavares Bernardino Signed-off-by: Brian Cain --- tests/tcg/hexagon/Makefile.target | 1 + tests/tcg/hexagon/invalid-slots.c | 72 +++++++++++++++++++++++++++++++ tests/tcg/hexagon/valid-slots.c | 62 ++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 tests/tcg/hexagon/valid-slots.c diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index a2a0ffc69b..80e56f7d05 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -51,6 +51,7 @@ HEX_TESTS += scatter_gather HEX_TESTS += hvx_misc HEX_TESTS += hvx_histogram HEX_TESTS += invalid-slots +HEX_TESTS += valid-slots HEX_TESTS += invalid-encoding HEX_TESTS += multiple-writes HEX_TESTS += unaligned_pc diff --git a/tests/tcg/hexagon/invalid-slots.c b/tests/tcg/hexagon/invalid-slots.c index 607027f314..f2dace2e54 100644 --- a/tests/tcg/hexagon/invalid-slots.c +++ b/tests/tcg/hexagon/invalid-slots.c @@ -55,6 +55,75 @@ static int test_invalid_slots(void) return sig; } +/* Load then indirect jump, load encoded first: no high slot left for jump. */ +static int test_invalid_slots_highslot(void) +{ + int sig; + + asm volatile( + "r0 = #0\n" + "r1 = ##1f\n" + "memw(%1) = r1\n" + "r3 = #mem\n" + ".word 0x91834006\n" /* { r6 = memw(r3+#0); */ + ".word 0x529fc000\n" /* jumpr r31 } */ + "1:\n" + "%0 = r0\n" + : "=r"(sig) + : "r"(&resume_pc) + : "r0", "r1", "r3", "r6", "memory"); + + return sig; +} + +/* + * Three predicate-logical ops: each is restricted to slots 2 and 3, so the + * fourth-and-fifth-slot-free packet still has only two slots for three ops. + * No change-of-flow is involved, so the only reason to reject it is the slot + * conflict. + */ +static int test_invalid_slots_crslot23(void) +{ + int sig; + + asm volatile( + "r0 = #0\n" + "r1 = ##1f\n" + "memw(%1) = r1\n" + ".word 0x6b024100\n" /* { p0 = and(p1, p2); */ + ".word 0x6b224103\n" /* p3 = or(p1, p2); */ + ".word 0x6b42c301\n" /* p1 = xor(p2, p3) } */ + "1:\n" + "%0 = r0\n" + : "=r"(sig) + : "r"(&resume_pc) + : "r0", "r1", "p0", "p1", "p3", "memory"); + + return sig; +} + +/* Three transfers plus a duplex: five ops for four slots. */ +static int test_invalid_slots_five(void) +{ + int sig; + + asm volatile( + "r0 = #0\n" + "r1 = ##1f\n" + "memw(%1) = r1\n" + ".word 0x78004020\n" /* { r0 = #1; */ + ".word 0x78004041\n" /* r1 = #2; */ + ".word 0x78004062\n" /* r2 = #3; */ + ".word 0x28452856\n" /* r5 = #4; r6 = #5 } */ + "1:\n" + "%0 = r0\n" + : "=r"(sig) + : "r"(&resume_pc) + : "r0", "r1", "r2", "r5", "r6", "memory"); + + return sig; +} + int main() { struct sigaction act; @@ -65,6 +134,9 @@ int main() assert(sigaction(SIGILL, &act, NULL) == 0); assert(test_invalid_slots() == SIGILL); + assert(test_invalid_slots_highslot() == SIGILL); + assert(test_invalid_slots_crslot23() == SIGILL); + assert(test_invalid_slots_five() == SIGILL); puts("PASS"); return EXIT_SUCCESS; diff --git a/tests/tcg/hexagon/valid-slots.c b/tests/tcg/hexagon/valid-slots.c new file mode 100644 index 0000000000..70d9b0b6ac --- /dev/null +++ b/tests/tcg/hexagon/valid-slots.c @@ -0,0 +1,62 @@ +/* + * Regression tests for valid packets that qemu incorrectly rejected as + * invalid. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include + +int err; + +#include "hex_test.h" + +/* volatile to keep the load from being optimized away */ +static volatile int buf[2] = { 0x1234, 0 }; + +/* Load and register transfer in one packet, load encoded first. */ +static int32_t load_imm_pair(void) +{ + int32_t out; + /* { r6 = memw(r3+#-4); r7 = #0x4ae6 } */ + asm volatile( + "{ r3 = %1 }\n\t" + ".word 0x97837fe6\n\t" + ".word 0x7845dcc7\n\t" + "{ %0 = r6 }\n\t" + : "=r"(out) : "r"(&buf[1]) : "r3", "r6", "r7"); + return out; +} + +static int32_t dcbuf[8] __attribute__((aligned(32))); + +/* Slot-0-only op (dczeroa) packed last with three transfers. */ +static void slot0_restricted(int32_t *out) +{ + asm volatile( + "{ %0 = #0x11\n\t" + " %1 = #0x22\n\t" + " %2 = #0x33\n\t" + " dczeroa(%3) }\n\t" + : "=r"(out[0]), "=r"(out[1]), "=r"(out[2]) + : "r"(dcbuf) : "memory"); +} + +int main() +{ + int32_t r[3]; + + check32(load_imm_pair(), 0x1234); + + dcbuf[0] = 0x5a5a5a5a; + slot0_restricted(r); + check32(r[0], 0x11); + check32(r[1], 0x22); + check32(r[2], 0x33); + check32(dcbuf[0], 0); /* dczeroa cleared the line */ + + puts(err ? "FAIL" : "PASS"); + return err; +} From 8f5bf4fa0aa2f5648f016b8265d86d4b05b42307 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 07:02:00 -0700 Subject: [PATCH 045/627] target/hexagon: don't let an idef-parser dest clobber its own source The idef-parser emitters write the destination in place, so when a packet is short-circuited and get_result_gpr() returns hex_gpr[] itself, an instruction naming one register as both source and destination reads back a value it already overwrote. `Rd32=cmpy(Rs32,Rt32):<<1:rnd:sat` with Rs == Rd is an example. Give a source reg that aliases a destination its own copy of the register value. Reviewed-by: Pierrick Bouvier Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_funcs.py | 15 ++++++++ target/hexagon/genptr.c | 11 ++++++ target/hexagon/genptr.h | 1 + target/hexagon/hex_common.py | 12 +++++++ tests/tcg/hexagon/read_write_overlap.c | 47 ++++++++++++++++++++++++++ 5 files changed, 86 insertions(+) diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index 6d5d99cee3..43e6807749 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -75,6 +75,21 @@ def gen_tcg_func(f, tag, regs, imms): f.write(f" int {hex_common.imm_name(immlett)} = insn->immed[{i}];\n") if hex_common.is_idef_parser_enabled(tag): + gpr_operands = [ + hex_common.get_register(tag, regtype, regid) + for regtype, regid in regs + if hex_common.get_register(tag, regtype, regid).may_alias_gpr() + ] + dests = [reg for reg in gpr_operands if reg.is_written()] + for reg in gpr_operands: + if reg.is_written() or not reg.is_read(): + continue + src = reg.reg_tcg() + for dest in dests: + f.write(hex_common.code_fmt(f"""\ + {src} = gen_unalias_gpr_src({src}, {dest.reg_tcg()}); + """)) + declared = [] ## Handle registers for regtype, regid in regs: diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 3f31037709..12813f48bf 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -91,6 +91,17 @@ TCGv get_result_gpr(DisasContext *ctx, int rnum) } } +TCGv gen_unalias_gpr_src(TCGv src, TCGv dst) +{ + if (src != dst) { + return src; + } + + TCGv tmp = tcg_temp_new(); + tcg_gen_mov_tl(tmp, src); + return tmp; +} + static TCGv_i64 get_result_gpr_pair(DisasContext *ctx, int rnum) { TCGv_i64 result = tcg_temp_new_i64(); diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h index 45ee038ca9..5d09677410 100644 --- a/target/hexagon/genptr.h +++ b/target/hexagon/genptr.h @@ -36,6 +36,7 @@ void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, uint32_t slot); TCGv gen_read_reg(TCGv result, int num); TCGv gen_read_preg(TCGv pred, uint8_t num); TCGv get_result_gpr(DisasContext *ctx, int rnum); +TCGv gen_unalias_gpr_src(TCGv src, TCGv dst); TCGv get_result_pred(DisasContext *ctx, int pnum); void gen_pred_write(DisasContext *ctx, int pnum, TCGv val); void gen_set_usr_field(DisasContext *ctx, int field, TCGv val); diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index d91a653c3d..09a025ba13 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -388,6 +388,8 @@ class Register: """)) def idef_arg(self, declared): declared.append(self.reg_tcg()) + def may_alias_gpr(self): + return False def helper_arg(self): return HelperArg( self.helper_proto_type(), @@ -495,6 +497,8 @@ class ReadWrite: return False class GprDest(Register, Single, Dest): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -510,6 +514,8 @@ class GprDest(Register, Single, Dest): """)) class GprSource(Register, Single, OldSource): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -531,6 +537,8 @@ class GprNewSource(Register, Single, NewSource): """)) class GprReadWrite(Register, Single, ReadWrite): + def may_alias_gpr(self): + return True def decl_tcg(self, f, tag, regno): self.decl_reg_num(f, regno) f.write(code_fmt(f"""\ @@ -557,6 +565,8 @@ class GprReadWrite(Register, Single, ReadWrite): """)) class ControlDest(Register, Single, Dest): + def may_alias_gpr(self): + return True def decl_reg_num(self, f, regno): f.write(code_fmt(f"""\ const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_SA0; @@ -593,6 +603,8 @@ class ControlSource(Register, Single, OldSource): """)) class ModifierSource(Register, Single, OldSource): + def may_alias_gpr(self): + return True def decl_reg_num(self, f, regno): f.write(code_fmt(f"""\ const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_M0; diff --git a/tests/tcg/hexagon/read_write_overlap.c b/tests/tcg/hexagon/read_write_overlap.c index 95c54ccd63..7eaf75f545 100644 --- a/tests/tcg/hexagon/read_write_overlap.c +++ b/tests/tcg/hexagon/read_write_overlap.c @@ -115,12 +115,59 @@ static void test_swiz(void) check32(swiz(0x11223344), 0x44332211); } +#define CMPY(NAME, ASM) \ +static inline uint32_t NAME##_rd_eq_rs(uint32_t x, uint32_t y) \ +{ \ + uint32_t res; \ + asm("r7 = %1\n\t" \ + ASM("r7", "%2") "\n\t" \ + "%0 = r7\n\t" \ + : "=r"(res) : "r"(x), "r"(y) : "r7"); \ + return res; \ +} \ +static inline uint32_t NAME##_rd_eq_rt(uint32_t x, uint32_t y) \ +{ \ + uint32_t res; \ + asm("r7 = %2\n\t" \ + ASM("%1", "r7") "\n\t" \ + "%0 = r7\n\t" \ + : "=r"(res) : "r"(x), "r"(y) : "r7"); \ + return res; \ +} + +#define CMPY_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):rnd:sat" +#define CMPY_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "):<<1:rnd:sat" +#define CMPYC_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):rnd:sat" +#define CMPYC_S1_RND_SAT(RS, RT) "r7 = cmpy(" RS "," RT "*):<<1:rnd:sat" + +CMPY(cmpyrs_s0, CMPY_RND_SAT) +CMPY(cmpyrs_s1, CMPY_S1_RND_SAT) +CMPY(cmpyrsc_s0, CMPYC_RND_SAT) +CMPY(cmpyrsc_s1, CMPYC_S1_RND_SAT) + +static void test_cmpy(void) +{ + check32(cmpyrs_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x011b105b); + check32(cmpyrs_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x011b105b); + check32(cmpyrs_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x023520b5); + check32(cmpyrs_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x023520b5); + check32(cmpyrsc_s0_rd_eq_rs(0x32195ce2, 0xef862430), 0x0d0f09e8); + check32(cmpyrsc_s0_rd_eq_rt(0x32195ce2, 0xef862430), 0x0d0f09e8); + check32(cmpyrsc_s1_rd_eq_rs(0x32195ce2, 0xef862430), 0x1a1f13d0); + check32(cmpyrsc_s1_rd_eq_rt(0x32195ce2, 0xef862430), 0x1a1f13d0); + + /* Both halves saturate */ + check32(cmpyrs_s1_rd_eq_rs(0x80008000, 0x80008000), 0x7fff0000); + check32(cmpyrsc_s1_rd_eq_rs(0x7fff8001, 0x80017fff), 0x00008000); +} + int main() { test_insert(); test_insert_rp(); test_asr_r_svw_trun(); test_swiz(); + test_cmpy(); puts(err ? "FAIL" : "PASS"); return err ? EXIT_FAILURE : EXIT_SUCCESS; From bc4681990bb6b065e78e7564cb431e44dd148b88 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 5 Aug 2026 18:23:04 +0200 Subject: [PATCH 046/627] linux-user/sh4: Deliver SIGILL on invalid instruction On invalid instruction, deliver SIGILL rather than crashing the whole process unconditionally. Cc: qemu-stable@nongnu.org Signed-off-by: Mikulas Patocka Reviewed-by: Yoshinori Sato Reviewed-by: Richard Henderson Signed-off-by: Helge Deller --- linux-user/sh4/cpu_loop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c index ee2958d0d9..0815b9c9bf 100644 --- a/linux-user/sh4/cpu_loop.c +++ b/linux-user/sh4/cpu_loop.c @@ -64,6 +64,13 @@ void cpu_loop(CPUSH4State *env) cpu_exec_step_atomic(cs); arch_interrupt = false; break; + case 0x180: + /* Illegal instruction */ + /* fallthrough */ + case 0x1a0: + /* Illegal instruction in delay slot */ + force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); + break; default: fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); From 668d571bf0c2ee4851be2187798f413025647fc3 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 4 Aug 2026 10:59:18 +0200 Subject: [PATCH 047/627] linux-user/sh4: Initialize the FPSCR register on signal On the SH4 architecture, the instructions that perform single precision and double precision floating point operations are encoded in the same way. The bit PR in the FPSCR register determines if the CPU performs single or double operation. According to the ABI, the PR bit must be set at function entry and function exit. GCC generates code that flips this bit as needed during function execution. If we get a signal, we must set the PR bit, so that the signal handler finds the bit in the expected state. Qemu lacked this logic, so that if the signal interrupts single-precision floating point calculation, the PR bit would be incorrectly clear at signal handler entry. If the signal handler performed some floating-point calculation, it would get incorrect result. This patch fixes the bug, by initializing the FPSCR register at signal entry. Note that we initialize the whole register, because the Linux kernel initializes the whole register too. Cc: qemu-stable@nongnu.org Signed-off-by: Mikulas Patocka Reviewed-by: Yoshinori Sato Signed-off-by: Helge Deller --- linux-user/sh4/signal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 00290d6e40..7f246e750d 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -206,6 +206,8 @@ void setup_frame(int sig, struct target_sigaction *ka, __put_user(set->sig[i + 1], &frame->extramask[i]); } + regs->fpscr = FPSCR_PR; + /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa_flags & TARGET_SA_RESTORER) { @@ -258,6 +260,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); } + regs->fpscr = FPSCR_PR; + /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa_flags & TARGET_SA_RESTORER) { From f7ad7b1f8c8148f39bc1f2c984bfc7b7c9c59041 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 3 Aug 2026 21:38:32 +0200 Subject: [PATCH 048/627] linux-user/sh4: Fix crashes on signal delivery in conditional delay slot If we get a signal in the delay slot, we must roll-back the PC to the jump instruction. This was already fixed by the commit 3b894b699c9a ("linux-user/sh4: Fix crashes on signal delivery"), however this fix omits a test for TB_FLAG_DELAY_SLOT_COND. TB_FLAG_DELAY_SLOT_COND is set by the conditional delayed branches bf/s and bt/s. Qemu did not roll-back the PC in this case, resulting in incorrect program execution. This patch fixes it. Cc: qemu-stable@nongnu.org Signed-off-by: Mikulas Patocka Reviewed-by: Yoshinori Sato Signed-off-by: Helge Deller --- linux-user/sh4/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 7f246e750d..047174ac8f 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -109,7 +109,7 @@ static void unwind_gusa(CPUSH4State *regs) the SP, otherwise we would be pushing the signal context to invalid memory. */ regs->gregs[15] = regs->gregs[1]; - } else if (regs->flags & TB_FLAG_DELAY_SLOT) { + } else if (regs->flags & (TB_FLAG_DELAY_SLOT | TB_FLAG_DELAY_SLOT_COND)) { /* If we are in a delay slot, push the previous instruction. */ regs->pc -= 2; } From 4713988da1c3ed7150014c87c2429d7a940b77c8 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:16:05 -0400 Subject: [PATCH 049/627] linux-user: implement mount_setattr(2) mount_setattr() was in the syscall tables but had no implementation, so guests always got -ENOSYS. systemd uses it when setting up per-unit credential mounts, which fails the affected units with EXIT_CREDENTIALS. struct mount_attr is an extensible struct like open_how, so handle it the same way openat2() does: reject sizes smaller than the ver0 struct and require any unknown trailing bytes to be zero. All of its fields are 64-bit, and the MOUNT_ATTR_* and MS_* propagation values are identical on every target, so only the byte order needs fixing up. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/strace.list | 3 +++ linux-user/syscall.c | 44 +++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 13 ++++++++++++ 3 files changed, 60 insertions(+) diff --git a/linux-user/strace.list b/linux-user/strace.list index 25ace05187..e952f15d20 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1737,3 +1737,6 @@ #ifdef TARGET_NR_fspick { TARGET_NR_fspick, "fspick", "%s(%d,%s,%d)", NULL, NULL }, #endif +#ifdef TARGET_NR_mount_setattr +{ TARGET_NR_mount_setattr, "mount_setattr", "%s(%d,%s,%d,%p,%d)", NULL, NULL }, +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dc028686f4..cfa68dfbdb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9735,6 +9735,13 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname, int, __to_dfd, const char *, __to_pathname, unsigned int, flag) #endif +#if defined(TARGET_NR_mount_setattr) && defined(__NR_mount_setattr) +#define __NR_sys_mount_setattr __NR_mount_setattr +_syscall5(int, sys_mount_setattr, int, dfd, const char *, path, + unsigned int, flags, struct mount_attr_ver0 *, uattr, + size_t, usize) +#endif + #if defined(TARGET_NR_fsopen) && defined(__NR_fsopen) #define __NR_sys_fsopen __NR_fsopen _syscall2(int, sys_fsopen, const char *, fs_name, unsigned int, flags); @@ -14480,6 +14487,43 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return do_map_shadow_stack(cpu_env, arg1, arg2, arg3); #endif +#if defined(TARGET_NR_mount_setattr) && defined(__NR_mount_setattr) + case TARGET_NR_mount_setattr: + { + struct mount_attr_ver0 attr = {}; + abi_ulong usize = arg5; + + if (usize < sizeof(struct target_mount_attr_ver0)) { + return -TARGET_EINVAL; + } + ret = copy_struct_from_user(&attr, sizeof(attr), arg4, usize); + if (ret) { + if (ret == -TARGET_E2BIG) { + qemu_log_mask(LOG_UNIMP, + "Unimplemented mount_setattr mount_attr " + "size: " TARGET_ABI_FMT_lu "\n", usize); + } + return ret; + } + /* + * MOUNT_ATTR_* and the MS_* propagation flags have the same + * values on all targets, so only byte order needs fixing up. + */ + attr.attr_set = tswap64(attr.attr_set); + attr.attr_clr = tswap64(attr.attr_clr); + attr.propagation = tswap64(attr.propagation); + attr.userns_fd = tswap64(attr.userns_fd); + + p = lock_user_string(arg2); + if (!p) { + return -TARGET_EFAULT; + } + ret = get_errno(sys_mount_setattr(arg1, p, arg3, &attr, + sizeof(attr))); + unlock_user(p, arg2, 0); + } + return ret; +#endif #if defined(TARGET_NR_fsopen) && defined(__NR_fsopen) case TARGET_NR_fsopen: { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e033c7db34..e28853c93b 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2770,6 +2770,19 @@ struct target_open_how_ver0 { abi_ullong mode; abi_ullong resolve; }; +/* from kernel's include/uapi/linux/mount.h */ +struct mount_attr_ver0 { + uint64_t attr_set; + uint64_t attr_clr; + uint64_t propagation; + uint64_t userns_fd; +}; +struct target_mount_attr_ver0 { + abi_ullong attr_set; + abi_ullong attr_clr; + abi_ullong propagation; + abi_ullong userns_fd; +}; #ifndef RESOLVE_NO_MAGICLINKS #define RESOLVE_NO_MAGICLINKS 0x02 #endif From 01b4e06b5225787139dae760e8b4fe0c39e5c04d Mon Sep 17 00:00:00 2001 From: Saul Freedman Date: Sun, 14 Jun 2026 23:33:38 -0400 Subject: [PATCH 050/627] target/i386/kvm: Fix CET SSP MSR read feature check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kvm_get_msrs() adds U_CET and S_CET when CET shadow stacks or IBT are enabled, but it checks FEAT_7_0_EDX with the ECX-defined CPUID_7_0_ECX_CET_SHSTK bit before adding the PL0-PL3 SSP MSRs. CPUID_7_0_ECX_CET_SHSTK belongs to FEAT_7_0_ECX. The current check therefore skips MSR_IA32_PL0_SSP through MSR_IA32_PL3_SSP even when guest shadow stacks are enabled. kvm_put_msrs() already uses FEAT_7_0_ECX for the same shadow-stack condition. Use the same feature word in kvm_get_msrs() so QEMU does not restore CET enablement with stale or zero SSP values. Fixes: b6f85c5e4527 ("i386/kvm: Add save/restore support for CET MSRs") Cc: qemu-stable@nongnu.org Signed-off-by: Saul Freedman Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20260615033338.1563854-1-fre3dm4n@gmail.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 4272b6770c..644c45fb0a 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5022,7 +5022,7 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, MSR_IA32_U_CET, 0); kvm_msr_entry_add(cpu, MSR_IA32_S_CET, 0); - if (env->features[FEAT_7_0_EDX] & CPUID_7_0_ECX_CET_SHSTK) { + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_CET_SHSTK) { kvm_msr_entry_add(cpu, MSR_IA32_PL0_SSP, 0); kvm_msr_entry_add(cpu, MSR_IA32_PL1_SSP, 0); kvm_msr_entry_add(cpu, MSR_IA32_PL2_SSP, 0); From 88dfd97b8acfe41cac7304fa1b6034952f046d1d Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:23:29 -0400 Subject: [PATCH 051/627] linux-user: support writing floating-point registers to a core dump Write an NT_FPREGSET note for targets that opt in: a target_elf.h that defines HAVE_ELF_CORE_FPREGS and target_elf_fpregset_t, and supplies an elf_core_copy_fpregs() beside the existing elf_core_copy_regs(). Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/elfload.c | 19 +++++++++++++++++++ linux-user/loader.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e7c56af8ed..88508deac5 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1887,6 +1887,17 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, size_t sz, off_t offset) bswap_phdr(phdr, 1); } +#ifdef HAVE_ELF_CORE_FPREGS +static void fill_fpregset_note(void *data, CPUState *cpu) +{ + /* Fill locally and copy: note memory is only aligned to 4. */ + target_elf_fpregset_t fpregs = {}; + + elf_core_copy_fpregs(&fpregs, cpu_env(cpu)); + memcpy(data, &fpregs, sizeof(fpregs)); +} +#endif + static void fill_prstatus_note(void *data, CPUState *cpu, int signr) { /* @@ -2166,6 +2177,9 @@ static int elf_core_dump(int signr, const CPUArchState *env) offset += size_note("CORE", ts->info->auxv_len); offset += size_note("CORE", sizeof(struct target_elf_prpsinfo)); offset += size_note("CORE", sizeof(struct target_elf_prstatus)) * cpus; +#ifdef HAVE_ELF_CORE_FPREGS + offset += size_note("CORE", sizeof(target_elf_fpregset_t)) * cpus; +#endif note_size = offset - note_offset; data_offset = TARGET_PAGE_ALIGN(offset); @@ -2222,6 +2236,11 @@ static int elf_core_dump(int signr, const CPUArchState *env) dptr = fill_note(&hptr, NT_PRSTATUS, "CORE", sizeof(struct target_elf_prstatus)); fill_prstatus_note(dptr, cpu_iter, cpu_iter == cpu ? signr : 0); +#ifdef HAVE_ELF_CORE_FPREGS + dptr = fill_note(&hptr, NT_FPREGSET, "CORE", + sizeof(target_elf_fpregset_t)); + fill_fpregset_note(dptr, cpu_iter); +#endif } if (dump_write(fd, header, data_offset) < 0) { diff --git a/linux-user/loader.h b/linux-user/loader.h index da9ad28db5..5ddd140276 100644 --- a/linux-user/loader.h +++ b/linux-user/loader.h @@ -109,6 +109,9 @@ bool init_guest_commpage(void); struct target_elf_gregset_t; void elf_core_copy_regs(struct target_elf_gregset_t *, const CPUArchState *); +/* Only defined by a target whose target_elf.h sets HAVE_ELF_CORE_FPREGS. */ +struct target_elf_fpregset_t; +void elf_core_copy_fpregs(struct target_elf_fpregset_t *, const CPUArchState *); typedef struct { const uint8_t *image; From 2304a655296aa3bf5e416cf5ce33e481fb87f73a Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:15:03 -0400 Subject: [PATCH 052/627] linux-user/alpha: write the floating-point registers to a core dump A guest core carried only the general-purpose registers, so a debugger opening one reported every floating-point register as unavailable -- including the arguments of the function that crashed. Implement HAVE_ELF_CORE_FPREGS for Alpha: define target_elf_fpregset_t to match the kernel's layout ($f0-$f30 plus the control register in the slot $f31 would occupy) and fill it from elf_core_copy_fpregs(). Checked with lldb on a core from a program that faults with live values in $f16 and $f17: both read back correctly, as does the control register. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/alpha/elfload.c | 10 ++++++++++ linux-user/alpha/target_elf.h | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/linux-user/alpha/elfload.c b/linux-user/alpha/elfload.c index 7be9e466b6..c2517516ad 100644 --- a/linux-user/alpha/elfload.c +++ b/linux-user/alpha/elfload.c @@ -32,3 +32,13 @@ const char *get_elf_cpu_model(uint32_t eflags) { return "ev67"; } + +void elf_core_copy_fpregs(target_elf_fpregset_t *r, const CPUAlphaState *env) +{ + int i; + + for (i = 0; i < 31; i++) { + r->fpr[i] = tswap64(env->fir[i]); + } + r->fpcr = tswap64(cpu_alpha_load_fpcr((CPUAlphaState *)env)); +} diff --git a/linux-user/alpha/target_elf.h b/linux-user/alpha/target_elf.h index dd90c6f783..5efe7f3174 100644 --- a/linux-user/alpha/target_elf.h +++ b/linux-user/alpha/target_elf.h @@ -19,6 +19,17 @@ * r0-r30 at indices 0-30, pc at 31, ps at 32. * r31 (hardwired zero) is not stored; pc occupies index 31. */ +/* + * The floating-point note holds $f0 through $f30 and then the control + * register in the slot $f31 would occupy; $f31 reads as zero. + */ +#define HAVE_ELF_CORE_FPREGS 1 + +typedef struct target_elf_fpregset_t { + uint64_t fpr[31]; /* $f0-$f30 */ + uint64_t fpcr; /* the slot for $f31 */ +} target_elf_fpregset_t; + typedef struct target_elf_gregset_t { abi_ulong regs[31]; /* integer registers r0-r30 [0..30] */ abi_ulong pc; /* program counter [31] */ From bc22871fc0146f3cf6f4bbef9b6cdef16d1643f5 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:15:04 -0400 Subject: [PATCH 053/627] linux-user/mips: write the floating-point registers to a core dump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write an NT_FPREGSET note for MIPS and MIPS64, matching the kernel's elf_fpregset_t layout (ELF_NFPREG = 33): fpr[0..31] hold f0-f31, and fcsr occupies the low 32 bits of slot 32. The pad field rounds the struct to 33 × 8 bytes = 264 bytes. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/mips/elfload.c | 8 ++++++++ linux-user/mips/target_elf.h | 13 +++++++++++++ linux-user/mips64/target_elf.h | 13 +++++++++++++ 3 files changed, 34 insertions(+) diff --git a/linux-user/mips/elfload.c b/linux-user/mips/elfload.c index ce2c4514f3..1d62ae0a4d 100644 --- a/linux-user/mips/elfload.c +++ b/linux-user/mips/elfload.c @@ -130,6 +130,14 @@ const char *get_elf_base_platform(CPUState *cs) #undef MATCH_PLATFORM_INSN +void elf_core_copy_fpregs(target_elf_fpregset_t *r, const CPUMIPSState *env) +{ + for (int i = 0; i < 32; i++) { + r->fpr[i] = tswap64(env->active_fpu.fpr[i].d); + } + r->fcsr = tswap32(env->active_fpu.fcr31); +} + /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs. */ #ifndef TARGET_MIPS64 void elf_core_copy_regs(target_elf_gregset_t *r, const CPUMIPSState *env) diff --git a/linux-user/mips/target_elf.h b/linux-user/mips/target_elf.h index 157306f7a0..426f905d3a 100644 --- a/linux-user/mips/target_elf.h +++ b/linux-user/mips/target_elf.h @@ -26,4 +26,17 @@ typedef struct target_elf_gregset_t { }; } target_elf_gregset_t; +#define HAVE_ELF_CORE_FPREGS 1 + +/* + * Matches the kernel's elf_fpregset_t (ELF_NFPREG = 33): + * fpr[0..31] hold f0-f31; fcsr occupies the low 32 bits of slot 32. + * pad rounds the struct to 33 × 8 bytes = 264 bytes. + */ +typedef struct target_elf_fpregset_t { + uint64_t fpr[32]; + uint32_t fcsr; + uint32_t pad; +} target_elf_fpregset_t; + #endif diff --git a/linux-user/mips64/target_elf.h b/linux-user/mips64/target_elf.h index 061471a0f1..efb5d97563 100644 --- a/linux-user/mips64/target_elf.h +++ b/linux-user/mips64/target_elf.h @@ -32,4 +32,17 @@ typedef struct target_elf_gregset_t { }; } target_elf_gregset_t; +#define HAVE_ELF_CORE_FPREGS 1 + +/* + * Matches the kernel's elf_fpregset_t (ELF_NFPREG = 33): + * fpr[0..31] hold f0-f31; fcsr occupies the low 32 bits of slot 32. + * pad rounds the struct to 33 × 8 bytes = 264 bytes. + */ +typedef struct target_elf_fpregset_t { + uint64_t fpr[32]; + uint32_t fcsr; + uint32_t pad; +} target_elf_fpregset_t; + #endif From 474ad686693c8faeba34fd9e46ec81c98bb015ab Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:15:05 -0400 Subject: [PATCH 054/627] linux-user/hppa: write the floating-point registers to a core dump Write an NT_FPREGSET note for HPPA, matching the kernel's elf_fpregset_t layout (ELF_NFPREG = 32): fr0-fr31 as 64-bit values. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/hppa/elfload.c | 7 +++++++ linux-user/hppa/target_elf.h | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/linux-user/hppa/elfload.c b/linux-user/hppa/elfload.c index ff4301b2ed..dd5b0b380e 100644 --- a/linux-user/hppa/elfload.c +++ b/linux-user/hppa/elfload.c @@ -17,6 +17,13 @@ const char *get_elf_platform(CPUState *cs) return "PARISC"; } +void elf_core_copy_fpregs(target_elf_fpregset_t *r, const CPUArchState *env) +{ + for (int i = 0; i < 32; i++) { + r->fpr[i] = tswap64(env->fr[i]); + } +} + void elf_core_copy_regs(target_elf_gregset_t *r, const CPUArchState *env) { int i; diff --git a/linux-user/hppa/target_elf.h b/linux-user/hppa/target_elf.h index 22547b1437..4357873aff 100644 --- a/linux-user/hppa/target_elf.h +++ b/linux-user/hppa/target_elf.h @@ -39,4 +39,13 @@ typedef struct target_elf_gregset_t { #define STACK_ALIGNMENT 64 #define VDSO_HEADER "vdso.c.inc" +#define HAVE_ELF_CORE_FPREGS 1 + +/* + * Matches the kernel's elf_fpregset_t (ELF_NFPREG = 32): fr0-fr31. + */ +typedef struct target_elf_fpregset_t { + uint64_t fpr[32]; +} target_elf_fpregset_t; + #endif From 0f183237d24daac28b6290b0605cba7b47aa8052 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:15:06 -0400 Subject: [PATCH 055/627] linux-user/riscv: write the floating-point registers to a core dump Write an NT_FPREGSET note for RISC-V, matching struct __riscv_d_ext_state from uapi/asm/ptrace.h: f0-f31 as 64-bit values followed by fcsr. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/riscv/elfload.c | 9 +++++++++ linux-user/riscv/target_elf.h | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/linux-user/riscv/elfload.c b/linux-user/riscv/elfload.c index afe103a631..1bc8beacb1 100644 --- a/linux-user/riscv/elfload.c +++ b/linux-user/riscv/elfload.c @@ -11,6 +11,15 @@ const char *get_elf_cpu_model(uint32_t eflags) return "max"; } +void elf_core_copy_fpregs(target_elf_fpregset_t *r, const CPURISCVState *env) +{ + for (int i = 0; i < 32; i++) { + r->fpr[i] = tswap64(env->fpr[i]); + } + r->fcsr = tswap32(((uint32_t)env->frm << FSR_RD_SHIFT) | + (riscv_cpu_get_fflags((CPURISCVState *)env) << FSR_AEXC_SHIFT)); +} + void elf_core_copy_regs(target_elf_gregset_t *r, const CPURISCVState *env) { r->pc = tswapal(env->pc); diff --git a/linux-user/riscv/target_elf.h b/linux-user/riscv/target_elf.h index 859f726578..185b81a2db 100644 --- a/linux-user/riscv/target_elf.h +++ b/linux-user/riscv/target_elf.h @@ -27,4 +27,15 @@ typedef struct target_elf_gregset_t { abi_ulong regs[31]; } target_elf_gregset_t; +#define HAVE_ELF_CORE_FPREGS 1 + +/* + * Matches struct __riscv_d_ext_state from uapi/asm/ptrace.h: + * f0-f31 as 64-bit values followed by fcsr. + */ +typedef struct target_elf_fpregset_t { + uint64_t fpr[32]; + uint32_t fcsr; +} target_elf_fpregset_t; + #endif From ce276ab1a92cad460930fada1bc2e2e4a96f7595 Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Wed, 5 Aug 2026 13:15:07 -0400 Subject: [PATCH 056/627] linux-user/sh4: write the floating-point registers to a core dump Write an NT_FPREGSET note for SH4, matching struct user_fpu_struct from arch/sh/include/asm/user.h: fr0-fr15, xf0-xf15, fpscr, fpul. Signed-off-by: Matt Turner Reviewed-by: Helge Deller Signed-off-by: Helge Deller --- linux-user/sh4/elfload.c | 10 ++++++++++ linux-user/sh4/target_elf.h | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/linux-user/sh4/elfload.c b/linux-user/sh4/elfload.c index f03ce49e7d..41601626ca 100644 --- a/linux-user/sh4/elfload.c +++ b/linux-user/sh4/elfload.c @@ -52,6 +52,16 @@ abi_ulong get_elf_hwcap(CPUState *cs) return hwcap; } +void elf_core_copy_fpregs(target_elf_fpregset_t *r, const CPUSH4State *env) +{ + for (int i = 0; i < 16; i++) { + r->fpregs[i] = tswap32(env->fregs[i]); + r->xfpregs[i] = tswap32(env->fregs[16 + i]); + } + r->fpscr = tswap32(env->fpscr); + r->fpul = tswap32(env->fpul); +} + void elf_core_copy_regs(target_elf_gregset_t *r, const CPUSH4State *env) { for (int i = 0; i < 16; i++) { diff --git a/linux-user/sh4/target_elf.h b/linux-user/sh4/target_elf.h index 3fcb63d409..5923022036 100644 --- a/linux-user/sh4/target_elf.h +++ b/linux-user/sh4/target_elf.h @@ -25,4 +25,16 @@ typedef struct target_elf_gregset_t { struct target_pt_regs pt; } target_elf_gregset_t; +#define HAVE_ELF_CORE_FPREGS 1 + +/* + * Matches struct user_fpu_struct from arch/sh/include/asm/user.h. + */ +typedef struct target_elf_fpregset_t { + uint32_t fpregs[16]; + uint32_t xfpregs[16]; + uint32_t fpscr; + uint32_t fpul; +} target_elf_fpregset_t; + #endif From aae77f5dddef62da7e1479c257d99d2ab574df56 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 21:17:18 +0200 Subject: [PATCH 057/627] target/s390x: Make PRNO TRNG interruptible fill_buf_random() writes the entire guest-requested amount of random bytes in one go. Since the length is a full 64-bit value, a guest can request several gigabytes and keep the vCPU spinning inside the helper, without a chance to react to interrupts. Do the same thing as HELPER(mvcl): check cpu_loop_exit_requested() at the bottom of the loop, and when a return to the main loop is pending, stop and report partial completion with condition code 3. Reported-by: Christian Borntraeger Fixes: 3dbc5fdacb5a ("target/s390x: support PRNO_TRNG instruction") Cc: qemu-stable@nongnu.org Reviewed-by: Richard Henderson Signed-off-by: Ilya Leoshkevich Reviewed-by: Harald Freudenberger Link: https://lore.kernel.org/qemu-devel/20260714191948.342204-2-iii@linux.ibm.com Signed-off-by: Eric Farman --- target/s390x/tcg/crypto_helper.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 8fe0a22219..6a5dbe1caf 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -16,6 +16,7 @@ #include "qemu/guest-random.h" #include "s390x-internal.h" #include "tcg_s390x.h" +#include "exec/cpu-common.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst-common.h" #include "accel/tcg/cpu-mmu-index.h" @@ -242,8 +243,8 @@ static int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra, return !len ? 0 : 3; } -static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra, - uint64_t *buf_reg, uint64_t *len_reg) +static int fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra, + uint64_t *buf_reg, uint64_t *len_reg) { const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx); uint8_t tmp[256]; @@ -265,7 +266,13 @@ static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra, --*len_reg; } len -= block; + + if (cpu_loop_exit_requested(env_cpu(env))) { + break; + } } + + return len == 0 ? 0 : 3; } uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, @@ -278,6 +285,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, uint8_t subfunc[16] = { 0 }; uint64_t param_addr; MemOpIdx oi; + int cc; switch (type) { case S390_FEAT_TYPE_KMAC: @@ -308,9 +316,13 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, return cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2], &env->regs[r2 + 1], type); case 114: /* CPACF_PRNO_TRNG */ - fill_buf_random(env, mmu_idx, ra, &env->regs[r1], &env->regs[r1 + 1]); - fill_buf_random(env, mmu_idx, ra, &env->regs[r2], &env->regs[r2 + 1]); - break; + cc = fill_buf_random(env, mmu_idx, ra, + &env->regs[r1], &env->regs[r1 + 1]); + if (cc == 0) { + cc = fill_buf_random(env, mmu_idx, ra, + &env->regs[r2], &env->regs[r2 + 1]); + } + return cc; default: /* we don't implement any other subfunction yet */ g_assert_not_reached(); From abe1d893f41d5fcbdabc22f46ec148069a4ef319 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 21:17:19 +0200 Subject: [PATCH 058/627] tests/tcg/s390x: Test PRNO TRNG interruptibility Add a small test that issues a large PRNO TRNG request while a timer is running, and checks that the timer interrupts it several times. Signed-off-by: Ilya Leoshkevich Reviewed-by: Harald Freudenberger Link: https://lore.kernel.org/qemu-devel/20260714191948.342204-3-iii@linux.ibm.com Signed-off-by: Eric Farman --- tests/tcg/s390x/Makefile.target | 1 + tests/tcg/s390x/prno-trng.c | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/tcg/s390x/prno-trng.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 0ca030ded0..48cba4cdfa 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -75,6 +75,7 @@ Z13_TESTS+=vcksm Z13_TESTS+=vstl Z13_TESTS+=vrep Z13_TESTS+=precise-smc-user +Z13_TESTS+=prno-trng $(Z13_TESTS): CFLAGS+=-march=z13 -O2 TESTS+=$(Z13_TESTS) diff --git a/tests/tcg/s390x/prno-trng.c b/tests/tcg/s390x/prno-trng.c new file mode 100644 index 0000000000..43eea5db1d --- /dev/null +++ b/tests/tcg/s390x/prno-trng.c @@ -0,0 +1,67 @@ +/* + * Test that PERFORM RANDOM NUMBER OPERATION TRNG is interruptible. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include +#include +#include +#include +#include +#include + +static unsigned char buf1[16 * 1024 * 1024]; +static unsigned char buf2[16 * 1024 * 1024]; + +static volatile sig_atomic_t interrupted; + +static void sigprof_handler(int sig, siginfo_t *info, void *ucontext) +{ + struct ucontext *uc = ucontext; + unsigned long addr = uc->uc_mcontext.regs.psw.addr; + + if (*(unsigned short *)(addr - 4) == 0xb93c) { + interrupted++; + } +} + +static void prno_trng(void *b1, unsigned long l1, void *b2, unsigned long l2) +{ + register unsigned long r0 asm("r0") = 114; /* TRNG */ + register unsigned long r2 asm("r2") = (unsigned long)b1; + register unsigned long r3 asm("r3") = l1; + register unsigned long r4 asm("r4") = (unsigned long)b2; + register unsigned long r5 asm("r5") = l2; + + asm volatile("0: ppno %[r2],%[r4]\n" /* prno alias for old toolchains */ + " jo 0b" + : [r2] "+r" (r2), [r3] "+r" (r3) + , [r4] "+r" (r4), [r5] "+r" (r5) + : "r" (r0) + : "cc", "memory"); +} + +int main(void) +{ + struct itimerval it = { + .it_interval = { .tv_usec = 10000 }, /* 0.01s */ + .it_value = { .tv_usec = 10000 }, + }; + struct sigaction act = { + .sa_sigaction = sigprof_handler, + .sa_flags = SA_SIGINFO, + }; + int err; + + err = sigaction(SIGPROF, &act, NULL); + assert(err == 0); + err = setitimer(ITIMER_PROF, &it, NULL); + assert(err == 0); + + prno_trng(buf1, sizeof(buf1), buf2, sizeof(buf2)); + printf("interrupted %d times\n", interrupted); + assert(interrupted >= 3); + + return EXIT_SUCCESS; +} From 0103cb1cd175a070f52ed0ca4fe0712c2ba2befc Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 21:02:40 +0200 Subject: [PATCH 059/627] target/s390x: Fix DR/D INT64_MIN / -1 host crash helper_divs32() divides the 64-bit dividend by the 32-bit divisor as a 64-bit host operation, guarding only against a zero divisor. INT64_MIN / -1 therefore overflows the host division before the representability check runs; on hosts that trap this, QEMU is killed with SIGFPE instead of raising the fixed-point-divide exception the guest expects: qemu-s390x: QEMU internal SIGFPE {code=INTDIV, addr=...} helper_divs64() already guards the same case; add the missing check to helper_divs32(). Reported-by: Christian Borntraeger Fixes: b4e2bd3563af ("target-s390: Send signals for divide") Cc: qemu-stable@nongnu.org Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Link: https://lore.kernel.org/qemu-devel/20260714190351.337923-2-iii@linux.ibm.com Signed-off-by: Eric Farman --- target/s390x/tcg/int_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index fbda396f5b..5aedd1405b 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -39,7 +39,8 @@ uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) int32_t b = b64; int64_t q, r; - if (b == 0) { + /* Catch divide by zero, and non-representable quotient (MIN / -1). */ + if (b == 0 || (b == -1 && a == (1ll << 63))) { tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); } From aa5d03bc93514ceed8d94f38dbdf951f6cb19d23 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 21:02:41 +0200 Subject: [PATCH 060/627] tests/tcg/s390x: Test DR overflow (INT64_MIN / -1) Check that DR with a non-representable quotient raises SIGFPE rather than crashing the emulator. Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Link: https://lore.kernel.org/qemu-devel/20260714190351.337923-3-iii@linux.ibm.com Signed-off-by: Eric Farman --- tests/tcg/s390x/div.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/tcg/s390x/div.c b/tests/tcg/s390x/div.c index 6ad9900e08..124c9ecc33 100644 --- a/tests/tcg/s390x/div.c +++ b/tests/tcg/s390x/div.c @@ -1,6 +1,15 @@ #include +#include #include +/* Set asynchronously by the signal handler. */ +static volatile int signum; + +static void signal_handler(int n) +{ + signum = n; +} + static void test_dr(void) { register int32_t r0 asm("r0") = -1; @@ -65,11 +74,39 @@ static void test_dlgr(void) assert(r == 1); } +/* + * The most negative dividend divided by -1 yields a quotient that does not + * fit into 32 bits, so DR must raise a fixed-point-divide exception. + */ +static void test_dr_overflow(void) +{ + struct sigaction act = { .sa_handler = signal_handler }; + register int32_t r0 asm("r0"); + register int32_t r1 asm("r1"); + int32_t b = -1; + int err; + + err = sigaction(SIGFPE, &act, NULL); + assert(err == 0); + signum = -1; + + r0 = 0x80000000; + r1 = 0; + asm volatile("dr %[r0],%[b]" + : [r0] "+r" (r0), [r1] "+r" (r1) + : [b] "r" (b) + : "cc"); + assert(signum == SIGFPE); + + signal(SIGFPE, SIG_DFL); +} + int main(void) { test_dr(); test_dlr(); test_dsgr(); test_dlgr(); + test_dr_overflow(); return 0; } From 4e994ebb01442d90e97e2f94f53f61b1b0b34f62 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 27 Jul 2026 13:50:48 +0200 Subject: [PATCH 061/627] hw/char/sclpconsole-lm: avoid guest triggerable assert If a guest uses incorrect message length it can trigger an assert in process_mdb which kills the guest instead of reporting an error. Fix this by adding the correct length check. Fixes: 6a444f8507 ("s390/sclplmconsole: Add support for SCLP line-mode console") Cc: qemu-stable@nongnu.org Signed-off-by: Christian Borntraeger Reviewed-by: Matthew Rosato Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260727115052.24289-2-borntraeger@linux.ibm.com [farman@linux.ibm.com: Fixed typo in commit message, added qemu-stable] Signed-off-by: Eric Farman --- hw/char/sclpconsole-lm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index 9a16896d22..f6ed282f1b 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -243,7 +243,8 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); len = be16_to_cpu(data->mdb.header.length); - if (len < sizeof(data->mdb.header)) { + if (len < sizeof(data->mdb.header) || + len > be16_to_cpu(data->header.length) - sizeof(EventBufferHeader)) { return SCLP_RC_INCONSISTENT_LENGTHS; } len -= sizeof(data->mdb.header); From df607fd056044e40352a43f0b4422b9a5cb015c8 Mon Sep 17 00:00:00 2001 From: Joshua Daley Date: Mon, 27 Jul 2026 13:50:49 +0200 Subject: [PATCH 062/627] s390x/ipl: validate num_comp against iplb length before iterating In ipl_valid_pv_components(), the upper bound of the for loop, ipib_pv->num_comp, is read from guest memory. Before iterating, verify that its value will not cause a read beyond the end of the IplParameterBlock. Fixes: c3347ed0d2ee42a7 ("s390x: protvirt: Support unpack facility") Cc: qemu-stable@nongnu.org Signed-off-by: Joshua Daley Reviewed-by: Christian Borntraeger Reviewed-by: Matthew Rosato Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260727115052.24289-3-borntraeger@linux.ibm.com [farman@linux.ibm.com: Added qemu-stable] Signed-off-by: Eric Farman --- hw/s390x/ipl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index fac30763df..ef9c063d90 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -124,6 +124,12 @@ static inline bool ipl_valid_pv_components(IplParameterBlock *iplb) return false; } + if (offsetof(IplParameterBlock, pv.components) + + ipib_pv->num_comp * sizeof(IPLBlockPVComp) > + be32_to_cpu(iplb->len)) { + return false; + } + for (i = 0; i < ipib_pv->num_comp; i++) { /* Addr must be 4k aligned */ if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) { From a9f1e84c6b8213fb1bfc664b1ffa1a8d975a69b6 Mon Sep 17 00:00:00 2001 From: Joshua Daley Date: Mon, 27 Jul 2026 13:50:50 +0200 Subject: [PATCH 063/627] pc-bios/s390-ccw: fix out-of-bounds read in iso_get_file_size() In the dir_rem[level] == 0 case, level is decremented, then a virtio_read() is issued on sec_loc[level]. If level is -1, then the 4 bytes before the static sec_loc array are read, and the virtio_read() is issued on that garbage block number. Guard the call to virtio_read() against the value of level to prevent this. Fixes: 869648e87eeb ("pc-bios/s390-ccw: El Torito 16-bit boot image size field workaround") Cc: qemu-stable@nongnu.org Signed-off-by: Joshua Daley Reviewed-by: Christian Borntraeger Reviewed-by: Matthew Rosato Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260727115052.24289-4-borntraeger@linux.ibm.com [farman@linux.ibm.com: Fixed typo on Christian's tag, added qemu-stable] Signed-off-by: Eric Farman --- pc-bios/s390-ccw/bootmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 420ee32eff..ed6e8cbbc7 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -902,7 +902,7 @@ static inline long iso_get_file_size(uint32_t load_rba) if (dir_rem[level] == 0) { /* Nothing remaining */ level--; - if (virtio_read(sec_loc[level], temp)) { + if (level >= 0 && virtio_read(sec_loc[level], temp)) { puts("Failed to read ISO directory"); return -EIO; } From 33909d4ebd5c197626c3142550ee11f4bdb1df48 Mon Sep 17 00:00:00 2001 From: Joshua Daley Date: Mon, 27 Jul 2026 13:50:51 +0200 Subject: [PATCH 064/627] pc-bios/s390-ccw: bounds-check zipl menu entry index before array write menu_get_zipl_boot_index() iterates NUL-separated strings from the zipl stage-2 boot-menu block, passes each to zipl_print_entry() which converts EBCDIC to ASCII and returns atoi(), then writes true into valid_entries[entry]. valid_entries is a MAX_BOOT_ENTRIES element stack array, but entry was never bounds-checked, so a crafted on-disk value could index arbitrarily beyond the array. Fix this in two places: - zipl_print_entry() now validates that the first significant character (after an optional leading space) is a digit. Entries that fail this check return -1 without printing. - menu_get_zipl_boot_index() skips any entry whose index is outside [0, MAX_BOOT_ENTRIES) before writing to valid_entries[]. Fixes: 7385e947fc65 ("pc-bios/s390-ccw: fix non-sequential boot entries (eckd)") Cc: qemu-stable@nongnu.org Signed-off-by: Joshua Daley Reviewed-by: Matthew Rosato Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260727115052.24289-5-borntraeger@linux.ibm.com [farman@linux.ibm.com: Added qemu-stable] Signed-off-by: Eric Farman --- pc-bios/s390-ccw/menu.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index eeaff78f87..b6a9a56d46 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -176,18 +176,24 @@ int menu_get_boot_index(bool *valid_entries) return boot_index; } -/* Returns the entry number that was printed */ +/* Returns the entry number that was printed, or -1 on invalid entry */ static int zipl_print_entry(const char *data, size_t len) { char buf[len + 2]; + const char *p; ebcdic_to_ascii(data, buf, len); buf[len] = '\n'; buf[len + 1] = '\0'; + p = (buf[0] == ' ') ? buf + 1 : buf; + if (!isdigit((unsigned char)*p)) { + return -1; + } + printf("%s", buf); - return buf[0] == ' ' ? atoi(buf + 1) : atoi(buf); + return atoi(p); } int menu_get_zipl_boot_index(const char *menu_data) @@ -216,6 +222,9 @@ int menu_get_zipl_boot_index(const char *menu_data) entry = zipl_print_entry(menu_data, len); menu_data += len + 1; + if (entry < 0 || entry >= MAX_BOOT_ENTRIES) { + continue; + } valid_entries[entry] = true; if (entry == 0) { From a3856a7ba44ba1b740eee7759b03079e2f5f637b Mon Sep 17 00:00:00 2001 From: Joshua Daley Date: Tue, 28 Jul 2026 15:47:04 +0200 Subject: [PATCH 065/627] pc-bios/s390-ccw: bound zipl menu strlen and replace VLA in zipl_print_entry menu_get_zipl_boot_index() calls strlen() on a pointer into the middle of _s2 with no upper bound, so a stage-2 image whose blocks contain no NUL bytes causes strlen() to walk beyond _s2. The resulting length is then used to size a stack VLA in zipl_print_entry(), risking a stack overflow. Fix by: - Implementing strnlen(), a bounded version of strlen(). s390-ccw uses libc from SLOF, which includes strlen() but does not have an implementation of strnlen(), so we must implement our own. - Adding a menu_data_end parameter to menu_get_zipl_boot_index() and replacing both strlen() calls with strnlen() bounded by the remaining buffer space. The loop guard also checks that the pointer has not reached menu_data_end. The function returns 0 (boot default) if somehow menu_data reaches menu_data_end before printing any entries. - Replacing the VLA char buf[len + 2] in zipl_print_entry() with a fixed ZIPL_ENTRY_MAX + 2 (82-byte) buffer and truncating len before use. - Passing s2_end (_s2 + sizeof(_s2)) as menu_data_end at the one call site in eckd_get_boot_menu_index(), so the bound is exactly the end of the buffer. Fixes: f7178910845a ("s390-ccw: print zipl boot menu") Cc: qemu-stable@nongnu.org Signed-off-by: Joshua Daley Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/qemu-devel/20260728134704.2924005-2-jdaley@linux.ibm.com [farman@linux.ibm.com: Per list, add strnlen rationale to commit message and added cc stable] Signed-off-by: Eric Farman --- pc-bios/s390-ccw/bootmap.c | 4 +++- pc-bios/s390-ccw/helper.h | 10 ++++++++++ pc-bios/s390-ccw/menu.c | 29 +++++++++++++++++++++++------ pc-bios/s390-ccw/s390-ccw.h | 2 +- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index ed6e8cbbc7..81512265ce 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -61,6 +61,7 @@ static uint8_t _s2[MAX_SECTOR_SIZE * 3] __attribute__((__aligned__(PAGE_SIZE))); static void *s2_prev_blk = _s2; static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE; static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2; +static void *s2_end = _s2 + sizeof(_s2); static inline int verify_boot_info(BootInfo *bip) { @@ -308,7 +309,8 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr) } } - return menu_get_zipl_boot_index(s2_cur_blk + banner_offset); + return menu_get_zipl_boot_index(s2_cur_blk + banner_offset, + s2_end); } prev_block_nr = cur_block_nr; diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h index 8e3dfcb6d6..d9b7da444a 100644 --- a/pc-bios/s390-ccw/helper.h +++ b/pc-bios/s390-ccw/helper.h @@ -45,4 +45,14 @@ static inline void sleep(unsigned int seconds) } } +static inline size_t strnlen(const char *s, size_t maxlen) +{ + size_t len = 0; + + while (len < maxlen && s[len]) { + len++; + } + return len; +} + #endif diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index b6a9a56d46..9b81154b0e 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -16,6 +16,7 @@ #include "s390-ccw.h" #include "sclp.h" #include "s390-time.h" +#include "helper.h" #define KEYCODE_NO_INP '\0' #define KEYCODE_ESCAPE '\033' @@ -26,6 +27,9 @@ #define ZIPL_TIMEOUT_OFFSET 138 #define ZIPL_FLAG_OFFSET 140 +/* Max printable chars for a zipl boot menu entry */ +#define ZIPL_ENTRY_MAX 80 + #define TOD_CLOCK_MILLISECOND 0x3e8000 #define LOW_CORE_EXTERNAL_INT_ADDR 0x86 @@ -179,9 +183,13 @@ int menu_get_boot_index(bool *valid_entries) /* Returns the entry number that was printed, or -1 on invalid entry */ static int zipl_print_entry(const char *data, size_t len) { - char buf[len + 2]; + char buf[ZIPL_ENTRY_MAX + 2]; const char *p; + if (len > ZIPL_ENTRY_MAX) { + len = ZIPL_ENTRY_MAX; + } + ebcdic_to_ascii(data, buf, len); buf[len] = '\n'; buf[len + 1] = '\0'; @@ -196,7 +204,7 @@ static int zipl_print_entry(const char *data, size_t len) return atoi(p); } -int menu_get_zipl_boot_index(const char *menu_data) +int menu_get_zipl_boot_index(const char *menu_data, const char *menu_data_end) { size_t len; int entry; @@ -212,13 +220,22 @@ int menu_get_zipl_boot_index(const char *menu_data) timeout = zipl_timeout * 1000; } - /* Print banner */ + if (menu_data >= menu_data_end) { + return 0; /* Boot default */ + } + + /* Skip banner */ + len = strnlen(menu_data, menu_data_end - menu_data); + menu_data += len + 1; + if (menu_data >= menu_data_end || !(*menu_data)) { + return 0; /* No entries, boot default */ + } + puts("s390-ccw zIPL Boot Menu\n"); - menu_data += strlen(menu_data) + 1; /* Print entries */ - while (*menu_data) { - len = strlen(menu_data); + while (menu_data < menu_data_end && *menu_data) { + len = strnlen(menu_data, menu_data_end - menu_data); entry = zipl_print_entry(menu_data, len); menu_data += len + 1; diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 1e1f71775e..f6030a6071 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -76,7 +76,7 @@ void jump_to_low_kernel(void); /* menu.c */ void menu_set_parms(uint8_t boot_menu_flag, uint32_t boot_menu_timeout); -int menu_get_zipl_boot_index(const char *menu_data); +int menu_get_zipl_boot_index(const char *menu_data, const char *menu_data_end); bool menu_is_enabled_zipl(void); int menu_get_enum_boot_index(bool *valid_entries); bool menu_is_enabled_enum(void); From c4d9412cdd1c9d1b8b2fcb0e0dbf57ca6286afd7 Mon Sep 17 00:00:00 2001 From: Jared Rossi Date: Tue, 28 Jul 2026 18:30:13 -0400 Subject: [PATCH 066/627] pc-bios/s390-ccw: Fix off-by-one errors with loadparm and boot entries The loadparm may optionally be used to select a boot entry, with the intended range being 0 through 31 inclusive, for a total of 32 entries. Previously, MAX_BOOT_ENTRIES was defined as 31, indicating that it was intended to correspond to the index of the boot entry rather than the count; however, some guards also used MAX_BOOT_ENTRIES as a count of the maximum allowed entries, which resulted in a mismatch between the intended and actual range such that index 31 could never be used in practice. Move the definition of MAX_BOOT_ENTRIES to qipl.h so it is shared and change the value to 32, representing a count of the maximum number of allowed boot entries and allowing the loadparm to accept values 0 through 31 as intended. Update some instances in the netboot code where MAX_BOOT_ENTRIES was used as the max index so that all guards treat MAX_BOOT_ENTRIES as a count across all boot methods. Cc: qemu-stable@nongnu.org Fixes: 806315279d5c ("pc-bios/s390-ccw: Remove panics from ECKD IPL path") Signed-off-by: Jared Rossi Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/qemu-devel/20260728223013.4047042-1-jrossi@linux.ibm.com Signed-off-by: Eric Farman --- include/hw/s390x/ipl/qipl.h | 2 ++ pc-bios/s390-ccw/netmain.c | 11 +++++++---- pc-bios/s390-ccw/s390-ccw.h | 2 -- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h index 8d3c83a80b..b390f2f112 100644 --- a/include/hw/s390x/ipl/qipl.h +++ b/include/hw/s390x/ipl/qipl.h @@ -20,6 +20,8 @@ #define LOADPARM_LEN 8 #define NO_LOADPARM "\0\0\0\0\0\0\0\0" +#define MAX_BOOT_ENTRIES 32 + enum S390IplType { S390_IPL_TYPE_FCP = 0x00, S390_IPL_TYPE_CCW = 0x02, diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index 651cedf6ef..791854fce0 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -40,6 +40,9 @@ #define DEFAULT_BOOT_RETRIES 10 #define DEFAULT_TFTP_RETRIES 20 +/* Index 0 is reserved for default alias, start PXE cfg indices at 1 */ +#define PXECFG_MAX (MAX_BOOT_ENTRIES - 1) + extern char _start[]; #define KERNEL_ADDR ((void *)0L) @@ -381,13 +384,13 @@ static int net_select_and_load_kernel(filename_ip_t *fn_ip, static int net_try_pxelinux_cfg(filename_ip_t *fn_ip) { - struct pl_cfg_entry entries[MAX_BOOT_ENTRIES]; + struct pl_cfg_entry entries[PXECFG_MAX]; int num_ent, def_ent = 0; num_ent = pxelinux_load_parse_cfg(fn_ip, mac, get_uuid(), DEFAULT_TFTP_RETRIES, cfgbuf, sizeof(cfgbuf), - entries, MAX_BOOT_ENTRIES, &def_ent); + entries, PXECFG_MAX, &def_ent); return net_select_and_load_kernel(fn_ip, num_ent, def_ent, entries); } @@ -470,11 +473,11 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip) * a magic comment string. */ if (!strncasecmp("# pxelinux", cfgbuf, 10)) { - struct pl_cfg_entry entries[MAX_BOOT_ENTRIES]; + struct pl_cfg_entry entries[PXECFG_MAX]; int num_ent, def_ent = 0; num_ent = pxelinux_parse_cfg(cfgbuf, sizeof(cfgbuf), entries, - MAX_BOOT_ENTRIES, &def_ent); + PXECFG_MAX, &def_ent); return net_select_and_load_kernel(fn_ip, num_ent, def_ent, entries); } diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index f6030a6071..25aac91d45 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -82,8 +82,6 @@ int menu_get_enum_boot_index(bool *valid_entries); bool menu_is_enabled_enum(void); int menu_get_boot_index(bool *valid_entries); -#define MAX_BOOT_ENTRIES 31 - __attribute__ ((__noreturn__)) static inline void panic(const char *string) { From 2c32c273da6d4ecead76441adf96cb685f31df3c Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 22:29:54 +0200 Subject: [PATCH 067/627] target/s390x/tcg: Set STCK/STCKF condition code after the store STORE CLOCK [FAST] to an inaccessible address aborts QEMU: $ qemu-s390x ./stckf ERROR:cc_helper.c:128:cc_calc_addu: assertion failed: (carry_out <= 1) op_stck() sets the condition code with gen_op_movi_cc() before the output operand store, which is deferred to wout_m1_64(). Assigning a constant condition code discards the lazy CC values, so the optimizer drops the writes that produced them. When the store then raises an exception, the instruction is suppressed and s390x_restore_state_to_opc() reinstates the cc_op recorded at the start of STCK[F], but cc_src/cc_dst now hold stale values, so the next condition code evaluation reads garbage. Fix by performing the store manually. The alternative of not discarding in gen_op_movi_cc() keeps the inputs live, but results in less optimal code. Reported-by: Ido Plat Fixes: 434c91a5f4ed ("target-s390: Convert STCK") Cc: qemu-stable@nongnu.org Signed-off-by: Ilya Leoshkevich Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260714203206.363028-2-iii@linux.ibm.com Signed-off-by: Eric Farman --- target/s390x/tcg/insn-data.h.inc | 4 ++-- target/s390x/tcg/translate.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc index 0d5392eac5..1ea72248a6 100644 --- a/target/s390x/tcg/insn-data.h.inc +++ b/target/s390x/tcg/insn-data.h.inc @@ -887,8 +887,8 @@ C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) /* STORE CLOCK */ - F(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0, IF_IO) - F(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0, IF_IO) + F(0xb205, STCK, S, Z, la2, 0, new, 0, stck, 0, IF_IO) + F(0xb27c, STCKF, S, SCF, la2, 0, new, 0, stck, 0, IF_IO) /* STORE CLOCK EXTENDED */ F(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0, IF_IO) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 82165ac1ec..1b6023168b 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -4108,7 +4108,9 @@ static DisasJumpType op_stap(DisasContext *s, DisasOps *o) static DisasJumpType op_stck(DisasContext *s, DisasOps *o) { gen_helper_stck(o->out, tcg_env); + tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_BEUQ); /* ??? We don't implement clock states. */ + /* Set the CC after the store; a suppressed store must preserve it. */ gen_op_movi_cc(s, 0); return DISAS_NEXT; } From e79ea4472691fd7f7b3436dafbabd17c78fc8bf4 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 14 Jul 2026 22:29:55 +0200 Subject: [PATCH 068/627] tests/tcg/s390x: Test STCKF condition code on a faulting store Add a small test to prevent regressions. Signed-off-by: Ilya Leoshkevich Reviewed-by: Eric Farman Link: https://lore.kernel.org/qemu-devel/20260714203206.363028-3-iii@linux.ibm.com Signed-off-by: Eric Farman --- tests/tcg/s390x/Makefile.target | 1 + tests/tcg/s390x/stckf.c | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/tcg/s390x/stckf.c diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index 48cba4cdfa..97c0f02190 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -50,6 +50,7 @@ TESTS+=cvb TESTS+=ts TESTS+=ex-smc TESTS+=divide-to-integer +TESTS+=stckf cdsg: CFLAGS+=-pthread cdsg: LDFLAGS+=-pthread diff --git a/tests/tcg/s390x/stckf.c b/tests/tcg/s390x/stckf.c new file mode 100644 index 0000000000..51c8c9df9f --- /dev/null +++ b/tests/tcg/s390x/stckf.c @@ -0,0 +1,44 @@ +/* + * Test that a faulting STORE CLOCK FAST does not clobber the condition code. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include +#include +#include + +static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) +{ + mcontext_t *mcontext = &((ucontext_t *)ucontext)->uc_mcontext; + + /* The condition code must be the one set by SLGR, not garbage. */ + _exit(((mcontext->psw.mask >> 44) & 3) == 3 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +int main(void) +{ + struct sigaction act = { + .sa_sigaction = handle_sigsegv, + .sa_flags = SA_SIGINFO, + }; + int err; + + err = sigaction(SIGSEGV, &act, NULL); + assert(err == 0); + + asm volatile( + "lghi %%r1,100\n" + "lghi %%r2,0\n" + "clgr %%r1,%%r2\n" /* CC_OP_LTUGTU_64 */ + /* cc_src=100 is not valid for CC_OP_SUBU */ + "ipm %%r0\n" /* force cc_src to env */ + "lghi %%r3,5\n" + "lghi %%r4,3\n" + "slgr %%r3,%%r4\n" /* CC_OP_SUBU, cc=3 */ + "lghi %%r5,0\n" + "stckf 0(%%r5)\n" /* faults; cc must stay 3 */ + : : : "r0", "r1", "r2", "r3", "r4", "r5", "cc", "memory"); + + return EXIT_FAILURE; +} From 6126cbe2e59d7a9df1128f6072e3480267451187 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Wed, 5 Aug 2026 12:37:28 +0200 Subject: [PATCH 069/627] target/s390x: Allow 2G hugepages guest backing Allow mapping guest with 2G hugepages on hosts that support it. Rename kvm_s390_get_hpage_1m() to kvm_s390_get_hpage() to reflect that it is not anymore limited only to 1m hpages. Signed-off-by: Claudio Imbrenda Reviewed-by: Eric Farman Reviewed-by: Hendrik Brueckner Reviewed-by: Matthew Rosato Link: https://lore.kernel.org/qemu-devel/20260805103728.97602-2-imbrenda@linux.ibm.com Signed-off-by: Eric Farman --- target/s390x/diag.c | 2 +- target/s390x/kvm/kvm.c | 40 +++++++++++++++++------------------- target/s390x/kvm/kvm_s390x.h | 2 +- target/s390x/kvm/stubs.c | 2 +- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 80f0958478..46d191b87d 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -185,7 +185,7 @@ out: return false; } - if (kvm_enabled() && kvm_s390_get_hpage_1m()) { + if (kvm_enabled() && kvm_s390_get_hpage()) { error_report("Protected VMs can currently not be backed with " "huge pages"); env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 72031a5714..803b878b4f 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -145,7 +145,7 @@ static int cap_mem_op; static int cap_mem_op_extension; static int cap_s390_irq; static int cap_ri; -static int cap_hpage_1m; +static int cap_hpage; static int cap_vcpu_resets; static int cap_protected; static int cap_zpci_op; @@ -231,7 +231,7 @@ static void kvm_s390_enable_cmma(void) .attr = KVM_S390_VM_MEM_ENABLE_CMMA, }; - if (cap_hpage_1m) { + if (cap_hpage) { warn_report("CMM will not be enabled because it is not " "compatible with huge memory backings."); return; @@ -292,30 +292,28 @@ void kvm_s390_crypto_reset(void) } } -void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp) +static bool kvm_s390_pgsize_cap(uint32_t capa, const char *s, Error **errp) { - if (pagesize == 4 * KiB) { - return; + if (kvm_vm_enable_cap(kvm_state, capa, 0)) { + error_setg(errp, "Memory backing with %s pages was specified, " + "but KVM does not support this memory backing", s); + return false; } - - if (pagesize != 1 * MiB) { - error_setg(errp, "Memory backing with 2G pages was specified, " - "but KVM does not support this memory backing"); - return; - } - - if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) { - error_setg(errp, "Memory backing with 1M pages was specified, " - "but KVM does not support this memory backing"); - return; - } - - cap_hpage_1m = 1; + return true; } -int kvm_s390_get_hpage_1m(void) +void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp) { - return cap_hpage_1m; + if (pagesize == MiB) { + cap_hpage = kvm_s390_pgsize_cap(KVM_CAP_S390_HPAGE_1M, "1M", errp); + } else if (pagesize != 4 * KiB) { + cap_hpage = 2 * kvm_s390_pgsize_cap(KVM_CAP_S390_HPAGE_2G, "2G", errp); + } +} + +int kvm_s390_get_hpage(void) +{ + return cap_hpage; } static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque) diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h index 7b1cce3e60..3c4fa0489c 100644 --- a/target/s390x/kvm/kvm_s390x.h +++ b/target/s390x/kvm/kvm_s390x.h @@ -25,7 +25,7 @@ void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code); int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); -int kvm_s390_get_hpage_1m(void); +int kvm_s390_get_hpage(void); int kvm_s390_get_protected_dump(void); int kvm_s390_get_ri(void); int kvm_s390_get_zpci_op(void); diff --git a/target/s390x/kvm/stubs.c b/target/s390x/kvm/stubs.c index 196127baa5..ebf3c83994 100644 --- a/target/s390x/kvm/stubs.c +++ b/target/s390x/kvm/stubs.c @@ -143,7 +143,7 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) g_assert_not_reached(); } -int kvm_s390_get_hpage_1m(void) +int kvm_s390_get_hpage(void) { g_assert_not_reached(); } From 84f07211cc5b4fc6a371559bf8a5de4fb068e648 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 11 Aug 2026 10:04:46 -0400 Subject: [PATCH 070/627] Update version for v11.1.0 release Signed-off-by: Stefan Hajnoczi --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 63d29a3de9..68d8f15e23 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -11.0.93 +11.1.0 From 343b1d2d8838c4dc8728baf096933b77c6dbc749 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 11 Aug 2026 11:43:44 -0400 Subject: [PATCH 071/627] Open 11.2 development tree Signed-off-by: Stefan Hajnoczi --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 68d8f15e23..cf942bd79b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -11.1.0 +11.1.50 From 0573b1e11a2d746b290c76328b15bf06bf0e36a1 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 30 Jul 2026 10:13:17 +0200 Subject: [PATCH 072/627] MAINTAINERS: add myself to IDE maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Denis V. Lunev CC: Stefan Hajnoczi CC: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260730081325.1816193-2-den@openvz.org> [John Snow has acknowledged this: https://lore.kernel.org/qemu-devel/CAFn=p-abWtYqGtCbH9XTK62oEPK=vLPjy-scwqR+crXvOQ3RrA@mail.gmail.com/ --Stefan] Signed-off-by: Stefan Hajnoczi --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 902db77218..4628793dde 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2160,6 +2160,7 @@ F: docs/specs/edu.rst IDE M: John Snow +M: Denis V. Lunev L: qemu-block@nongnu.org S: Odd Fixes F: include/hw/ide/ From 2fad751ed6b14ef02b8c728b1b88c6c809f767d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 9 Jul 2026 18:41:00 +0200 Subject: [PATCH 073/627] hw/arm/aspeed: Add missing PCI_EXPRESS -> PCIE_PORT Kconfig dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the missing Kconfig dependency on PCIE_PORT to avoid the following runtime error: Type 'aspeed.pcie-root-port' is missing its parent 'pcie-root-port-base' No need to have ASPEED_SOC select PCI_EXPRESS since it is already selected by PCI_EXPRESS_ASPEED. Cc: qemu-stable@nongnu.org Fixes: 2af56518fa9 ("hw/pci-host/aspeed: Add AST2600 PCIe Root Port and make address configurable") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260709164103.37614-2-philmd@oss.qualcomm.com Signed-off-by: Cédric Le Goater --- hw/arm/Kconfig | 1 - hw/pci-host/Kconfig | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 82e0bc2e70..00e2d93803 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -557,7 +557,6 @@ config ASPEED_SOC select MAX31785 select FSI_APB2OPB_ASPEED select AT24C - select PCI_EXPRESS select PCI_EXPRESS_ASPEED config MPS2 diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 8cbb8304a3..bda6e161f1 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -49,6 +49,7 @@ config PCI_I440FX config PCI_EXPRESS_ASPEED bool select PCI_EXPRESS + select PCIE_PORT config PCI_EXPRESS_Q35 bool From 6440880ed371f74b3019462acfb2cd7709372db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 9 Jul 2026 18:41:01 +0200 Subject: [PATCH 074/627] hw/arm/aspeed: Add missing Kconfig dependencies on required components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add various missing Kconfig dependencies of the Aspeed SoCs: - USB EHCI (commit bfdd34f1caa "hw/arm: ast2400/ast2500: Wire up EHCI controllers") - OR-IRQ (commit d831c5fd868 "aspeed/intc: Add AST2700 support") - SDHCI (commit 2bea128c3d0 "hw/sd/aspeed_sdhci: New device" and f25c0ae1079 "aspeed/soc: Add AST2600 support") This fixes the following runtime issues: qemu-system-aarch64: unknown type 'platform-ehci-usb' qemu-system-aarch64: unknown type 'or-irq' qemu-system-aarch64: unknown type 'generic-sdhci' Cc: qemu-stable@nongnu.org Fixes: 2bea128c3d0 ("hw/sd/aspeed_sdhci: New device") Fixes: f25c0ae1079 ("aspeed/soc: Add AST2600 support") Fixes: d831c5fd868 ("aspeed/intc: Add AST2700 support") Fixes: bfdd34f1caa ("hw/arm: ast2400/ast2500: Wire up EHCI controllers") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260709164103.37614-3-philmd@oss.qualcomm.com Signed-off-by: Cédric Le Goater --- hw/arm/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 00e2d93803..6f5b2add66 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -551,6 +551,7 @@ config ASPEED_SOC select TMP105 select TMP421 select EMC141X + select OR_IRQ select UNIMP select LED select PMBUS @@ -558,6 +559,8 @@ config ASPEED_SOC select FSI_APB2OPB_ASPEED select AT24C select PCI_EXPRESS_ASPEED + select USB_EHCI_SYSBUS + select SDHCI config MPS2 bool From 826f9765c0681167eb427f1aafd2fe2c5f3c1f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 9 Jul 2026 18:41:02 +0200 Subject: [PATCH 075/627] hw/arm/aspeed: Add missing Kconfig dependencies on optional components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing Kconfig optional dependencies to avoid the following runtime error: qemu-system-aarch64: -device loader,force-raw=on,addr=0x400000000,file=./u-boot.bin: 'loader' is not a valid device model name qemu-system-aarch64: -device e1000e,netdev=net1,bus=pcie.2: 'e1000e' is not a valid device model name Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260709164103.37614-4-philmd@oss.qualcomm.com Signed-off-by: Cédric Le Goater --- hw/arm/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 6f5b2add66..5869f0f9e8 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -533,7 +533,9 @@ config ASPEED_SOC bool default y depends on TCG && ARM + imply GENERIC_LOADER imply PCI_DEVICES + imply E1000E_PCI_EXPRESS select DS1338 select FTGMAC100 select I2C From 38ed803aebb29ceebcc3e87b0b0d80114b9aa94c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:07 +0000 Subject: [PATCH 076/627] hw/usb/hcd-ehci: Change descriptor addresses to 64-bit with migration compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change internal EHCI descriptor addresses from uint32_t to uint64_t. The following fields are updated: - EHCIPacket::qtdaddr - EHCIQueue::{qhaddr, qtdaddr} - EHCIState::{a_fetch_addr, p_fetch_addr} Update get_dwords() and put_dwords() to take 64-bit addresses and propagate the type change through the descriptor traversal paths. Adjust NLPTR_GET() to operate on 64-bit values: #define NLPTR_GET(x) ((x) & ~0x1fULL) so that link pointer masking works correctly when descriptor addresses exceed 32-bit space. The previous mask (0xffffffe0) implicitly truncated addresses to 32 bits. This patch does not change the on-wire descriptor layout yet. It only removes the internal 32-bit address limit and prepares for later patches that will add full 64-bit QH/qTD/iTD/siTD support. Update the EHCI trace-events prototypes for QH, qTD, iTD, and siTD to use uint64_t for the address argument and print it with PRIx64. This ensures full 64-bit addresses are shown in trace output and improves debugging of queue heads and transfer descriptors. Migration compatibility: To preserve backward migration compatibility, keep the legacy 32-bit fetch address fields (a_fetch_addr_32, p_fetch_addr_32) alongside the new 64-bit fields. Migration format is selected using a machine compat property "x-migrate-fetch-addr-64bit": - Old machine types migrate 32-bit fetch addresses - New machine types migrate full 64-bit fetch addresses This is implemented using VMSTATE_UINT32_TEST() and VMSTATE_UINT64_TEST() so that only the appropriate format is migrated. In pre_save, the 32-bit shadow fields are populated when migrating to old machine types. In post_load, the 32-bit values are restored into the 64-bit fields when loading old migration streams. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/core/machine.c | 2 ++ hw/usb/hcd-ehci.c | 74 +++++++++++++++++++++++++++++++-------------- hw/usb/hcd-ehci.h | 30 +++++++++++++----- hw/usb/trace-events | 24 +++++++-------- 4 files changed, 89 insertions(+), 41 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 73b4d82b4a..eb5e3809d6 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -51,6 +51,8 @@ GlobalProperty hw_compat_11_0[] = { { TYPE_ARM_SMMUV3, "ssidsize", "0" }, { TYPE_ARM_SMMUV3, "oas", "44" }, { "migration", "switchover-ack-legacy", "on" }, + { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, + { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, }; const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0); diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 28a60e4c1a..1a0c580115 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -72,7 +72,7 @@ typedef enum { } EHCI_STATES; /* macros for accessing fields within next link pointer entry */ -#define NLPTR_GET(x) ((x) & 0xffffffe0) +#define NLPTR_GET(x) ((x) & ~0x1fULL) #define NLPTR_TYPE_GET(x) (((x) >> 1) & 3) #define NLPTR_TBIT(x) ((x) & 1) /* 1=invalid, 0=valid */ @@ -287,7 +287,7 @@ static int ehci_get_state(EHCIState *s, int async) return async ? s->astate : s->pstate; } -static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr) +static void ehci_set_fetch_addr(EHCIState *s, int async, uint64_t addr) { if (async) { s->a_fetch_addr = addr; @@ -296,7 +296,7 @@ static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr) } } -static int ehci_get_fetch_addr(EHCIState *s, int async) +static uint64_t ehci_get_fetch_addr(EHCIState *s, int async) { return async ? s->a_fetch_addr : s->p_fetch_addr; } @@ -373,7 +373,7 @@ static inline bool ehci_periodic_enabled(EHCIState *s) } /* Get an array of dwords from main memory */ -static inline int get_dwords(EHCIState *ehci, uint32_t addr, +static inline int get_dwords(EHCIState *ehci, uint64_t addr, uint32_t *buf, int num) { int i; @@ -395,7 +395,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr, } /* Put an array of dwords in to main memory */ -static inline int put_dwords(EHCIState *ehci, uint32_t addr, +static inline int put_dwords(EHCIState *ehci, uint64_t addr, uint32_t *buf, int num) { int i; @@ -549,7 +549,7 @@ static void ehci_free_packet(EHCIPacket *p) /* queue management */ -static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) +static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint64_t addr, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; EHCIQueue *q; @@ -622,7 +622,7 @@ static void ehci_free_queue(EHCIQueue *q, const char *warn) g_free(q); } -static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, +static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint64_t addr, int async) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; @@ -1135,7 +1135,7 @@ static void ehci_flush_qh(EHCIQueue *q) { uint32_t *qh = (uint32_t *) &q->qh; uint32_t dwords = sizeof(EHCIqh) >> 2; - uint32_t addr = NLPTR_GET(q->qhaddr); + uint64_t addr = NLPTR_GET(q->qhaddr); put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); } @@ -1406,12 +1406,13 @@ static int ehci_execute(EHCIPacket *p, const char *action) /* 4.7.2 */ static int ehci_process_itd(EHCIState *ehci, EHCIitd *itd, - uint32_t addr) + uint64_t addr) { USBDevice *dev; USBEndpoint *ep; uint32_t i, len, pid, dir, devaddr, endp; - uint32_t pg, off, ptr1, ptr2, max, mult; + uint32_t pg, off, max, mult; + uint64_t ptr1, ptr2; ehci->periodic_sched_active = PERIODIC_ACTIVE; @@ -1528,7 +1529,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) EHCIqh qh; int i = 0; int again = 0; - uint32_t entry = ehci->asynclistaddr; + uint64_t entry = ehci->asynclistaddr; /* set reclamation flag at start event (4.8.6) */ if (async) { @@ -1578,7 +1579,7 @@ out: static int ehci_state_fetchentry(EHCIState *ehci, int async) { int again = 0; - uint32_t entry = ehci_get_fetch_addr(ehci, async); + uint64_t entry = ehci_get_fetch_addr(ehci, async); if (NLPTR_TBIT(entry)) { ehci_set_state(ehci, async, EST_ACTIVE); @@ -1611,8 +1612,8 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async) default: /* TODO: handle FSTN type */ qemu_log_mask(LOG_GUEST_ERROR, - "FETCHENTRY: entry at 0x%x is of type %u " - "which is not supported yet\n", + "FETCHENTRY: entry at %" PRIx64 " is of type %" PRIu64 + " which is not supported yet\n", entry, NLPTR_TYPE_GET(entry)); return -1; } @@ -1623,7 +1624,7 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { - uint32_t entry; + uint64_t entry; EHCIQueue *q; EHCIqh qh; @@ -1712,7 +1713,7 @@ out: static int ehci_state_fetchitd(EHCIState *ehci, int async) { - uint32_t entry; + uint64_t entry; EHCIitd itd; assert(!async); @@ -1738,7 +1739,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) static int ehci_state_fetchsitd(EHCIState *ehci, int async) { - uint32_t entry; + uint64_t entry; EHCIsitd sitd; assert(!async); @@ -1802,7 +1803,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) EHCIqtd qtd; EHCIPacket *p; int again = 1; - uint32_t addr; + uint64_t addr; addr = NLPTR_GET(q->qtdaddr); if (get_dwords(q->ehci, addr + 8, &qtd.token, 1) < 0) { @@ -1885,7 +1886,7 @@ static int ehci_fill_queue(EHCIPacket *p) USBEndpoint *ep = p->packet.ep; EHCIQueue *q = p->queue; EHCIqtd qtd = p->qtd; - uint32_t qtdaddr; + uint64_t qtdaddr; for (;;) { if (NLPTR_TBIT(qtd.next) != 0) { @@ -2008,7 +2009,8 @@ static int ehci_state_executing(EHCIQueue *q) static int ehci_state_writeback(EHCIQueue *q) { EHCIPacket *p = QTAILQ_FIRST(&q->packets); - uint32_t *qtd, addr; + uint32_t *qtd; + uint64_t addr; int again = 0; /* Write back the QTD from the QH area */ @@ -2414,6 +2416,18 @@ static USBBusOps ehci_bus_ops_standalone = { .wakeup_endpoint = ehci_wakeup_endpoint, }; +static bool ehci_fetch_addr_64_needed(void *opaque, int version_id) +{ + EHCIState *s = opaque; + + return s->migrate_fetch_addr_64bit; +} + +static bool ehci_fetch_addr_32_needed(void *opaque, int version_id) +{ + return !ehci_fetch_addr_64_needed(opaque, version_id); +} + static int usb_ehci_pre_save(void *opaque) { EHCIState *ehci = opaque; @@ -2424,6 +2438,11 @@ static int usb_ehci_pre_save(void *opaque) ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS; ehci->frindex = new_frindex; + if (!ehci->migrate_fetch_addr_64bit) { + ehci->migrate_a_fetch_addr = ehci->a_fetch_addr; + ehci->migrate_p_fetch_addr = ehci->p_fetch_addr; + } + return 0; } @@ -2444,6 +2463,11 @@ static int usb_ehci_post_load(void *opaque, int version_id) } } + if (!s->migrate_fetch_addr_64bit) { + s->a_fetch_addr = s->migrate_a_fetch_addr; + s->p_fetch_addr = s->migrate_p_fetch_addr; + } + return 0; } @@ -2504,8 +2528,14 @@ const VMStateDescription vmstate_ehci = { /* schedule state */ VMSTATE_UINT32(astate, EHCIState), VMSTATE_UINT32(pstate, EHCIState), - VMSTATE_UINT32(a_fetch_addr, EHCIState), - VMSTATE_UINT32(p_fetch_addr, EHCIState), + VMSTATE_UINT32_TEST(migrate_a_fetch_addr, EHCIState, + ehci_fetch_addr_32_needed), + VMSTATE_UINT32_TEST(migrate_p_fetch_addr, EHCIState, + ehci_fetch_addr_32_needed), + VMSTATE_UINT64_TEST(a_fetch_addr, EHCIState, + ehci_fetch_addr_64_needed), + VMSTATE_UINT64_TEST(p_fetch_addr, EHCIState, + ehci_fetch_addr_64_needed), VMSTATE_END_OF_LIST() } }; diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index d038ee1e31..cbc32c296d 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -208,7 +208,7 @@ struct EHCIPacket { QTAILQ_ENTRY(EHCIPacket) next; EHCIqtd qtd; /* copy of current QTD (being worked on) */ - uint32_t qtdaddr; /* address QTD read from */ + uint64_t qtdaddr; /* address QTD read from */ USBPacket packet; QEMUSGList sgl; @@ -229,8 +229,8 @@ struct EHCIQueue { * when guest removes an entry (doorbell, handshake sequence) */ EHCIqh qh; /* copy of current QH (being worked on) */ - uint32_t qhaddr; /* address QH read from */ - uint32_t qtdaddr; /* address QTD read from */ + uint64_t qhaddr; /* address QH read from */ + uint64_t qtdaddr; /* address QTD read from */ int last_pid; /* pid of last packet executed */ USBDevice *dev; QTAILQ_HEAD(, EHCIPacket) packets; @@ -256,6 +256,11 @@ struct EHCIState { /* properties */ uint32_t maxframes; + /* + * Controls migration stream compatibility for old machine types. + * Old machine types only transfer 32-bit fetch addresses. + */ + bool migrate_fetch_addr_64bit; /* * EHCI spec version 1.0 Section 2.3 @@ -293,9 +298,18 @@ struct EHCIState { EHCIQueueHead aqueues; EHCIQueueHead pqueues; - /* which address to look at next */ - uint32_t a_fetch_addr; - uint32_t p_fetch_addr; + /* + * which address to look at next + * + * Migration compatibility fields for old machine types that only + * support 32-bit fetch addresses in the migration stream. + * + * New machine types migrate the full 64-bit runtime fetch address. + */ + uint32_t migrate_a_fetch_addr; + uint32_t migrate_p_fetch_addr; + uint64_t a_fetch_addr; + uint64_t p_fetch_addr; USBPacket ipacket; QEMUSGList isgl; @@ -308,7 +322,9 @@ struct EHCIState { }; #define DEFINE_EHCI_COMMON_PROPERTIES(_state) \ - DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128) + DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128), \ + DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \ + ehci.migrate_fetch_addr_64bit, true) extern const VMStateDescription vmstate_ehci; diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 0d4318dcf1..8c90688bb3 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -86,15 +86,15 @@ usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio 0x%04 usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio 0x%04x [port %d] = 0x%x (old: 0x%x)" usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" -usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%08x: next 0x%08x qtds 0x%08x,0x%08x,0x%08x" -usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%08x - rl %d, mplen %d, eps %d, ep %d, dev %d" -usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ 0x%08x - c %d, h %d, dtc %d, i %d" +usb_ehci_qh_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ 0x%" PRIx64 ": next 0x%08x qtds 0x%08x,0x%08x,0x%08x" +usb_ehci_qh_fields(uint64_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ 0x%" PRIx64 " - rl %d, mplen %d, eps %d, ep %d, dev %d" +usb_ehci_qh_bits(uint64_t addr, int c, int h, int dtc, int i) "QH @ 0x%" PRIx64 " - c %d, h %d, dtc %d, i %d" usb_ehci_qh_tbytes(uint32_t tbytes) "updating tbytes to %d" -usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%08x: next 0x%08x altnext 0x%08x" -usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%08x - tbytes %d, cpage %d, cerr %d, pid %d" -usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%08x - ioc %d, active %d, halt %d, babble %d, xacterr %d" -usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%08x: next 0x%08x - mplen %d, mult %d, ep %d, dev %d" -usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ 0x%08x: next 0x%08x - active %d" +usb_ehci_qtd_ptrs(void *q, uint64_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ 0x%" PRIx64 ": next 0x%08x altnext 0x%08x" +usb_ehci_qtd_fields(uint64_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ 0x%" PRIx64 " - tbytes %d, cpage %d, cerr %d, pid %d" +usb_ehci_qtd_bits(uint64_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ 0x%" PRIx64 " - ioc %d, active %d, halt %d, babble %d, xacterr %d" +usb_ehci_itd(uint64_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ 0x%" PRIx64 ": next 0x%08x - mplen %d, mult %d, ep %d, dev %d" +usb_ehci_sitd(uint64_t addr, uint32_t nxt, uint32_t active) "SITD @ 0x%" PRIx64 ": next 0x%08x - active %d" usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s" usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s" usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d" @@ -104,15 +104,15 @@ usb_ehci_port_resume(uint32_t port) "port #%d" usb_ehci_port_disable(uint32_t port) "port #%d" usb_ehci_queue_action(void *q, const char *action) "q %p: %s" usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" -usb_ehci_packet_submit(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%x, next=0x%x, qtd=0x%x, pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d" +usb_ehci_packet_submit(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int pid, size_t len, int endp, int status, int actual_length) "qh=0x%" PRIx64 ", next=0x%x, qtd=0x%" PRIx64 ", pid=0x%x, len=%zd, endp=0x%x, status=%d, actual_length=%d" usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" usb_ehci_guest_bug(const char *reason) "%s" usb_ehci_doorbell_ring(void) "" usb_ehci_doorbell_ack(void) "" usb_ehci_dma_error(void) "" -usb_ehci_execute_complete(uint32_t qhaddr, uint32_t next, uint32_t qtdaddr, int status, int actual_length) "qhaddr=0x%x, next=0x%x, qtdaddr=0x%x, status=%d, actual_length=%d" -usb_ehci_fetchqh_reclaim_done(uint32_t qhaddr) "QH 0x%08x H-bit set, reclamation status reset - done processing" -usb_ehci_fetchqh_dbg(uint32_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%08x (h 0x%x halt 0x%x active 0x%x) next 0x%08x" +usb_ehci_execute_complete(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int status, int actual_length) "qhaddr=0x%" PRIx64 ", next=0x%x, qtdaddr=0x%" PRIx64 ", status=%d, actual_length=%d" +usb_ehci_fetchqh_reclaim_done(uint64_t qhaddr) "QH 0x%" PRIx64 " H-bit set, reclamation status reset - done processing" +usb_ehci_fetchqh_dbg(uint64_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%" PRIx64 " (h 0x%x halt 0x%x active 0x%x) next 0x%08x" usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x" usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes" usb_ehci_log(const char *msg) "%s" From 7e6c5727e16fca59af7a681716d25aabc1892f96 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:08 +0000 Subject: [PATCH 077/627] hw/usb/hcd-ehci: Add property to advertise 64-bit addressing capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new boolean property, "caps-64bit-addr", to control HCCPARAMS[0] (64-bit Addressing Capability). When enabled, the EHCI controller advertises support for 64-bit address memory pointers as defined in the EHCI specification (Table 2-7, HCCPARAMS). This allows software to use the 64-bit data structure formats described in Appendix B. When disabled (default), the controller reports 32-bit addressing capability and uses the standard 32-bit data structures. The EHCI CTRLDSSEGMENT register provides the upper 32 bits [63:32] used to form 64-bit addresses for EHCI control data structures. Per EHCI 1.0 spec section 2.3.5, when the HCCPARAMS 64-bit Addressing Capability bit is zero, CTRLDSSEGMENT is not used: software cannot write it and reads must return zero. Add a capability check in the operational register write handler and reject guest writes to CTRLDSSEGMENT when 64-bit addressing is not enabled. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 14 +++++++++++++- hw/usb/hcd-ehci.h | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 1a0c580115..e65ea825b0 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1109,6 +1109,15 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, } break; + case CTRLDSSEGMENT: + if (!s->caps_64bit_addr) { + qemu_log_mask(LOG_GUEST_ERROR, + "ehci: write to CTRLDSSEGMENT while " + "64-bit addressing capability is disabled\n"); + return; + } + break; + case ASYNCLISTADDR: if (ehci_async_enabled(s)) { qemu_log_mask(LOG_GUEST_ERROR, @@ -2554,6 +2563,9 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp) s->maxframes); return; } + if (s->caps_64bit_addr) { + s->caps[0x08] |= BIT(0); + } memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps); memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg); @@ -2613,7 +2625,7 @@ void usb_ehci_init(EHCIState *s, DeviceState *dev) s->caps[0x05] = 0x00; /* No companion ports at present */ s->caps[0x06] = 0x00; s->caps[0x07] = 0x00; - s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ + s->caps[0x08] = 0x80; /* We can cache whole frame */ s->caps[0x0a] = 0x00; s->caps[0x0b] = 0x00; diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index cbc32c296d..f739e6371b 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -261,6 +261,7 @@ struct EHCIState { * Old machine types only transfer 32-bit fetch addresses. */ bool migrate_fetch_addr_64bit; + bool caps_64bit_addr; /* * EHCI spec version 1.0 Section 2.3 @@ -324,7 +325,9 @@ struct EHCIState { #define DEFINE_EHCI_COMMON_PROPERTIES(_state) \ DEFINE_PROP_UINT32("maxframes", _state, ehci.maxframes, 128), \ DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \ - ehci.migrate_fetch_addr_64bit, true) + ehci.migrate_fetch_addr_64bit, true), \ + DEFINE_PROP_BOOL("caps-64bit-addr", _state, \ + ehci.caps_64bit_addr, false) extern const VMStateDescription vmstate_ehci; From 0cb43fdc0b2f2fb7f1c914d734ac32d9b91a5bbe Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:10 +0000 Subject: [PATCH 078/627] hw/usb/hcd-ehci: Implement 64-bit QH descriptor addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EHCI supports 64-bit control data structure addressing when the 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register supplies the upper 32 bits which are concatenated with 32-bit link pointer fields to form full 64-bit descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B). The current implementation assumes 32-bit QH descriptor addresses and directly uses link pointer values without applying the CTRLDSSEGMENT upper dword. Introduce a helper, ehci_get_desc_addr(), to construct full 64-bit descriptor addresses when 64-bit capability is enabled. Update QH traversal paths (async list walk, horizontal QH link, and periodic schedule entry handling) to use the translated 64-bit addresses. EHCI 64-bit buffer pointer fields are defined in Appendix B as split 32-bit low/high parts located at separate offsets, rather than a single contiguous 64-bit field. Therefore, the buffer pointers cannot be represented as uint64_t bufptr[5] without violating the descriptor layout defined by the specification. Introduce ehci_get_buf_addr() to construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[] fields. Use this helper when calculating transfer buffer addresses so that data buffers above 4GB are correctly handled. Also add bufptr_hi[5] to EHCIqh to support 64-bit buffer pointer fields as defined in Appendix B. When 64-bit capability is disabled, descriptor addresses remain 32-bit and existing behaviour is unchanged. Note: Similar split 64-bit buffer pointer handling is required for qTD, iTD and siTD descriptors, which will be addressed in follow-up changes. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 72 +++++++++++++++++++++++++++++++++++---------- hw/usb/hcd-ehci.h | 4 +++ hw/usb/trace-events | 2 +- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index e65ea825b0..fd5be7430e 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -96,6 +96,15 @@ typedef enum { *data = val; \ } while (0) +/* + * EHCIqh / EHCIqtd / EHCIitd are sized to always include the extended + * high buffer pointer fields from EHCI 1.0 Appendix B. When 64-bit + * addressing capability is not advertised to the guest, the descriptors + * in guest memory only have the classic 32-bit layout, so DMA transfers + * must not read or write past that boundary. + */ +#define EHCI_QH_DWORDS_32 (offsetof(EHCIqh, bufptr_hi) / sizeof(uint32_t)) + static const char *ehci_state_names[] = { [EST_INACTIVE] = "INACTIVE", [EST_ACTIVE] = "ACTIVE", @@ -147,6 +156,28 @@ static const char *addr2str(hwaddr addr) return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); } +static uint64_t ehci_get_buf_addr(const EHCIState *s, uint32_t hi, + uint32_t lo, uint32_t lo_mask) +{ + uint64_t addr = lo & lo_mask; + + if (s->caps_64bit_addr) { + addr = deposit64(addr, 32, 32, hi); + } + + return addr; +} + +static uint64_t ehci_get_desc_addr(const EHCIState *s, uint32_t lo) +{ + return ehci_get_buf_addr(s, s->ctrldssegment, lo, UINT32_MAX); +} + +static uint32_t ehci_qh_dwords(const EHCIState *s) +{ + return s->caps_64bit_addr ? (sizeof(EHCIqh) >> 2) : EHCI_QH_DWORDS_32; +} + static void ehci_trace_usbsts(uint32_t mask, int state) { /* interrupts */ @@ -440,7 +471,7 @@ static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) (qh->current_qtd != q->qh.current_qtd) || (q->async && qh->next_qtd != q->qh.next_qtd) || (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd, - 7 * sizeof(uint32_t)) != 0) || + EHCI_QH_OVERLAY_COUNT * sizeof(uint32_t)) != 0) || (q->dev != NULL && q->dev->addr != devaddr)) { return false; } else { @@ -487,8 +518,9 @@ static void ehci_writeback_async_complete_packet(EHCIPacket *p) int state; /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */ + memset(&qh, 0, sizeof(qh)); get_dwords(q->ehci, NLPTR_GET(q->qhaddr), - (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + (uint32_t *) &qh, ehci_qh_dwords(q->ehci)); get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) { @@ -1143,7 +1175,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, static void ehci_flush_qh(EHCIQueue *q) { uint32_t *qh = (uint32_t *) &q->qh; - uint32_t dwords = sizeof(EHCIqh) >> 2; + uint32_t dwords = ehci_qh_dwords(q->ehci); uint64_t addr = NLPTR_GET(q->qhaddr); put_dwords(q->ehci, addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3); @@ -1538,7 +1570,9 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) EHCIqh qh; int i = 0; int again = 0; - uint64_t entry = ehci->asynclistaddr; + uint64_t entry = 0; + + entry = ehci_get_desc_addr(ehci, ehci->asynclistaddr); /* set reclamation flag at start event (4.8.6) */ if (async) { @@ -1548,9 +1582,10 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) ehci_queues_rip_unused(ehci, async); /* Find the head of the list (4.9.1.1) */ + memset(&qh, 0, sizeof(qh)); for (i = 0; i < MAX_QH; i++) { if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, - sizeof(EHCIqh) >> 2) < 0) { + ehci_qh_dwords(ehci)) < 0) { return 0; } ehci_trace_qh(NULL, NLPTR_GET(entry), &qh); @@ -1566,8 +1601,8 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) goto out; } - entry = qh.next; - if (entry == ehci->asynclistaddr) { + entry = ehci_get_desc_addr(ehci, qh.next); + if (entry == ehci_get_desc_addr(ehci, ehci->asynclistaddr)) { break; } } @@ -1651,8 +1686,9 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) goto out; } + memset(&qh, 0, sizeof(qh)); if (get_dwords(ehci, NLPTR_GET(q->qhaddr), - (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) { + (uint32_t *) &qh, ehci_qh_dwords(ehci)) < 0) { q = NULL; goto out; } @@ -1693,7 +1729,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) } if (trace_event_get_state_backends(TRACE_USB_EHCI_FETCHQH_DBG)) { - if (q->qhaddr != q->qh.next) { + if (q->qhaddr != ehci_get_desc_addr(ehci, q->qh.next)) { trace_usb_ehci_fetchqh_dbg(q->qhaddr, q->qh.epchar & QH_EPCHAR_H, q->qh.token & QTD_TOKEN_HALT, @@ -1876,10 +1912,12 @@ static int ehci_state_fetchqtd(EHCIQueue *q) static int ehci_state_horizqh(EHCIQueue *q) { + uint64_t addr; int again = 0; - if (ehci_get_fetch_addr(q->ehci, q->async) != q->qh.next) { - ehci_set_fetch_addr(q->ehci, q->async, q->qh.next); + addr = ehci_get_desc_addr(q->ehci, q->qh.next); + if (ehci_get_fetch_addr(q->ehci, q->async) != addr) { + ehci_set_fetch_addr(q->ehci, q->async, addr); ehci_set_state(q->ehci, q->async, EST_FETCHENTRY); again = 1; } else { @@ -2205,6 +2243,8 @@ static void ehci_advance_periodic_state(EHCIState *ehci) uint32_t entry; uint32_t list; const int async = 0; + uint64_t entry64; + uint64_t list64; /* 4.6 */ @@ -2229,12 +2269,14 @@ static void ehci_advance_periodic_state(EHCIState *ehci) break; } list |= ((ehci->frindex & 0x1ff8) >> 1); - - if (get_dwords(ehci, list, &entry, 1) < 0) { + list64 = ehci_get_desc_addr(ehci, list); + if (get_dwords(ehci, list64, &entry, 1) < 0) { break; } - trace_usb_ehci_periodic_state_advance(ehci->frindex / 8, list, entry); - ehci_set_fetch_addr(ehci, async, entry); + entry64 = ehci_get_desc_addr(ehci, entry); + trace_usb_ehci_periodic_state_advance(ehci->frindex / 8, + list64, entry64); + ehci_set_fetch_addr(ehci, async, entry64); ehci_set_state(ehci, async, EST_FETCHENTRY); ehci_advance_state(ehci, async); ehci_queues_rip_unused(ehci, async); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index f739e6371b..8732264fde 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -141,6 +141,9 @@ typedef struct EHCIqtd { #define QTD_BUFPTR_SH 12 } EHCIqtd; +/* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */ +#define EHCI_QH_OVERLAY_COUNT 12 + /* * EHCI spec version 1.0 Section 3.6 */ @@ -194,6 +197,7 @@ typedef struct EHCIqh { #define BUFPTR_FRAMETAG_MASK 0x0000001f #define BUFPTR_SBYTES_MASK 0x00000fe0 #define BUFPTR_SBYTES_SH 5 + uint32_t bufptr_hi[5]; } EHCIqh; enum async_state { diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 8c90688bb3..67249d69c2 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -113,7 +113,7 @@ usb_ehci_dma_error(void) "" usb_ehci_execute_complete(uint64_t qhaddr, uint32_t next, uint64_t qtdaddr, int status, int actual_length) "qhaddr=0x%" PRIx64 ", next=0x%x, qtdaddr=0x%" PRIx64 ", status=%d, actual_length=%d" usb_ehci_fetchqh_reclaim_done(uint64_t qhaddr) "QH 0x%" PRIx64 " H-bit set, reclamation status reset - done processing" usb_ehci_fetchqh_dbg(uint64_t qhaddr, uint32_t h, uint32_t halt, uint32_t active, uint32_t next) "QH 0x%" PRIx64 " (h 0x%x halt 0x%x active 0x%x) next 0x%08x" -usb_ehci_periodic_state_advance(uint32_t frame, uint32_t list, uint32_t entry) "frame=%d, list=0x%x, entry=0x%x" +usb_ehci_periodic_state_advance(uint32_t frame, uint64_t list, uint64_t entry) "frame=%d, list=0x%" PRIx64 ", entry=0x%" PRIx64 usb_ehci_skipped_uframes(uint64_t skipped_uframes) "skipped %" PRIu64 " uframes" usb_ehci_log(const char *msg) "%s" From dea1ed14c931504a56cc767da26eed7fb3ac155b Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:11 +0000 Subject: [PATCH 079/627] hw/usb/hcd-ehci: Implement 64-bit qTD descriptor addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EHCI supports 64-bit addressing when the 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register provides the upper 32 bits that are concatenated with 32-bit link pointer values to form 64-bit control data structure addresses (EHCI 1.0, section 2.3.5 and Appendix B). qTD link pointers (current_qtd/next_qtd/altnext_qtd and qTD.next) are stored as 32-bit values in the data structures and must be expanded to full 64-bit descriptor addresses when 64-bit mode is enabled. Update the qTD traversal paths to use ehci_get_desc_addr() when following link pointers. Appendix B also defines high dword fields for qTD buffer pointers. Add bufptr_hi[5] to EHCIqtd and extend qTD fetch and QH overlay handling to load and propagate the high buffer pointer fields. When 64-bit capability is disabled, descriptor and buffer addresses remain 32-bit and existing behaviour is unchanged. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 33 ++++++++++++++++++++++++--------- hw/usb/hcd-ehci.h | 1 + 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index fd5be7430e..947af86ac4 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -104,6 +104,7 @@ typedef enum { * must not read or write past that boundary. */ #define EHCI_QH_DWORDS_32 (offsetof(EHCIqh, bufptr_hi) / sizeof(uint32_t)) +#define EHCI_QTD_DWORDS_32 (offsetof(EHCIqtd, bufptr_hi) / sizeof(uint32_t)) static const char *ehci_state_names[] = { [EST_INACTIVE] = "INACTIVE", @@ -178,6 +179,11 @@ static uint32_t ehci_qh_dwords(const EHCIState *s) return s->caps_64bit_addr ? (sizeof(EHCIqh) >> 2) : EHCI_QH_DWORDS_32; } +static uint32_t ehci_qtd_dwords(const EHCIState *s) +{ + return s->caps_64bit_addr ? (sizeof(EHCIqtd) >> 2) : EHCI_QTD_DWORDS_32; +} + static void ehci_trace_usbsts(uint32_t mask, int state) { /* interrupts */ @@ -486,7 +492,8 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) (p->qtd.next != qtd->next)) || (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || p->qtd.token != qtd->token || - p->qtd.bufptr[0] != qtd->bufptr[0]) { + p->qtd.bufptr[0] != qtd->bufptr[0] || + p->qtd.bufptr_hi[0] != qtd->bufptr_hi[0]) { return false; } else { return true; @@ -519,10 +526,11 @@ static void ehci_writeback_async_complete_packet(EHCIPacket *p) /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */ memset(&qh, 0, sizeof(qh)); + memset(&qtd, 0, sizeof(qtd)); get_dwords(q->ehci, NLPTR_GET(q->qhaddr), (uint32_t *) &qh, ehci_qh_dwords(q->ehci)); get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), - (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + (uint32_t *) &qtd, ehci_qtd_dwords(q->ehci)); if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) { p->async = EHCI_ASYNC_INITIALIZED; ehci_free_packet(p); @@ -1215,6 +1223,7 @@ static int ehci_qh_do_overlay(EHCIQueue *q) for (i = 0; i < 5; i++) { q->qh.bufptr[i] = p->qtd.bufptr[i]; + q->qh.bufptr_hi[i] = p->qtd.bufptr_hi[i]; } if (!(q->qh.epchar & QH_EPCHAR_DTC)) { @@ -1248,7 +1257,8 @@ static int ehci_init_transfer(EHCIPacket *p) return -1; } - page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; + page = ehci_get_buf_addr(p->queue->ehci, p->qtd.bufptr_hi[cpage], + p->qtd.bufptr[cpage], QTD_BUFPTR_MASK); page += offset; plen = bytes; if (plen > 4096 - offset) { @@ -1744,7 +1754,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (NLPTR_TBIT(q->qh.current_qtd) == 0) && (q->qh.current_qtd != 0)) { - q->qtdaddr = q->qh.current_qtd; + q->qtdaddr = ehci_get_desc_addr(ehci, q->qh.current_qtd); ehci_set_state(ehci, async, EST_FETCHQTD); } else { @@ -1822,14 +1832,14 @@ static int ehci_state_advqueue(EHCIQueue *q) */ if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) && (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) { - q->qtdaddr = q->qh.altnext_qtd; + q->qtdaddr = ehci_get_desc_addr(q->ehci, q->qh.altnext_qtd); ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* * next qTD is valid */ } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) { - q->qtdaddr = q->qh.next_qtd; + q->qtdaddr = ehci_get_desc_addr(q->ehci, q->qh.next_qtd); ehci_set_state(q->ehci, q->async, EST_FETCHQTD); /* @@ -1855,10 +1865,14 @@ static int ehci_state_fetchqtd(EHCIQueue *q) return 0; } barrier(); + memset(qtd.bufptr_hi, 0, sizeof(qtd.bufptr_hi)); if (get_dwords(q->ehci, addr + 0, &qtd.next, 1) < 0 || get_dwords(q->ehci, addr + 4, &qtd.altnext, 1) < 0 || get_dwords(q->ehci, addr + 12, qtd.bufptr, - ARRAY_SIZE(qtd.bufptr)) < 0) { + ARRAY_SIZE(qtd.bufptr)) < 0 || + (q->ehci->caps_64bit_addr && + get_dwords(q->ehci, addr + offsetof(EHCIqtd, bufptr_hi), + qtd.bufptr_hi, ARRAY_SIZE(qtd.bufptr_hi)) < 0)) { return 0; } ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); @@ -1939,7 +1953,7 @@ static int ehci_fill_queue(EHCIPacket *p) if (NLPTR_TBIT(qtd.next) != 0) { break; } - qtdaddr = qtd.next; + qtdaddr = ehci_get_desc_addr(q->ehci, qtd.next); /* * Detect circular td lists, Windows creates these, counting on the * active bit going low after execution to make the queue stop. @@ -1949,8 +1963,9 @@ static int ehci_fill_queue(EHCIPacket *p) goto leave; } } + memset(qtd.bufptr_hi, 0, sizeof(qtd.bufptr_hi)); if (get_dwords(q->ehci, NLPTR_GET(qtdaddr), - (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) { + (uint32_t *) &qtd, ehci_qtd_dwords(q->ehci)) < 0) { return -1; } ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 8732264fde..7fed206906 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -139,6 +139,7 @@ typedef struct EHCIqtd { uint32_t bufptr[5]; /* Standard buffer pointer */ #define QTD_BUFPTR_MASK 0xfffff000 #define QTD_BUFPTR_SH 12 + uint32_t bufptr_hi[5]; } EHCIqtd; /* QH overlay: altnext_qtd, token, bufptr[5], bufptr_hi[5] */ From d027e3c63c60b0c6daf93ccfbd127bb60526ab0d Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:13 +0000 Subject: [PATCH 080/627] hw/usb/hcd-ehci: Implement 64-bit iTD descriptor addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EHCI supports 64-bit control data structure addressing when the 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register provides the upper 32 bits that are concatenated with 32-bit link pointer values to form full 64-bit descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B). iTD link pointers are stored as 32-bit values and must be expanded to full 64-bit descriptor addresses when 64-bit mode is enabled. Update the iTD traversal path to use ehci_get_desc_addr() when following link pointers. Appendix B also defines high dword fields for iTD buffer pointers. Add bufptr_hi[7] to EHCIitd and use ehci_get_buf_addr() to construct full 64-bit buffer addresses from bufptr[] and bufptr_hi[] fields when processing isochronous transfers. This allows buffers above 4GB to be handled correctly. When 64-bit capability is disabled, descriptor and buffer addresses remain 32-bit and existing behaviour is unchanged. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 20 +++++++++++++++----- hw/usb/hcd-ehci.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 947af86ac4..1a286c32e6 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -105,6 +105,7 @@ typedef enum { */ #define EHCI_QH_DWORDS_32 (offsetof(EHCIqh, bufptr_hi) / sizeof(uint32_t)) #define EHCI_QTD_DWORDS_32 (offsetof(EHCIqtd, bufptr_hi) / sizeof(uint32_t)) +#define EHCI_ITD_DWORDS_32 (offsetof(EHCIitd, bufptr_hi) / sizeof(uint32_t)) static const char *ehci_state_names[] = { [EST_INACTIVE] = "INACTIVE", @@ -184,6 +185,11 @@ static uint32_t ehci_qtd_dwords(const EHCIState *s) return s->caps_64bit_addr ? (sizeof(EHCIqtd) >> 2) : EHCI_QTD_DWORDS_32; } +static uint32_t ehci_itd_dwords(const EHCIState *s) +{ + return s->caps_64bit_addr ? (sizeof(EHCIitd) >> 2) : EHCI_ITD_DWORDS_32; +} + static void ehci_trace_usbsts(uint32_t mask, int state) { /* interrupts */ @@ -1486,7 +1492,8 @@ static int ehci_process_itd(EHCIState *ehci, return -1; } - ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK); + ptr1 = ehci_get_buf_addr(ehci, itd->bufptr_hi[pg], + itd->bufptr[pg], ITD_BUFPTR_MASK); qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as); if (off + len > 4096) { /* transfer crosses page border */ @@ -1494,7 +1501,9 @@ static int ehci_process_itd(EHCIState *ehci, qemu_sglist_destroy(&ehci->isgl); return -1; /* avoid page pg + 1 */ } - ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK); + ptr2 = ehci_get_buf_addr(ehci, itd->bufptr_hi[pg + 1], + itd->bufptr[pg + 1], + ITD_BUFPTR_MASK); uint32_t len2 = off + len - 4096; uint32_t len1 = len - len2; qemu_sglist_add(&ehci->isgl, ptr1 + off, len1); @@ -1774,8 +1783,9 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); + memset(&itd, 0, sizeof(itd)); if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, - sizeof(EHCIitd) >> 2) < 0) { + ehci_itd_dwords(ehci)) < 0) { return -1; } ehci_trace_itd(ehci, entry, &itd); @@ -1785,8 +1795,8 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) } put_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, - sizeof(EHCIitd) >> 2); - ehci_set_fetch_addr(ehci, async, itd.next); + ehci_itd_dwords(ehci)); + ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci, itd.next)); ehci_set_state(ehci, async, EST_FETCHENTRY); return 1; diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 7fed206906..49176f3fd2 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -63,6 +63,7 @@ typedef struct EHCIitd { #define ITD_BUFPTR_MAXPKT_SH 0 #define ITD_BUFPTR_MULT_MASK 0x00000003 #define ITD_BUFPTR_MULT_SH 0 + uint32_t bufptr_hi[7]; } EHCIitd; /* From 11b30c864a2562af9708b6648dbf4d60124687f9 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:14 +0000 Subject: [PATCH 081/627] hw/usb/hcd-ehci: Implement 64-bit siTD descriptor addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EHCI supports 64-bit control data structure addressing when the 64-bit Addressing Capability bit in HCCPARAMS is set. In that mode, the CTRLDSSEGMENT register provides the upper 32 bits that are concatenated with 32-bit link pointer values to form full 64-bit descriptor addresses (EHCI 1.0, section 2.3.5 and Appendix B). siTD link pointers are stored as 32-bit values and must be expanded to full 64-bit descriptor addresses when 64-bit mode is enabled. Update the siTD traversal path to use ehci_get_desc_addr() when following link pointers. When 64-bit capability is disabled, descriptor addresses remain 32-bit and existing behaviour is unchanged. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 1a286c32e6..9a80c74972 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1823,7 +1823,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) warn_report("Skipping active siTD"); } - ehci_set_fetch_addr(ehci, async, sitd.next); + ehci_set_fetch_addr(ehci, async, ehci_get_desc_addr(ehci, sitd.next)); ehci_set_state(ehci, async, EST_FETCHENTRY); return 1; } From 11438bb2b44de3724cde65fc9dfbc423044d0019 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:16 +0000 Subject: [PATCH 082/627] hw/usb/hcd-ehci: Add ctrldssegment-default property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When 64-bit addressing is supported, the Linux EHCI driver programs the segment register to zero. See ehci_run function: https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-hcd.c The driver comment also notes that descriptor structures allocated from the DMA pool use segment zero semantics. Descriptor memory is allocated using the DMA API. The platform driver configures a 64-bit DMA mask so memory can be allocated above 4GB. See ehci_platform_probe function: https://github.com/torvalds/linux/blob/master/drivers/usb/host/ehci-platform.c On AST2700 platforms, system DRAM is mapped above 4GB at 0x400000000. As a result, descriptor addresses constructed directly from the guest EHCI registers do not match the actual system address used by the controller when fetching queue heads (QH) and queue element transfer descriptors (qTD). Add a ctrldssegment-default property so platforms can provide a descriptor address offset when constructing descriptor addresses. This allows systems where DRAM resides above 4GB to access EHCI descriptors correctly. The default value is zero, so existing machines are not affected. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/usb/hcd-ehci.c | 1 + hw/usb/hcd-ehci.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 9a80c74972..451a918e9f 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1162,6 +1162,7 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, "64-bit addressing capability is disabled\n"); return; } + val |= s->ctrldssegment_default; break; case ASYNCLISTADDR: diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 49176f3fd2..b5ac9c8670 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -268,6 +268,7 @@ struct EHCIState { */ bool migrate_fetch_addr_64bit; bool caps_64bit_addr; + uint32_t ctrldssegment_default; /* * EHCI spec version 1.0 Section 2.3 @@ -333,7 +334,9 @@ struct EHCIState { DEFINE_PROP_BOOL("x-migrate-fetch-addr-64bit", _state, \ ehci.migrate_fetch_addr_64bit, true), \ DEFINE_PROP_BOOL("caps-64bit-addr", _state, \ - ehci.caps_64bit_addr, false) + ehci.caps_64bit_addr, false), \ + DEFINE_PROP_UINT32("ctrldssegment-default", _state, \ + ehci.ctrldssegment_default, 0) extern const VMStateDescription vmstate_ehci; From 8b529eeccbe05b616da5ee86dc980038807c3a06 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:17 +0000 Subject: [PATCH 083/627] hw/arm/aspeed_ast27x0: Set EHCI ctrldssegment-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On AST2700 platforms, system DRAM is mapped above 4GB with a base address at 0x400000000. The Linux EHCI driver programs the segment register to zero when 64-bit addressing is supported. As a result, descriptor addresses derived from the EHCI registers do not include the DRAM base address. Descriptor memory is allocated through the DMA API with a 64-bit DMA mask, allowing descriptors to reside in DRAM above 4GB. On AST2700, EHCI queue heads (QH) and queue element transfer descriptors (qTD) are therefore placed at addresses starting from 0x400000000. Set the ctrldssegment-default property to "sc->memmap[ASPEED_DEV_SDRAM] >> 32" so the upper 32 bits of descriptor addresses are adjusted accordingly. This allows the emulated EHCI controller to construct correct system addresses when accessing descriptors in DRAM above 4GB. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index dddd7d2106..0b56d2bb67 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -870,6 +870,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) /* EHCI */ for (i = 0; i < sc->ehcis_num; i++) { + object_property_set_int(OBJECT(&s->ehci[i]), "ctrldssegment-default", + sc->memmap[ASPEED_DEV_SDRAM] >> 32, + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } From 39170be7cf5ac55ca079e60d136b9eb5d2a25ff3 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:19 +0000 Subject: [PATCH 084/627] hw/arm/aspeed_ast27x0: Enable 64-bit EHCI DMA addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2700 supports a 64-bit DRAM address space. Therefore, DMA transactions must be capable of accessing 64-bit addresses. Enable the "caps-64bit-addr" property for the EHCI controllers on AST2700 so that USB DMA operations can correctly handle 64-bit memory addresses. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 0b56d2bb67..7c062580f2 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -873,6 +873,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->ehci[i]), "ctrldssegment-default", sc->memmap[ASPEED_DEV_SDRAM] >> 32, &error_abort); + object_property_set_bool(OBJECT(&s->ehci[i]), "caps-64bit-addr", true, + &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } From 87c565334014d47ea987bd6a8c0919c03e4c4636 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Mon, 13 Jul 2026 03:27:20 +0000 Subject: [PATCH 085/627] tests/functional/aarch64/test_aspeed_ast2700: Add USB EHCI test for AST2700 A1/A2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a functional test to verify USB EHCI support on the AST2700 A2/A1 by attaching a USB keyboard device and checking its enumeration via lsusb. This introduces a helper routine that runs lsusb in the guest and validates that the emulated "QEMU USB Keyboard" is detected. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260713032704.3583103-11-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/aarch64/test_aspeed_ast2700a1.py | 7 +++++++ tests/functional/aarch64/test_aspeed_ast2700a2.py | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/functional/aarch64/test_aspeed_ast2700a1.py b/tests/functional/aarch64/test_aspeed_ast2700a1.py index ddddd2d47a..adbbef5cf1 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700a1.py +++ b/tests/functional/aarch64/test_aspeed_ast2700a1.py @@ -118,6 +118,11 @@ class AST2x00MachineSDK(QemuSystemTest): 'ip addr show dev eth2', 'inet 10.0.2.15/24') + def do_ast2700_usb_ehci_test(self): + exec_command_and_wait_for_pattern(self, + 'lsusb', + 'QEMU QEMU USB Keyboard') + def start_ast2700_test(self, name, bus_id): num_cpu = 4 load_images_list = [ @@ -161,10 +166,12 @@ class AST2x00MachineSDK(QemuSystemTest): self.archive_extract(self.ASSET_SDK_V1101_AST2700A1) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') + self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3') self.start_ast2700_test('ast2700-a1-image', 1) self.verify_openbmc_boot_and_login('ast2700-a1') self.do_ast2700_i2c_test(1) self.do_ast2700_pcie_test() + self.do_ast2700_usb_ehci_test() def test_aarch64_ast2700a1_evb_sdk_vbootrom_v11_01(self): self.set_machine('ast2700a1-evb') diff --git a/tests/functional/aarch64/test_aspeed_ast2700a2.py b/tests/functional/aarch64/test_aspeed_ast2700a2.py index 0fe04a6eca..5f9073c897 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700a2.py +++ b/tests/functional/aarch64/test_aspeed_ast2700a2.py @@ -121,6 +121,11 @@ class AST2x00MachineSDK(QemuSystemTest): 'ip addr show dev eth2', 'inet 10.0.2.15/24') + def do_ast2700_usb_ehci_test(self): + exec_command_and_wait_for_pattern(self, + 'lsusb', + 'QEMU QEMU USB Keyboard') + def start_ast2700_test(self, name, bus_id): num_cpu = 4 load_images_list = [ @@ -164,10 +169,12 @@ class AST2x00MachineSDK(QemuSystemTest): self.archive_extract(self.ASSET_SDK_V1101_AST2700A2) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') + self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3') self.start_ast2700_test('ast2700-default-image', 1) self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test(1) self.do_ast2700_pcie_test() + self.do_ast2700_usb_ehci_test() def test_aarch64_ast2700a2_evb_sdk_vbootrom_v11_01(self): self.set_machine('ast2700a2-evb') From 7a79a76286262fa25dcdf7fe585e4a963e67ceed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 14 Jul 2026 14:46:18 +0200 Subject: [PATCH 086/627] tests/qtest: aspeed_smc: Introduce read_page_mem_fn for page read helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This to prepare for fast-read variants. No functional change. Reviewed-by: Bin Meng Link: https://lore.kernel.org/qemu-devel/20260714124621.522948-2-clg@redhat.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-smc-utils.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c index c27d09e767..ed125741eb 100644 --- a/tests/qtest/aspeed-smc-utils.c +++ b/tests/qtest/aspeed-smc-utils.c @@ -186,6 +186,9 @@ static void read_page_mem(const AspeedSMCTestData *data, uint32_t addr, } } +typedef void (*read_page_mem_fn)(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page); + static void write_page_mem(const AspeedSMCTestData *data, uint32_t addr, uint32_t write_value) { @@ -327,9 +330,9 @@ void aspeed_smc_test_erase_all(const void *data) flash_reset(test_data); } -void aspeed_smc_test_write_page(const void *data) +static void test_write_page(const AspeedSMCTestData *test_data, + read_page_mem_fn reader) { - const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data; uint32_t my_page_addr = test_data->page_addr; uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; uint32_t page[FLASH_PAGE_SIZE / 4]; @@ -350,13 +353,13 @@ void aspeed_smc_test_write_page(const void *data) spi_ctrl_stop_user(test_data); /* Check what was written */ - read_page(test_data, my_page_addr, page); + reader(test_data, my_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, my_page_addr + i * 4); } /* Check some other page. It should be full of 0xff */ - read_page(test_data, some_page_addr, page); + reader(test_data, some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); } @@ -364,9 +367,14 @@ void aspeed_smc_test_write_page(const void *data) flash_reset(test_data); } -void aspeed_smc_test_read_page_mem(const void *data) +void aspeed_smc_test_write_page(const void *data) +{ + test_write_page(data, read_page); +} + +static void test_read_page_mem(const AspeedSMCTestData *test_data, + read_page_mem_fn reader) { - const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data; uint32_t my_page_addr = test_data->page_addr; uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; uint32_t page[FLASH_PAGE_SIZE / 4]; @@ -393,13 +401,13 @@ void aspeed_smc_test_read_page_mem(const void *data) spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); /* Check what was written */ - read_page_mem(test_data, my_page_addr, page); + reader(test_data, my_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, my_page_addr + i * 4); } /* Check some other page. It should be full of 0xff */ - read_page_mem(test_data, some_page_addr, page); + reader(test_data, some_page_addr, page); for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { g_assert_cmphex(page[i], ==, 0xffffffff); } @@ -407,6 +415,11 @@ void aspeed_smc_test_read_page_mem(const void *data) flash_reset(test_data); } +void aspeed_smc_test_read_page_mem(const void *data) +{ + test_read_page_mem(data, read_page_mem); +} + void aspeed_smc_test_write_page_mem(const void *data) { const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data; From afd36b9c073276cf57476e2c2b367c6289a62ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 14 Jul 2026 14:46:19 +0200 Subject: [PATCH 087/627] tests/qtest: aspeed_smc: Add fast-read test coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a spi_ctrl_set_fast_read() helper and add read_page_mem_fast_read (CTRL_FREADMODE with dummy byte) and write_page_fast_read (user-mode FAST_READ) tests. While at it, replace the license boilerplate with SPDX identifier. Reviewed-by: Bin Meng Link: https://lore.kernel.org/qemu-devel/20260714124621.522948-3-clg@redhat.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-smc-utils.c | 75 ++++++++++++++++++++++++++-------- tests/qtest/aspeed-smc-utils.h | 23 +++-------- tests/qtest/aspeed_smc-test.c | 39 ++++++++++-------- tests/qtest/ast2700-smc-test.c | 4 ++ 4 files changed, 90 insertions(+), 51 deletions(-) diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c index ed125741eb..07e65e0173 100644 --- a/tests/qtest/aspeed-smc-utils.c +++ b/tests/qtest/aspeed-smc-utils.c @@ -4,23 +4,7 @@ * * Copyright (C) 2016 IBM Corp. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-License-Identifier: MIT */ #include "qemu/osdep.h" @@ -107,6 +91,23 @@ static void spi_ctrl_setmode(const AspeedSMCTestData *data, uint8_t mode, spi_writel(data, ctrl_reg, ctrl); } +/* Set FREADMODE with a fast read command and 1 dummy byte */ +static void spi_ctrl_set_fast_read(const AspeedSMCTestData *data, uint8_t cmd) +{ + uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; + uint32_t ctrl = spi_readl(data, ctrl_reg); + uint32_t iomode = 0; + + ctrl &= ~(CTRL_USERMODE | (0xff << 16) | + (0x3 << CTRL_DUMMY_LOW_SHIFT) | + (0x1 << CTRL_DUMMY_HIGH_SHIFT) | + CTRL_IO_MODE_MASK); + ctrl |= CTRL_FREADMODE | (cmd << 16) | + (1 << CTRL_DUMMY_LOW_SHIFT) | + iomode; + spi_writel(data, ctrl_reg, ctrl); +} + static void spi_ctrl_start_user(const AspeedSMCTestData *data) { uint32_t ctrl_reg = R_CTRL0 + data->cs * 4; @@ -697,3 +698,43 @@ void aspeed_smc_test_write_page_qpi(const void *data) flash_reset(test_data); } +static void read_page_mem_fast_read(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_set_fast_read(data, FAST_READ); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, addr + i * 4)); + } +} + +void aspeed_smc_test_read_page_mem_fast_read(const void *data) +{ + test_read_page_mem(data, read_page_mem_fast_read); +} + +static void read_page_fast_read(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_start_user(data); + + flash_writeb(data, 0, EN_4BYTE_ADDR); + flash_writeb(data, 0, FAST_READ); + flash_writel(data, 0, make_be32(addr)); + /* 1 dummy byte for standard SPI fast-read */ + flash_writeb(data, 0, 0x00); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, 0)); + } + spi_ctrl_stop_user(data); +} + +void aspeed_smc_test_write_page_fast_read(const void *data) +{ + test_write_page(data, read_page_fast_read); +} diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h index e2fd8ff1bd..7504f5a525 100644 --- a/tests/qtest/aspeed-smc-utils.h +++ b/tests/qtest/aspeed-smc-utils.h @@ -4,23 +4,7 @@ * * Copyright (C) 2016 IBM Corp. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-License-Identifier: MIT */ #ifndef TESTS_ASPEED_SMC_UTILS_H @@ -44,6 +28,8 @@ #define CTRL_FREADMODE 0x1 #define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 +#define CTRL_DUMMY_LOW_SHIFT 6 +#define CTRL_DUMMY_HIGH_SHIFT 14 #define SR_WEL BIT(1) /* @@ -55,6 +41,7 @@ enum { WRDI = 0x4, BULK_ERASE = 0xc7, READ = 0x03, + FAST_READ = 0x0b, PP = 0x02, WRSR = 0x1, WREN = 0x6, @@ -90,5 +77,7 @@ void aspeed_smc_test_status_reg_write_protection(const void *data); void aspeed_smc_test_write_block_protect(const void *data); void aspeed_smc_test_write_block_protect_bottom_bit(const void *data); void aspeed_smc_test_write_page_qpi(const void *data); +void aspeed_smc_test_read_page_mem_fast_read(const void *data); +void aspeed_smc_test_write_page_fast_read(const void *data); #endif /* TESTS_ASPEED_SMC_UTILS_H */ diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 39af1df0ed..4697c493a8 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -4,23 +4,7 @@ * * Copyright (C) 2016 IBM Corp. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * SPDX-License-Identifier: MIT */ #include "qemu/osdep.h" @@ -68,6 +52,15 @@ static void test_palmetto_bmc(AspeedSMCTestData *data) data, aspeed_smc_test_read_status_reg); qtest_add_data_func("/ast2400/smc/status_reg_write_protection", data, aspeed_smc_test_status_reg_write_protection); + qtest_add_data_func("/ast2400/smc/read_page_mem_fast_read", + data, aspeed_smc_test_read_page_mem_fast_read); + qtest_add_data_func("/ast2400/smc/write_page_fast_read", + data, aspeed_smc_test_write_page_fast_read); + /* + * Block protect tests must be run last because the block protect + * state is not cleared by reset_memory() and silently prevents + * subsequent flash writes. + */ qtest_add_data_func("/ast2400/smc/write_block_protect", data, aspeed_smc_test_write_block_protect); qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit", @@ -115,6 +108,10 @@ static void test_ast2500_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_status_reg); qtest_add_data_func("/ast2500/smc/write_page_qpi", data, aspeed_smc_test_write_page_qpi); + qtest_add_data_func("/ast2500/smc/read_page_mem_fast_read", + data, aspeed_smc_test_read_page_mem_fast_read); + qtest_add_data_func("/ast2500/smc/write_page_fast_read", + data, aspeed_smc_test_write_page_fast_read); } static void test_ast2600_evb(AspeedSMCTestData *data) @@ -158,6 +155,10 @@ static void test_ast2600_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_status_reg); qtest_add_data_func("/ast2600/smc/write_page_qpi", data, aspeed_smc_test_write_page_qpi); + qtest_add_data_func("/ast2600/smc/read_page_mem_fast_read", + data, aspeed_smc_test_read_page_mem_fast_read); + qtest_add_data_func("/ast2600/smc/write_page_fast_read", + data, aspeed_smc_test_write_page_fast_read); } static void test_ast1030_evb(AspeedSMCTestData *data) @@ -201,6 +202,10 @@ static void test_ast1030_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_status_reg); qtest_add_data_func("/ast1030/smc/write_page_qpi", data, aspeed_smc_test_write_page_qpi); + qtest_add_data_func("/ast1030/smc/read_page_mem_fast_read", + data, aspeed_smc_test_read_page_mem_fast_read); + qtest_add_data_func("/ast1030/smc/write_page_fast_read", + data, aspeed_smc_test_write_page_fast_read); } int main(int argc, char **argv) diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c index 33fc47230e..9ad04b574c 100644 --- a/tests/qtest/ast2700-smc-test.c +++ b/tests/qtest/ast2700-smc-test.c @@ -52,6 +52,10 @@ static void test_ast2700_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_status_reg); qtest_add_data_func("/ast2700/smc/write_page_qpi", data, aspeed_smc_test_write_page_qpi); + qtest_add_data_func("/ast2700/smc/read_page_mem_fast_read", + data, aspeed_smc_test_read_page_mem_fast_read); + qtest_add_data_func("/ast2700/smc/write_page_fast_read", + data, aspeed_smc_test_write_page_fast_read); } int main(int argc, char **argv) From da5598227d06112f7d5ef6dcb567173158690565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 14 Jul 2026 14:46:20 +0200 Subject: [PATCH 088/627] tests/qtest: aspeed_smc: Add Dual Output Read (DOR) test coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add read_page_mem_dor (CTRL_FREADMODE with DOR command and dual data IO mode) and write_page_dor (user-mode DOR) tests. Reviewed-by: Bin Meng Link: https://lore.kernel.org/qemu-devel/20260714124621.522948-4-clg@redhat.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-smc-utils.c | 45 ++++++++++++++++++++++++++++++++++ tests/qtest/aspeed-smc-utils.h | 4 +++ tests/qtest/aspeed_smc-test.c | 16 ++++++++++++ tests/qtest/ast2700-smc-test.c | 4 +++ 4 files changed, 69 insertions(+) diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c index 07e65e0173..454224ec28 100644 --- a/tests/qtest/aspeed-smc-utils.c +++ b/tests/qtest/aspeed-smc-utils.c @@ -98,6 +98,10 @@ static void spi_ctrl_set_fast_read(const AspeedSMCTestData *data, uint8_t cmd) uint32_t ctrl = spi_readl(data, ctrl_reg); uint32_t iomode = 0; + if (cmd == DOR) { + iomode = CTRL_IO_DUAL_DATA; + } + ctrl &= ~(CTRL_USERMODE | (0xff << 16) | (0x3 << CTRL_DUMMY_LOW_SHIFT) | (0x1 << CTRL_DUMMY_HIGH_SHIFT) | @@ -738,3 +742,44 @@ void aspeed_smc_test_write_page_fast_read(const void *data) { test_write_page(data, read_page_fast_read); } + +static void read_page_mem_dor(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_set_fast_read(data, DOR); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, addr + i * 4)); + } +} + +void aspeed_smc_test_read_page_mem_dor(const void *data) +{ + test_read_page_mem(data, read_page_mem_dor); +} + +static void read_page_dor(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_start_user(data); + + flash_writeb(data, 0, EN_4BYTE_ADDR); + flash_writeb(data, 0, DOR); + flash_writel(data, 0, make_be32(addr)); + /* 1 dummy byte for standard SPI DOR */ + flash_writeb(data, 0, 0x00); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, 0)); + } + spi_ctrl_stop_user(data); +} + +void aspeed_smc_test_write_page_dor(const void *data) +{ + test_write_page(data, read_page_dor); +} diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h index 7504f5a525..04d3c7db5f 100644 --- a/tests/qtest/aspeed-smc-utils.h +++ b/tests/qtest/aspeed-smc-utils.h @@ -28,6 +28,7 @@ #define CTRL_FREADMODE 0x1 #define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 +#define CTRL_IO_DUAL_DATA BIT(29) #define CTRL_DUMMY_LOW_SHIFT 6 #define CTRL_DUMMY_HIGH_SHIFT 14 #define SR_WEL BIT(1) @@ -42,6 +43,7 @@ enum { BULK_ERASE = 0xc7, READ = 0x03, FAST_READ = 0x0b, + DOR = 0x3b, PP = 0x02, WRSR = 0x1, WREN = 0x6, @@ -79,5 +81,7 @@ void aspeed_smc_test_write_block_protect_bottom_bit(const void *data); void aspeed_smc_test_write_page_qpi(const void *data); void aspeed_smc_test_read_page_mem_fast_read(const void *data); void aspeed_smc_test_write_page_fast_read(const void *data); +void aspeed_smc_test_read_page_mem_dor(const void *data); +void aspeed_smc_test_write_page_dor(const void *data); #endif /* TESTS_ASPEED_SMC_UTILS_H */ diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 4697c493a8..a67cc5a999 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -56,6 +56,10 @@ static void test_palmetto_bmc(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_fast_read); qtest_add_data_func("/ast2400/smc/write_page_fast_read", data, aspeed_smc_test_write_page_fast_read); + qtest_add_data_func("/ast2400/smc/read_page_mem_dor", + data, aspeed_smc_test_read_page_mem_dor); + qtest_add_data_func("/ast2400/smc/write_page_dor", + data, aspeed_smc_test_write_page_dor); /* * Block protect tests must be run last because the block protect * state is not cleared by reset_memory() and silently prevents @@ -112,6 +116,10 @@ static void test_ast2500_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_fast_read); qtest_add_data_func("/ast2500/smc/write_page_fast_read", data, aspeed_smc_test_write_page_fast_read); + qtest_add_data_func("/ast2500/smc/read_page_mem_dor", + data, aspeed_smc_test_read_page_mem_dor); + qtest_add_data_func("/ast2500/smc/write_page_dor", + data, aspeed_smc_test_write_page_dor); } static void test_ast2600_evb(AspeedSMCTestData *data) @@ -159,6 +167,10 @@ static void test_ast2600_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_fast_read); qtest_add_data_func("/ast2600/smc/write_page_fast_read", data, aspeed_smc_test_write_page_fast_read); + qtest_add_data_func("/ast2600/smc/read_page_mem_dor", + data, aspeed_smc_test_read_page_mem_dor); + qtest_add_data_func("/ast2600/smc/write_page_dor", + data, aspeed_smc_test_write_page_dor); } static void test_ast1030_evb(AspeedSMCTestData *data) @@ -206,6 +218,10 @@ static void test_ast1030_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_fast_read); qtest_add_data_func("/ast1030/smc/write_page_fast_read", data, aspeed_smc_test_write_page_fast_read); + qtest_add_data_func("/ast1030/smc/read_page_mem_dor", + data, aspeed_smc_test_read_page_mem_dor); + qtest_add_data_func("/ast1030/smc/write_page_dor", + data, aspeed_smc_test_write_page_dor); } int main(int argc, char **argv) diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c index 9ad04b574c..bd9d3f7905 100644 --- a/tests/qtest/ast2700-smc-test.c +++ b/tests/qtest/ast2700-smc-test.c @@ -56,6 +56,10 @@ static void test_ast2700_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_fast_read); qtest_add_data_func("/ast2700/smc/write_page_fast_read", data, aspeed_smc_test_write_page_fast_read); + qtest_add_data_func("/ast2700/smc/read_page_mem_dor", + data, aspeed_smc_test_read_page_mem_dor); + qtest_add_data_func("/ast2700/smc/write_page_dor", + data, aspeed_smc_test_write_page_dor); } int main(int argc, char **argv) From a15167a329f7f9bf5a637ae8186ed51e31e5eb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 14 Jul 2026 14:46:21 +0200 Subject: [PATCH 089/627] tests/qtest: aspeed_smc: Add Quad Output Read (QOR) test coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add read_page_mem_qor (CTRL_FREADMODE with QOR command and quad data IO mode) and write_page_qor (user-mode QOR) tests. Reviewed-by: Bin Meng Link: https://lore.kernel.org/qemu-devel/20260714124621.522948-5-clg@redhat.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-smc-utils.c | 43 ++++++++++++++++++++++++++++++++++ tests/qtest/aspeed-smc-utils.h | 4 ++++ tests/qtest/aspeed_smc-test.c | 16 +++++++++++++ tests/qtest/ast2700-smc-test.c | 4 ++++ 4 files changed, 67 insertions(+) diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c index 454224ec28..6d75a95578 100644 --- a/tests/qtest/aspeed-smc-utils.c +++ b/tests/qtest/aspeed-smc-utils.c @@ -100,6 +100,8 @@ static void spi_ctrl_set_fast_read(const AspeedSMCTestData *data, uint8_t cmd) if (cmd == DOR) { iomode = CTRL_IO_DUAL_DATA; + } else if (cmd == QOR) { + iomode = CTRL_IO_QUAD_DATA; } ctrl &= ~(CTRL_USERMODE | (0xff << 16) | @@ -783,3 +785,44 @@ void aspeed_smc_test_write_page_dor(const void *data) { test_write_page(data, read_page_dor); } + +static void read_page_mem_qor(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_set_fast_read(data, QOR); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, addr + i * 4)); + } +} + +void aspeed_smc_test_read_page_mem_qor(const void *data) +{ + test_read_page_mem(data, read_page_mem_qor); +} + +static void read_page_qor(const AspeedSMCTestData *data, + uint32_t addr, uint32_t *page) +{ + int i; + + spi_ctrl_start_user(data); + + flash_writeb(data, 0, EN_4BYTE_ADDR); + flash_writeb(data, 0, QOR); + flash_writel(data, 0, make_be32(addr)); + /* 1 dummy byte for standard SPI QOR */ + flash_writeb(data, 0, 0x00); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(flash_readl(data, 0)); + } + spi_ctrl_stop_user(data); +} + +void aspeed_smc_test_write_page_qor(const void *data) +{ + test_write_page(data, read_page_qor); +} diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h index 04d3c7db5f..19c557b822 100644 --- a/tests/qtest/aspeed-smc-utils.h +++ b/tests/qtest/aspeed-smc-utils.h @@ -28,6 +28,7 @@ #define CTRL_FREADMODE 0x1 #define CTRL_WRITEMODE 0x2 #define CTRL_USERMODE 0x3 +#define CTRL_IO_QUAD_DATA BIT(30) #define CTRL_IO_DUAL_DATA BIT(29) #define CTRL_DUMMY_LOW_SHIFT 6 #define CTRL_DUMMY_HIGH_SHIFT 14 @@ -44,6 +45,7 @@ enum { READ = 0x03, FAST_READ = 0x0b, DOR = 0x3b, + QOR = 0x6b, PP = 0x02, WRSR = 0x1, WREN = 0x6, @@ -83,5 +85,7 @@ void aspeed_smc_test_read_page_mem_fast_read(const void *data); void aspeed_smc_test_write_page_fast_read(const void *data); void aspeed_smc_test_read_page_mem_dor(const void *data); void aspeed_smc_test_write_page_dor(const void *data); +void aspeed_smc_test_read_page_mem_qor(const void *data); +void aspeed_smc_test_write_page_qor(const void *data); #endif /* TESTS_ASPEED_SMC_UTILS_H */ diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index a67cc5a999..59c96bd68a 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -60,6 +60,10 @@ static void test_palmetto_bmc(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_dor); qtest_add_data_func("/ast2400/smc/write_page_dor", data, aspeed_smc_test_write_page_dor); + qtest_add_data_func("/ast2400/smc/read_page_mem_qor", + data, aspeed_smc_test_read_page_mem_qor); + qtest_add_data_func("/ast2400/smc/write_page_qor", + data, aspeed_smc_test_write_page_qor); /* * Block protect tests must be run last because the block protect * state is not cleared by reset_memory() and silently prevents @@ -120,6 +124,10 @@ static void test_ast2500_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_dor); qtest_add_data_func("/ast2500/smc/write_page_dor", data, aspeed_smc_test_write_page_dor); + qtest_add_data_func("/ast2500/smc/read_page_mem_qor", + data, aspeed_smc_test_read_page_mem_qor); + qtest_add_data_func("/ast2500/smc/write_page_qor", + data, aspeed_smc_test_write_page_qor); } static void test_ast2600_evb(AspeedSMCTestData *data) @@ -171,6 +179,10 @@ static void test_ast2600_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_dor); qtest_add_data_func("/ast2600/smc/write_page_dor", data, aspeed_smc_test_write_page_dor); + qtest_add_data_func("/ast2600/smc/read_page_mem_qor", + data, aspeed_smc_test_read_page_mem_qor); + qtest_add_data_func("/ast2600/smc/write_page_qor", + data, aspeed_smc_test_write_page_qor); } static void test_ast1030_evb(AspeedSMCTestData *data) @@ -222,6 +234,10 @@ static void test_ast1030_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_dor); qtest_add_data_func("/ast1030/smc/write_page_dor", data, aspeed_smc_test_write_page_dor); + qtest_add_data_func("/ast1030/smc/read_page_mem_qor", + data, aspeed_smc_test_read_page_mem_qor); + qtest_add_data_func("/ast1030/smc/write_page_qor", + data, aspeed_smc_test_write_page_qor); } int main(int argc, char **argv) diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c index bd9d3f7905..f85077e04f 100644 --- a/tests/qtest/ast2700-smc-test.c +++ b/tests/qtest/ast2700-smc-test.c @@ -60,6 +60,10 @@ static void test_ast2700_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_dor); qtest_add_data_func("/ast2700/smc/write_page_dor", data, aspeed_smc_test_write_page_dor); + qtest_add_data_func("/ast2700/smc/read_page_mem_qor", + data, aspeed_smc_test_read_page_mem_qor); + qtest_add_data_func("/ast2700/smc/write_page_qor", + data, aspeed_smc_test_write_page_qor); } int main(int argc, char **argv) From ffcbeb1f5a954284519a9ea1942466042b106544 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:01 +0000 Subject: [PATCH 090/627] hw/misc/aspeed_scu: Introduce Aspeed2700SCUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce Aspeed2700SCUState as an AST2700-specific subclass of AspeedSCUState. Currently, AST1700 and AST2700 reuse the generic AspeedSCUState. However, AST2700 requires SCU functionality that is specific to the platform, particularly for interactions with its coprocessors. Introduce a dedicated Aspeed2700SCUState to provide an extension point for AST2700-specific functionality while keeping the generic AspeedSCUState unchanged. Subsequent patches will migrate AST2700 users to the new subclass and move AST2700-specific code into it. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_scu.c | 8 +++++++- include/hw/misc/aspeed_scu.h | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index 5dbf81c0ce..efe1d6315b 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -930,6 +930,11 @@ static void aspeed_ast2700_scu_reset_hold(Object *obj, ResetType type) s->regs[AST2700_HW_STRAP1] = s->hw_strap1; } +static void aspeed_2700_scu_realize(DeviceState *dev, Error **errp) +{ + aspeed_scu_realize(dev, errp); +} + static void aspeed_2700_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -937,6 +942,7 @@ static void aspeed_2700_scu_class_init(ObjectClass *klass, const void *data) AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); dc->desc = "ASPEED 2700 System Control Unit"; + dc->realize = aspeed_2700_scu_realize; rc->phases.hold = aspeed_ast2700_scu_reset_hold; asc->resets = ast2700_a0_resets; asc->calc_hpll = aspeed_2600_scu_calc_hpll; @@ -1161,7 +1167,7 @@ static const TypeInfo aspeed_scu_types[] = { { .name = TYPE_ASPEED_2700_SCU, .parent = TYPE_ASPEED_SCU, - .instance_size = sizeof(AspeedSCUState), + .instance_size = sizeof(Aspeed2700SCUState), .class_init = aspeed_2700_scu_class_init, }, { diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index c30940ab76..904549465f 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -20,6 +20,7 @@ OBJECT_DECLARE_TYPE(AspeedSCUState, AspeedSCUClass, ASPEED_SCU) #define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500" #define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600" #define TYPE_ASPEED_2700_SCU TYPE_ASPEED_SCU "-ast2700" +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2700SCUState, ASPEED_2700_SCU) #define TYPE_ASPEED_2700_SCUIO TYPE_ASPEED_SCU "io" "-ast2700" #define TYPE_ASPEED_1030_SCU TYPE_ASPEED_SCU "-ast1030" @@ -41,6 +42,10 @@ struct AspeedSCUState { uint32_t hw_prot_key; }; +struct Aspeed2700SCUState { + AspeedSCUState parent_obj; +}; + #define AST2400_A1_SILICON_REV 0x02010303U #define AST2500_A1_SILICON_REV 0x04010303U #define AST2600_A3_SILICON_REV 0x05030303U From 69ba4d5b967cbc7995ac30775fdf4bc1e7350788 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:02 +0000 Subject: [PATCH 091/627] hw/arm/aspeed: Use Aspeed2700SCUState for AST2700 users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that Aspeed2700SCUState has been introduced, update the AST1700 and AST27x0 SoCs to instantiate the AST2700-specific SCU subclass instead of the generic AspeedSCUState. Also update the AST27x0 FC board to link the SSP/TSP coprocessors to the AST2700 SCU instance. This prepares the AST2700 platform for subsequent patches that move AST2700-specific SCU functionality into the subclass. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 4 ++-- hw/arm/aspeed_ast27x0.c | 16 ++++++++-------- include/hw/arm/aspeed_ast1700.h | 2 +- include/hw/arm/aspeed_soc.h | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 7d9fade68d..8d49bb95d6 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -158,7 +158,7 @@ static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) object_property_set_link(OBJECT(&s->ssp), "sram", OBJECT(&psp->sram), &error_abort); object_property_set_link(OBJECT(&s->ssp), "scu", - OBJECT(&psp->scu), &error_abort); + OBJECT(&s->ca35.scu), &error_abort); if (!qdev_realize(DEVICE(&s->ssp), NULL, errp)) { return false; } @@ -190,7 +190,7 @@ static bool ast2700fc_tsp_init(MachineState *machine, Error **errp) object_property_set_link(OBJECT(&s->tsp), "sram", OBJECT(&psp->sram), &error_abort); object_property_set_link(OBJECT(&s->tsp), "scu", - OBJECT(&psp->scu), &error_abort); + OBJECT(&s->ca35.scu), &error_abort); if (!qdev_realize(DEVICE(&s->tsp), NULL, errp)) { return false; } diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 7c062580f2..6365dbd638 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -435,12 +435,12 @@ static void aspeed_soc_ast2700_init(Object *obj) object_initialize_child(obj, "gic", &a->gic, gicv3_class_name()); - object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU); - qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", + object_initialize_child(obj, "scu", &a->scu, TYPE_ASPEED_2700_SCU); + qdev_prop_set_uint32(DEVICE(&a->scu), "silicon-rev", sc->silicon_rev); - object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), + object_property_add_alias(obj, "hw-strap1", OBJECT(&a->scu), "hw-strap1"); - object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu), + object_property_add_alias(obj, "hw-prot-key", OBJECT(&a->scu), "hw-prot-key"); object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO); @@ -808,10 +808,10 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_DEV_VBOOTROM], &s->vbootrom); /* SCU */ - if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { + if (!sysbus_realize(SYS_BUS_DEVICE(&a->scu), errp)) { return; } - aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->scu), 0, sc->memmap[ASPEED_DEV_SCU]); /* SCU1 */ @@ -934,7 +934,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]); hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize; - object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu), + object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&a->scu), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; @@ -1037,7 +1037,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_EMMC)); /* Timer */ - object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), + object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&a->scu), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; diff --git a/include/hw/arm/aspeed_ast1700.h b/include/hw/arm/aspeed_ast1700.h index f7bd4e8650..39c5977cf1 100644 --- a/include/hw/arm/aspeed_ast1700.h +++ b/include/hw/arm/aspeed_ast1700.h @@ -41,7 +41,7 @@ struct AspeedAST1700SoCState { MemoryRegion sram; AspeedSMCState spi; AspeedADCState adc; - AspeedSCUState scu; + Aspeed2700SCUState scu; AspeedGPIOState gpio; AspeedSGPIOState sgpiom[AST1700_SGPIO_NUM]; AspeedI2CState i2c; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 41dc04e293..cd68c7f1ca 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -151,6 +151,7 @@ struct Aspeed27x0SoCState { AspeedINTCState intcioexp[ASPEED_IOEXP_NUM]; GICv3State gic; MemoryRegion dram_empty; + Aspeed2700SCUState scu; }; #define TYPE_ASPEED27X0_SOC "aspeed27x0-soc" From ee3f2ace6fc8c9e079fd49b78ea6f71edb225fdd Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:04 +0000 Subject: [PATCH 092/627] hw/arm/aspeed_ast27x0: Move SCU link into AST27x0 coprocessors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SCU link is only needed by the AST27x0 SSP/TSP coprocessors for their AST2700-specific SCU alias window. Move the link property from the common AspeedCoprocessorState into Aspeed27x0CoprocessorState, so the generic coprocessor model no longer contains an AST2700-specific dependency. Also validate that the SCU link has been provided during device realize before accessing it. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-ssp.c | 20 ++++++++++++++++---- hw/arm/aspeed_ast27x0-tsp.c | 20 ++++++++++++++++---- hw/arm/aspeed_coprocessor_common.c | 2 -- include/hw/arm/aspeed_coprocessor.h | 5 +++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c index 68a8ab26f7..28bb59c8c5 100644 --- a/hw/arm/aspeed_ast27x0-ssp.c +++ b/hw/arm/aspeed_ast27x0-ssp.c @@ -167,6 +167,12 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->scu) { + error_setg(errp, TYPE_ASPEED27X0SSP_COPROCESSOR + ": 'scu' link is not set"); + return; + } + /* AST27X0 SSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -195,11 +201,11 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) &s->sram_alias); /* SCU */ - memory_region_init_alias(&s->scu_alias, OBJECT(s), "scu.alias", - &s->scu->iomem, 0, - memory_region_size(&s->scu->iomem)); + memory_region_init_alias(&a->scu_alias, OBJECT(a), "scu.alias", + &a->scu->parent_obj.iomem, 0, + memory_region_size(&a->scu->parent_obj.iomem)); memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCU], - &s->scu_alias); + &a->scu_alias); /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { @@ -275,6 +281,11 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) sc->memmap[ASPEED_DEV_OTP], 0x800); } +static const Property aspeed_27x0_coprocessor_properties[] = { + DEFINE_PROP_LINK("scu", Aspeed27x0CoprocessorState, scu, + TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), +}; + static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, const void *data) { @@ -288,6 +299,7 @@ static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, /* Reason: The Aspeed Coprocessor can only be instantiated from a board */ dc->user_creatable = false; dc->realize = aspeed_soc_ast27x0ssp_realize; + device_class_set_props(dc, aspeed_27x0_coprocessor_properties); sc->valid_cpu_types = valid_cpu_types; sc->irqmap = aspeed_soc_ast27x0ssp_irqmap; diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c index b8a4f7c91d..f5c4a02161 100644 --- a/hw/arm/aspeed_ast27x0-tsp.c +++ b/hw/arm/aspeed_ast27x0-tsp.c @@ -167,6 +167,12 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->scu) { + error_setg(errp, TYPE_ASPEED27X0TSP_COPROCESSOR + ": 'scu' link is not set"); + return; + } + /* AST27X0 TSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -195,11 +201,11 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) &s->sram_alias); /* SCU */ - memory_region_init_alias(&s->scu_alias, OBJECT(s), "scu.alias", - &s->scu->iomem, 0, - memory_region_size(&s->scu->iomem)); + memory_region_init_alias(&a->scu_alias, OBJECT(a), "scu.alias", + &a->scu->parent_obj.iomem, 0, + memory_region_size(&a->scu->parent_obj.iomem)); memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCU], - &s->scu_alias); + &a->scu_alias); /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { @@ -275,6 +281,11 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) sc->memmap[ASPEED_DEV_OTP], 0x800); } +static const Property aspeed_27x0_coprocessor_properties[] = { + DEFINE_PROP_LINK("scu", Aspeed27x0CoprocessorState, scu, + TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), +}; + static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, const void *data) { @@ -288,6 +299,7 @@ static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, /* Reason: The Aspeed Coprocessor can only be instantiated from a board */ dc->user_creatable = false; dc->realize = aspeed_soc_ast27x0tsp_realize; + device_class_set_props(dc, aspeed_27x0_coprocessor_properties); sc->valid_cpu_types = valid_cpu_types; sc->irqmap = aspeed_soc_ast27x0tsp_irqmap; diff --git a/hw/arm/aspeed_coprocessor_common.c b/hw/arm/aspeed_coprocessor_common.c index a0a4c73d08..43026d2a55 100644 --- a/hw/arm/aspeed_coprocessor_common.c +++ b/hw/arm/aspeed_coprocessor_common.c @@ -27,8 +27,6 @@ static const Property aspeed_coprocessor_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_LINK("sram", AspeedCoprocessorState, sram, TYPE_MEMORY_REGION, MemoryRegion *), - DEFINE_PROP_LINK("scu", AspeedCoprocessorState, scu, TYPE_ASPEED_SCU, - AspeedSCUState *), DEFINE_PROP_LINK("uart", AspeedCoprocessorState, uart, TYPE_SERIAL_MM, SerialMM *), DEFINE_PROP_INT32("uart-dev", AspeedCoprocessorState, uart_dev, 0), diff --git a/include/hw/arm/aspeed_coprocessor.h b/include/hw/arm/aspeed_coprocessor.h index ac58a5f424..adfc3c4512 100644 --- a/include/hw/arm/aspeed_coprocessor.h +++ b/include/hw/arm/aspeed_coprocessor.h @@ -20,10 +20,8 @@ struct AspeedCoprocessorState { MemoryRegion *sram; MemoryRegion sram_alias; MemoryRegion uart_alias; - MemoryRegion scu_alias; Clock *sysclk; - AspeedSCUState *scu; AspeedSCUState scuio; AspeedTimerCtrlState timerctrl; SerialMM *uart; @@ -52,6 +50,9 @@ struct Aspeed27x0CoprocessorState { UnimplementedDeviceState otp; ARMv7MState armv7m; + + MemoryRegion scu_alias; + Aspeed2700SCUState *scu; }; #define TYPE_ASPEED27X0SSP_COPROCESSOR "aspeed27x0ssp-coprocessor" From 2fbefe0eb4a39cd3e2ce301602e94e3b2bbe9a9b Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:05 +0000 Subject: [PATCH 093/627] hw/misc/aspeed_scu: Add separate reset handler for AST2700 SCUIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a dedicated reset handler for SCUIO. Previously, SCU and SCUIO shared the same reset handler. This no longer fits the AST2700 design, where SCU uses the Aspeed2700SCUState subclass and will handle coprocessor-related control in future changes. Since these controls are defined in SCU (not SCUIO), SCU and SCUIO should not share the same reset logic. This change gives SCUIO its own reset handler and prepares for upcoming SCU-specific functionality. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_scu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index efe1d6315b..ca93c3699d 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -1069,6 +1069,16 @@ static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = { [AST2700_SCUIO_FREQ_CNT_CTL] = 0x00000080, }; +static void aspeed_ast2700_scuio_reset_hold(Object *obj, ResetType type) +{ + AspeedSCUState *s = ASPEED_SCU(obj); + AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(obj); + + memcpy(s->regs, asc->resets, asc->nr_regs * 4); + s->regs[AST2700_SILICON_REV] = s->silicon_rev; + s->regs[AST2700_HW_STRAP1] = s->hw_strap1; +} + static void aspeed_2700_scuio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1076,7 +1086,7 @@ static void aspeed_2700_scuio_class_init(ObjectClass *klass, const void *data) AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); dc->desc = "ASPEED 2700 System Control Unit I/O"; - rc->phases.hold = aspeed_ast2700_scu_reset_hold; + rc->phases.hold = aspeed_ast2700_scuio_reset_hold; asc->resets = ast2700_a0_resets_io; asc->calc_hpll = aspeed_2600_scu_calc_hpll; asc->get_apb = aspeed_2700_scuio_get_apb_freq; From 7bb309ed43b06a75f8904011e7385379f4377c67 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:07 +0000 Subject: [PATCH 094/627] hw/arm/aspeed_ast27x0: Pass realized PSP SoC to SSP/TSP initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the realized PSP SoC to the SSP/TSP initialization helpers instead of retrieving it from the MachineState. This makes the dependency explicit, since the SSP and TSP coprocessors use resources owned by the PSP SoC, including the UARTs, SRAM, SCU and SCUIO. The PSP SoC must therefore be realized before the coprocessors are initialized. No functional change. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 8d49bb95d6..58d0b4d7cd 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -134,11 +134,9 @@ static bool ast2700fc_ca35_init(MachineState *machine, Error **errp) return true; } -static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) +static bool ast2700fc_ssp_init(Ast2700FCState *s, AspeedSoCState *psp, + Error **errp) { - Ast2700FCState *s = AST2700FC(machine); - AspeedSoCState *psp = ASPEED_SOC(&s->ca35); - s->ssp_sysclk = clock_new(OBJECT(s), "SSP_SYSCLK"); clock_set_hz(s->ssp_sysclk, 200000000ULL); @@ -166,11 +164,9 @@ static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) return true; } -static bool ast2700fc_tsp_init(MachineState *machine, Error **errp) +static bool ast2700fc_tsp_init(Ast2700FCState *s, AspeedSoCState *psp, + Error **errp) { - Ast2700FCState *s = AST2700FC(machine); - AspeedSoCState *psp = ASPEED_SOC(&s->ca35); - s->tsp_sysclk = clock_new(OBJECT(s), "TSP_SYSCLK"); clock_set_hz(s->tsp_sysclk, 200000000ULL); @@ -200,9 +196,19 @@ static bool ast2700fc_tsp_init(MachineState *machine, Error **errp) static void ast2700fc_init(MachineState *machine) { + Ast2700FCState *s = AST2700FC(machine); + AspeedSoCState *psp; + ast2700fc_ca35_init(machine, &error_abort); - ast2700fc_ssp_init(machine, &error_abort); - ast2700fc_tsp_init(machine, &error_abort); + + /* + * SSP and TSP use resources owned by the PSP SoC, such as UART, + * SRAM, SCU and SCUIO. Therefore the PSP SoC must be realized + * before the coprocessors are initialized. + */ + psp = ASPEED_SOC(&s->ca35); + ast2700fc_ssp_init(s, psp, &error_abort); + ast2700fc_tsp_init(s, psp, &error_abort); } static void ast2700fc_class_init(ObjectClass *oc, const void *data) From dba6f5c1df462830bf6daa82d7c08c34f76cc164 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:08 +0000 Subject: [PATCH 095/627] hw/arm/ast27x0: Share single SCUIO instance across PSP, SSP, and TSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2700 has a single SCUIO hardware block, memory-mapped at 0x14C02000–0x14C03FFF from the perspective of the main CA35 processor (PSP). The SSP and TSP coprocessors access this same SCUIO block at different addresses: 0x74C02000–0x74C03FFF. Previously, each subsystem (PSP, SSP, and TSP) instantiated its own SCUIO device, resulting in three independent SCUIO instances in the QEMU model. In real hardware, however, only a single SCUIO exists and is shared among all processors. This commit reworks the SCUIO model to correctly reflect the hardware behavior by allowing SSP and TSP to reference the PSP’s SCUIO instance. The following changes are introduced: - Add a scuio property to Aspeed27x0CoprocessorState for linking the coprocessor to the PSP’s SCUIO instance. - Replace per-coprocessor SCUIO instantiation with a shared SCUIO link. - Add "MemoryRegion scuio_alias" to model address remapping for SSP and TSP. - Create SCUIO alias regions in both SSP and TSP coprocessors and map them at 0x74C02000 to mirror the PSP’s SCUIO registers. - Ensure the SCUIO device in PSP is realized before SSP/TSP alias setup. With this change, PSP, SSP, and TSP now share a consistent SCUIO state, matching the single-SCUIO hardware design of AST2700. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 4 ++++ hw/arm/aspeed_ast27x0-ssp.c | 20 +++++++++++++++----- hw/arm/aspeed_ast27x0-tsp.c | 20 +++++++++++++++----- include/hw/arm/aspeed_coprocessor.h | 4 ++-- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 58d0b4d7cd..d14a42ebca 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -157,6 +157,8 @@ static bool ast2700fc_ssp_init(Ast2700FCState *s, AspeedSoCState *psp, OBJECT(&psp->sram), &error_abort); object_property_set_link(OBJECT(&s->ssp), "scu", OBJECT(&s->ca35.scu), &error_abort); + object_property_set_link(OBJECT(&s->ssp), "scuio", + OBJECT(&psp->scuio), &error_abort); if (!qdev_realize(DEVICE(&s->ssp), NULL, errp)) { return false; } @@ -187,6 +189,8 @@ static bool ast2700fc_tsp_init(Ast2700FCState *s, AspeedSoCState *psp, OBJECT(&psp->sram), &error_abort); object_property_set_link(OBJECT(&s->tsp), "scu", OBJECT(&s->ca35.scu), &error_abort); + object_property_set_link(OBJECT(&s->tsp), "scuio", + OBJECT(&psp->scuio), &error_abort); if (!qdev_realize(DEVICE(&s->tsp), NULL, errp)) { return false; } diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c index 28bb59c8c5..fa492f1797 100644 --- a/hw/arm/aspeed_ast27x0-ssp.c +++ b/hw/arm/aspeed_ast27x0-ssp.c @@ -142,8 +142,6 @@ static void aspeed_soc_ast27x0ssp_init(Object *obj) TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "ipc1", &a->ipc[1], TYPE_UNIMPLEMENTED_DEVICE); - object_initialize_child(obj, "scuio", &a->scuio, - TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "pric0", &a->pric[0], TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "pric1", &a->pric[1], @@ -173,6 +171,12 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->scuio) { + error_setg(errp, TYPE_ASPEED27X0SSP_COPROCESSOR + ": 'scuio' link is not set"); + return; + } + /* AST27X0 SSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -207,6 +211,13 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCU], &a->scu_alias); + /* SCUIO */ + memory_region_init_alias(&a->scuio_alias, OBJECT(a), "scuio.alias", + &a->scuio->iomem, 0, + memory_region_size(&a->scuio->iomem)); + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCUIO], + &a->scuio_alias); + /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { return; @@ -267,9 +278,6 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[1]), "aspeed.ipc1", sc->memmap[ASPEED_DEV_IPC1], 0x1000); - aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->scuio), - "aspeed.scuio", - sc->memmap[ASPEED_DEV_SCUIO], 0x1000); aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->pric[0]), "aspeed.pric0", sc->memmap[ASPEED_DEV_PRIC0], 0x1000); @@ -284,6 +292,8 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) static const Property aspeed_27x0_coprocessor_properties[] = { DEFINE_PROP_LINK("scu", Aspeed27x0CoprocessorState, scu, TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), + DEFINE_PROP_LINK("scuio", Aspeed27x0CoprocessorState, scuio, + TYPE_ASPEED_SCU, AspeedSCUState *), }; static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c index f5c4a02161..3a98bd232c 100644 --- a/hw/arm/aspeed_ast27x0-tsp.c +++ b/hw/arm/aspeed_ast27x0-tsp.c @@ -142,8 +142,6 @@ static void aspeed_soc_ast27x0tsp_init(Object *obj) TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "ipc1", &a->ipc[1], TYPE_UNIMPLEMENTED_DEVICE); - object_initialize_child(obj, "scuio", &a->scuio, - TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "pric0", &a->pric[0], TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "pric1", &a->pric[1], @@ -173,6 +171,12 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->scuio) { + error_setg(errp, TYPE_ASPEED27X0TSP_COPROCESSOR + ": 'scuio' link is not set"); + return; + } + /* AST27X0 TSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -207,6 +211,13 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCU], &a->scu_alias); + /* SCUIO */ + memory_region_init_alias(&a->scuio_alias, OBJECT(a), "scuio.alias", + &a->scuio->iomem, 0, + memory_region_size(&a->scuio->iomem)); + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SCUIO], + &a->scuio_alias); + /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { return; @@ -267,9 +278,6 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[1]), "aspeed.ipc1", sc->memmap[ASPEED_DEV_IPC1], 0x1000); - aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->scuio), - "aspeed.scuio", - sc->memmap[ASPEED_DEV_SCUIO], 0x1000); aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->pric[0]), "aspeed.pric0", sc->memmap[ASPEED_DEV_PRIC0], 0x1000); @@ -284,6 +292,8 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) static const Property aspeed_27x0_coprocessor_properties[] = { DEFINE_PROP_LINK("scu", Aspeed27x0CoprocessorState, scu, TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), + DEFINE_PROP_LINK("scuio", Aspeed27x0CoprocessorState, scuio, + TYPE_ASPEED_SCU, AspeedSCUState *), }; static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, diff --git a/include/hw/arm/aspeed_coprocessor.h b/include/hw/arm/aspeed_coprocessor.h index adfc3c4512..b77ea06e7f 100644 --- a/include/hw/arm/aspeed_coprocessor.h +++ b/include/hw/arm/aspeed_coprocessor.h @@ -22,7 +22,6 @@ struct AspeedCoprocessorState { MemoryRegion uart_alias; Clock *sysclk; - AspeedSCUState scuio; AspeedTimerCtrlState timerctrl; SerialMM *uart; int uart_dev; @@ -45,14 +44,15 @@ struct Aspeed27x0CoprocessorState { AspeedCoprocessorState parent; AspeedINTCState intc[2]; UnimplementedDeviceState ipc[2]; - UnimplementedDeviceState scuio; UnimplementedDeviceState pric[2]; UnimplementedDeviceState otp; ARMv7MState armv7m; MemoryRegion scu_alias; + MemoryRegion scuio_alias; Aspeed2700SCUState *scu; + AspeedSCUState *scuio; }; #define TYPE_ASPEED27X0SSP_COPROCESSOR "aspeed27x0ssp-coprocessor" From ab480be728c2fea79121d1448bda25f1bdbd759c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:09 +0000 Subject: [PATCH 096/627] hw/arm/ast27x0: Share FMC controller with SSP and TSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2700 provides a single FMC controller shared by the main CA35 processor (PSP) and the SSP/TSP coprocessors. >From the PSP perspective, the FMC controller is memory-mapped at 0x14000000–0x140000FF. The SSP and TSP access the same controller through a different address window at 0x74000000–0x740000FF. This change allows the SSP and TSP SoC models to reference the existing PSP FMC instance instead of creating independent controllers. An MMIO alias is added in the SSP and TSP address spaces to map their FMC access window to the shared FMC device. This ensures consistent FMC state across PSP, SSP, and TSP and matches the AST2700 hardware design. Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 4 ++++ hw/arm/aspeed_ast27x0-ssp.c | 16 ++++++++++++++++ hw/arm/aspeed_ast27x0-tsp.c | 16 ++++++++++++++++ include/hw/arm/aspeed_coprocessor.h | 7 +++++++ 4 files changed, 43 insertions(+) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index d14a42ebca..058cea42ed 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -159,6 +159,8 @@ static bool ast2700fc_ssp_init(Ast2700FCState *s, AspeedSoCState *psp, OBJECT(&s->ca35.scu), &error_abort); object_property_set_link(OBJECT(&s->ssp), "scuio", OBJECT(&psp->scuio), &error_abort); + object_property_set_link(OBJECT(&s->ssp), "fmc", + OBJECT(&psp->fmc), &error_abort); if (!qdev_realize(DEVICE(&s->ssp), NULL, errp)) { return false; } @@ -191,6 +193,8 @@ static bool ast2700fc_tsp_init(Ast2700FCState *s, AspeedSoCState *psp, OBJECT(&s->ca35.scu), &error_abort); object_property_set_link(OBJECT(&s->tsp), "scuio", OBJECT(&psp->scuio), &error_abort); + object_property_set_link(OBJECT(&s->tsp), "fmc", + OBJECT(&psp->fmc), &error_abort); if (!qdev_realize(DEVICE(&s->tsp), NULL, errp)) { return false; } diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c index fa492f1797..e03653086c 100644 --- a/hw/arm/aspeed_ast27x0-ssp.c +++ b/hw/arm/aspeed_ast27x0-ssp.c @@ -27,6 +27,7 @@ static const hwaddr aspeed_soc_ast27x0ssp_memmap[] = { [ASPEED_DEV_TIMER1] = 0x72C10000, [ASPEED_DEV_UART4] = 0x72C1A000, [ASPEED_DEV_IPC0] = 0x72C1C000, + [ASPEED_DEV_FMC] = 0x74000000, [ASPEED_DEV_PRIC1] = 0x74100000, [ASPEED_DEV_SCUIO] = 0x74C02000, [ASPEED_DEV_OTP] = 0x74C07000, @@ -177,6 +178,12 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->fmc) { + error_setg(errp, TYPE_ASPEED27X0SSP_COPROCESSOR + ": 'fmc' link is not set"); + return; + } + /* AST27X0 SSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -269,6 +276,13 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(s->uart), 0, aspeed_soc_ast27x0ssp_get_irq(s, s->uart_dev)); + /* FMC */ + memory_region_init_alias(&a->fmc_alias, OBJECT(a), "fmc.alias", + &a->fmc->mmio, 0, + memory_region_size(&a->fmc->mmio)); + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_FMC], + &a->fmc_alias); + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->timerctrl), "aspeed.timerctrl", sc->memmap[ASPEED_DEV_TIMER1], 0x200); @@ -294,6 +308,8 @@ static const Property aspeed_27x0_coprocessor_properties[] = { TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), DEFINE_PROP_LINK("scuio", Aspeed27x0CoprocessorState, scuio, TYPE_ASPEED_SCU, AspeedSCUState *), + DEFINE_PROP_LINK("fmc", Aspeed27x0CoprocessorState, fmc, TYPE_ASPEED_SMC, + AspeedSMCState *), }; static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c index 3a98bd232c..39ba062a20 100644 --- a/hw/arm/aspeed_ast27x0-tsp.c +++ b/hw/arm/aspeed_ast27x0-tsp.c @@ -27,6 +27,7 @@ static const hwaddr aspeed_soc_ast27x0tsp_memmap[] = { [ASPEED_DEV_TIMER1] = 0x72C10000, [ASPEED_DEV_UART4] = 0x72C1A000, [ASPEED_DEV_IPC0] = 0x72C1C000, + [ASPEED_DEV_FMC] = 0x74000000, [ASPEED_DEV_PRIC1] = 0x74100000, [ASPEED_DEV_SCUIO] = 0x74C02000, [ASPEED_DEV_OTP] = 0x74C07000, @@ -177,6 +178,12 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) return; } + if (!a->fmc) { + error_setg(errp, TYPE_ASPEED27X0TSP_COPROCESSOR + ": 'fmc' link is not set"); + return; + } + /* AST27X0 TSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); @@ -269,6 +276,13 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(s->uart), 0, aspeed_soc_ast27x0tsp_get_irq(s, s->uart_dev)); + /* FMC */ + memory_region_init_alias(&a->fmc_alias, OBJECT(a), "fmc.alias", + &a->fmc->mmio, 0, + memory_region_size(&a->fmc->mmio)); + memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_FMC], + &a->fmc_alias); + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->timerctrl), "aspeed.timerctrl", sc->memmap[ASPEED_DEV_TIMER1], 0x200); @@ -294,6 +308,8 @@ static const Property aspeed_27x0_coprocessor_properties[] = { TYPE_ASPEED_2700_SCU, Aspeed2700SCUState *), DEFINE_PROP_LINK("scuio", Aspeed27x0CoprocessorState, scuio, TYPE_ASPEED_SCU, AspeedSCUState *), + DEFINE_PROP_LINK("fmc", Aspeed27x0CoprocessorState, fmc, TYPE_ASPEED_SMC, + AspeedSMCState *), }; static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, diff --git a/include/hw/arm/aspeed_coprocessor.h b/include/hw/arm/aspeed_coprocessor.h index b77ea06e7f..acb8b06457 100644 --- a/include/hw/arm/aspeed_coprocessor.h +++ b/include/hw/arm/aspeed_coprocessor.h @@ -49,10 +49,17 @@ struct Aspeed27x0CoprocessorState { ARMv7MState armv7m; + /* + * SCU, SCUIO and FMC are not owned by this coprocessor: they are + * shared with the main PSP SoC, and only aliased into this + * coprocessor's own address space here. + */ MemoryRegion scu_alias; MemoryRegion scuio_alias; + MemoryRegion fmc_alias; Aspeed2700SCUState *scu; AspeedSCUState *scuio; + AspeedSMCState *fmc; }; #define TYPE_ASPEED27X0SSP_COPROCESSOR "aspeed27x0ssp-coprocessor" From 29139270d8ad70f2c422cc7cf483f465fba42397 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:11 +0000 Subject: [PATCH 097/627] hw/ssi/aspeed_smc: Add Data FIFO-based flash access support for AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2700 supports a Data FIFO mode where flash accesses can be performed directly through Data FIFO MMIO offsets. The Data FIFO start offset increments by one for every 16MB of flash address space, allowing the chip select (CS) to be decoded from the Data FIFO offset. This change adds Data FIFO support to the Aspeed SMC model and introduces a class callback to translate Data FIFO offsets into CS indices. For AST2700, the Data FIFO offset is matched against the segment start address of each CS to determine the target flash device. The SMC register region size (nregs) is also extended dynamically based on the number of supported chip selects to cover all possible Data FIFO regions. This breaks migration compatibility with older QEMU builds for the affected models, even though Aspeed machines are not officially covered by migration compatibility guarantees. Bump version_id to 4 and minimum_version_id to 2 to reflect the incompatible format. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/ssi/aspeed_smc.c | 117 +++++++++++++++++++++++++++++++++--- include/hw/ssi/aspeed_smc.h | 3 +- 2 files changed, 109 insertions(+), 11 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index c8cc6cfa56..bf596f7b2d 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -163,6 +163,9 @@ /* Read Timing Compensation Register */ #define R_TIMINGS (0x94 / 4) +/* Data fifo */ +#define R_DATA_FIFO (0x200 / 4) + /* SPI controller registers and bits (AST2400) */ #define R_SPI_CONF (0x00 / 4) #define SPI_CONF_ENABLE_W0 0 @@ -209,6 +212,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[]; #define ASPEED_SMC_FEATURE_DMA_GRANT 0x2 #define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4 #define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08 +#define ASPEED_SMC_FEATURE_DATA_FIFO 0x10 static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc) { @@ -225,6 +229,11 @@ static inline bool aspeed_smc_has_dma64(const AspeedSMCClass *asc) return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH); } +static inline bool aspeed_smc_has_data_fifo(const AspeedSMCClass *asc) +{ + return !!(asc->features & ASPEED_SMC_FEATURE_DATA_FIFO); +} + #define aspeed_smc_error(fmt, ...) \ qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__) @@ -664,6 +673,7 @@ static MemTxResult aspeed_smc_read(void *opaque, hwaddr addr, uint64_t *data, { AspeedSMCState *s = ASPEED_SMC(opaque); AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(opaque); + int cs; addr >>= 2; @@ -689,6 +699,18 @@ static MemTxResult aspeed_smc_read(void *opaque, hwaddr addr, uint64_t *data, trace_aspeed_smc_read(addr << 2, size, s->regs[addr]); *data = s->regs[addr]; + } else if (aspeed_smc_has_data_fifo(asc) && addr >= R_DATA_FIFO) { + cs = asc->data_fifo_offset_to_cs(s, addr << 2); + if (cs >= 0) { + /* + * Data fifo mode only supports SPI user mode. + * The flash address is provided by the SPI command/address cycles, + * the MMIO addr parameter is ignored. + */ + return aspeed_smc_flash_read(&s->flashes[cs], 0, data, size, attrs); + } + aspeed_smc_error("Invalid data fifo offset %" HWADDR_PRIx, addr << 2); + return MEMTX_ERROR; } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -1063,6 +1085,19 @@ static MemTxResult aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, } else if (aspeed_smc_has_dma(asc) && aspeed_smc_has_dma64(asc) && addr == R_DMA_DRAM_ADDR_HIGH) { s->regs[addr] = DMA_DRAM_ADDR_HIGH(value); + } else if (aspeed_smc_has_data_fifo(asc) && addr >= R_DATA_FIFO) { + int cs = asc->data_fifo_offset_to_cs(s, addr << 2); + if (cs >= 0) { + /* + * Data fifo mode only supports SPI user mode. + * The flash address is provided by the SPI command/address cycles, + * the MMIO addr parameter is ignored. + */ + return aspeed_smc_flash_write(&s->flashes[cs], 0, data, size, + attrs); + } + aspeed_smc_error("Invalid data fifo offset %" HWADDR_PRIx, addr << 2); + return MEMTX_ERROR; } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -1183,8 +1218,8 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) static const VMStateDescription vmstate_aspeed_smc = { .name = "aspeed.smc", - .version_id = 3, - .minimum_version_id = 1, + .version_id = 4, + .minimum_version_id = 2, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX), VMSTATE_UNUSED_V(2, 2), /* was snoop_index/snoop_dummies */ @@ -1808,6 +1843,39 @@ static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s, } } +/* + * Convert a data fifo offset to a chip select (CS). + * + * Data fifo access starts at 0x200. The data fifo offset index is + * calculated by subtracting the data fifo base offset from the MMIO address. + * + * The data fifo offset index increments by 1 for every 16MB of flash address + * space. Each offset step therefore represents a 16MB address decode range. + * + * The CS is determined by matching the data fifo offset index against the + * segment start address of each CS. + * + * Returns the CS index on success, or -1 if the offset is invalid. + */ +static int aspeed_2700_smc_data_fifo_offset_to_cs(const AspeedSMCState *s, + uint32_t offset) +{ + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + uint32_t start_offset; + uint32_t fifo_offset; + int i; + + for (i = 0; i < asc->cs_num_max; i++) { + start_offset = (s->regs[R_SEG_ADDR0 + i] & 0x0000ffff) << 16; + fifo_offset = start_offset / 0x1000000; + if (fifo_offset == offset - (R_DATA_FIFO << 2)) { + return i; + } + } + + return -1; +} + static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = { [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 | CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1), @@ -1842,6 +1910,27 @@ static const AspeedSegments aspeed_2700_fmc_segments[] = { { 0x0, 0 }, /* disabled */ }; +/* + * AST2700 supports data fifo mode with a base data fifo start offset of 0x200. + * + * The data fifo start offset increments by 1 for every 16MB of flash address + * space. Each offset step therefore represents a 16MB address decode range. + * + * Assuming each chip select (CS) can use the maximum flash size of 256MB: + * 256MB / 16MB = 0x10 offset steps per CS. + * + * Data fifo start offset for CSn: + * 0x200 + (n * 0x10) + * + * Examples: + * CS0: 0x200 + * CS1: 0x210 + * CS2: 0x220 + * CS3: 0x230 + * + * asc->nregs should be set to: 0x200 + (asc->cs_num_max * 0x10) + * to cover all possible data fifo regions. + */ static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1861,14 +1950,16 @@ static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data) asc->flash_window_base = 0x100000000; asc->flash_window_size = 1 * GiB; asc->features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH; + ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH | + ASPEED_SMC_FEATURE_DATA_FIFO; asc->dma_flash_mask = 0x2FFFFFFC; asc->dma_dram_mask = 0xFFFFFFFC; asc->dma_start_length = 1; - asc->nregs = ASPEED_SMC_R_MAX; + asc->nregs = (0x200 + (asc->cs_num_max * 0x10)) >> 2; asc->segment_to_reg = aspeed_2700_smc_segment_to_reg; asc->reg_to_segment = aspeed_2700_smc_reg_to_segment; asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; + asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs; asc->reg_ops = &aspeed_2700_smc_flash_ops; } @@ -1896,14 +1987,16 @@ static void aspeed_2700_spi0_class_init(ObjectClass *klass, const void *data) asc->flash_window_base = 0x180000000; asc->flash_window_size = 1 * GiB; asc->features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH; + ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH | + ASPEED_SMC_FEATURE_DATA_FIFO; asc->dma_flash_mask = 0x2FFFFFFC; asc->dma_dram_mask = 0xFFFFFFFC; asc->dma_start_length = 1; - asc->nregs = ASPEED_SMC_R_MAX; + asc->nregs = (0x200 + (asc->cs_num_max * 0x10)) >> 2; asc->segment_to_reg = aspeed_2700_smc_segment_to_reg; asc->reg_to_segment = aspeed_2700_smc_reg_to_segment; asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; + asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs; asc->reg_ops = &aspeed_2700_smc_flash_ops; } @@ -1930,14 +2023,16 @@ static void aspeed_2700_spi1_class_init(ObjectClass *klass, const void *data) asc->flash_window_base = 0x200000000; asc->flash_window_size = 1 * GiB; asc->features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH; + ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH | + ASPEED_SMC_FEATURE_DATA_FIFO; asc->dma_flash_mask = 0x2FFFFFFC; asc->dma_dram_mask = 0xFFFFFFFC; asc->dma_start_length = 1; - asc->nregs = ASPEED_SMC_R_MAX; + asc->nregs = (0x200 + (asc->cs_num_max * 0x10)) >> 2; asc->segment_to_reg = aspeed_2700_smc_segment_to_reg; asc->reg_to_segment = aspeed_2700_smc_reg_to_segment; asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; + asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs; asc->reg_ops = &aspeed_2700_smc_flash_ops; } @@ -1964,14 +2059,16 @@ static void aspeed_2700_spi2_class_init(ObjectClass *klass, const void *data) asc->flash_window_base = 0x280000000; asc->flash_window_size = 1 * GiB; asc->features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH; + ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH | + ASPEED_SMC_FEATURE_DATA_FIFO; asc->dma_flash_mask = 0x0FFFFFFC; asc->dma_dram_mask = 0xFFFFFFFC; asc->dma_start_length = 1; - asc->nregs = ASPEED_SMC_R_MAX; + asc->nregs = (0x200 + (asc->cs_num_max * 0x10)) >> 2; asc->segment_to_reg = aspeed_2700_smc_segment_to_reg; asc->reg_to_segment = aspeed_2700_smc_reg_to_segment; asc->dma_ctrl = aspeed_2600_smc_dma_ctrl; + asc->data_fifo_offset_to_cs = aspeed_2700_smc_data_fifo_offset_to_cs; asc->reg_ops = &aspeed_2700_smc_flash_ops; } diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index a273365689..5f391fc24e 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -47,7 +47,7 @@ struct AspeedSMCFlash { #define TYPE_ASPEED_SMC "aspeed.smc" OBJECT_DECLARE_TYPE(AspeedSMCState, AspeedSMCClass, ASPEED_SMC) -#define ASPEED_SMC_R_MAX (0x100 / 4) +#define ASPEED_SMC_R_MAX (0x300 / 4) #define ASPEED_SMC_CS_MAX 5 struct AspeedSMCState { @@ -114,6 +114,7 @@ struct AspeedSMCClass { AspeedSegments *seg); void (*dma_ctrl)(AspeedSMCState *s, uint32_t value); int (*addr_width)(const AspeedSMCState *s); + int (*data_fifo_offset_to_cs)(const AspeedSMCState *s, uint32_t offset); const MemoryRegionOps *reg_ops; }; From 828872aa980ce747e835a4182f9958b9e6e7554c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 17 Jul 2026 08:46:12 +0000 Subject: [PATCH 098/627] tests/qtest/ast2700-smc-test: Add Data FIFO mode test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two qtest cases exercising the new AST2700 Data FIFO-based flash access path (R_DATA_FIFO at spi_base + 0x200). Write_page_datafifo sends the page-program command and data through the FIFO port, then verifies the result via the regular read path. Read_page_datafifo writes a page the regular way, then reads it back through the FIFO port, so both directions are checked independently. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260717084559.3477061-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-smc-utils.c | 102 +++++++++++++++++++++++++++++++++ tests/qtest/aspeed-smc-utils.h | 4 ++ tests/qtest/ast2700-smc-test.c | 4 ++ 3 files changed, 110 insertions(+) diff --git a/tests/qtest/aspeed-smc-utils.c b/tests/qtest/aspeed-smc-utils.c index 6d75a95578..146332240d 100644 --- a/tests/qtest/aspeed-smc-utils.c +++ b/tests/qtest/aspeed-smc-utils.c @@ -57,6 +57,28 @@ static inline uint32_t flash_readl(const AspeedSMCTestData *data, return qtest_readl(data->s, data->flash_base + offset); } +/* + * Data FIFO port, in spi_base's register bank (not flash_base). Accesses + * through the FIFO require the complete user-mode transaction (opcode, + * address, and data). Assumes CS0, whose FIFO slot is at R_DATA_FIFO. + */ +static inline void datafifo_writeb(const AspeedSMCTestData *data, + uint8_t value) +{ + qtest_writeb(data->s, data->spi_base + R_DATA_FIFO, value); +} + +static inline void datafifo_writel(const AspeedSMCTestData *data, + uint32_t value) +{ + spi_writel(data, R_DATA_FIFO, value); +} + +static inline uint32_t datafifo_readl(const AspeedSMCTestData *data) +{ + return spi_readl(data, R_DATA_FIFO); +} + static void spi_conf(const AspeedSMCTestData *data, uint32_t value) { uint32_t conf = spi_readl(data, R_CONF); @@ -826,3 +848,83 @@ void aspeed_smc_test_write_page_qor(const void *data) { test_write_page(data, read_page_qor); } + +void aspeed_smc_test_write_page_datafifo(const void *data) +{ + const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data; + uint32_t my_page_addr = test_data->page_addr; + uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE; + uint32_t page[FLASH_PAGE_SIZE / 4]; + int i; + + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); + + /* + * Send the complete user-mode transaction (opcode, address, data) + * through the Data FIFO port. + */ + spi_ctrl_start_user(test_data); + datafifo_writeb(test_data, EN_4BYTE_ADDR); + datafifo_writeb(test_data, WREN); + datafifo_writeb(test_data, PP); + datafifo_writel(test_data, make_be32(my_page_addr)); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + datafifo_writel(test_data, make_be32(my_page_addr + i * 4)); + } + spi_ctrl_stop_user(test_data); + + /* Check what was written, using the regular read path */ + read_page(test_data, my_page_addr, page); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, my_page_addr + i * 4); + } + + /* Check some other page. It should be full of 0xff */ + read_page(test_data, some_page_addr, page); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, 0xffffffff); + } + + flash_reset(test_data); +} + +void aspeed_smc_test_read_page_datafifo(const void *data) +{ + const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data; + uint32_t my_page_addr = test_data->page_addr; + uint32_t page[FLASH_PAGE_SIZE / 4]; + int i; + + spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs)); + + /* Write the page the regular way */ + spi_ctrl_start_user(test_data); + flash_writeb(test_data, 0, EN_4BYTE_ADDR); + flash_writeb(test_data, 0, WREN); + flash_writeb(test_data, 0, PP); + flash_writel(test_data, 0, make_be32(my_page_addr)); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + flash_writel(test_data, 0, make_be32(my_page_addr + i * 4)); + } + spi_ctrl_stop_user(test_data); + + /* + * Read it back through the data FIFO port, again sending the whole + * transaction (opcode, address, data) through it. + */ + spi_ctrl_start_user(test_data); + datafifo_writeb(test_data, EN_4BYTE_ADDR); + datafifo_writeb(test_data, READ); + datafifo_writel(test_data, make_be32(my_page_addr)); + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + page[i] = make_be32(datafifo_readl(test_data)); + } + spi_ctrl_stop_user(test_data); + + for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) { + g_assert_cmphex(page[i], ==, my_page_addr + i * 4); + } + + flash_reset(test_data); +} diff --git a/tests/qtest/aspeed-smc-utils.h b/tests/qtest/aspeed-smc-utils.h index 19c557b822..e4f538e579 100644 --- a/tests/qtest/aspeed-smc-utils.h +++ b/tests/qtest/aspeed-smc-utils.h @@ -33,6 +33,8 @@ #define CTRL_DUMMY_LOW_SHIFT 6 #define CTRL_DUMMY_HIGH_SHIFT 14 #define SR_WEL BIT(1) +/* Data fifo */ +#define R_DATA_FIFO 0x200 /* * Flash commands @@ -87,5 +89,7 @@ void aspeed_smc_test_read_page_mem_dor(const void *data); void aspeed_smc_test_write_page_dor(const void *data); void aspeed_smc_test_read_page_mem_qor(const void *data); void aspeed_smc_test_write_page_qor(const void *data); +void aspeed_smc_test_write_page_datafifo(const void *data); +void aspeed_smc_test_read_page_datafifo(const void *data); #endif /* TESTS_ASPEED_SMC_UTILS_H */ diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c index f85077e04f..925dbcfaaf 100644 --- a/tests/qtest/ast2700-smc-test.c +++ b/tests/qtest/ast2700-smc-test.c @@ -64,6 +64,10 @@ static void test_ast2700_evb(AspeedSMCTestData *data) data, aspeed_smc_test_read_page_mem_qor); qtest_add_data_func("/ast2700/smc/write_page_qor", data, aspeed_smc_test_write_page_qor); + qtest_add_data_func("/ast2700/smc/write_page_datafifo", + data, aspeed_smc_test_write_page_datafifo); + qtest_add_data_func("/ast2700/smc/read_page_datafifo", + data, aspeed_smc_test_read_page_datafifo); } int main(int argc, char **argv) From 325d1c9344484d6653db3d764facf2a5aad96c3d Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:15:54 +0200 Subject: [PATCH 099/627] hw/sensor: adc128d818: add 12-bit 8-channel ADC device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ADC128D818 is a TI 12-bit, 8-channel I2C ADC used on several OpenBMC platforms for voltage and temperature monitoring. Implement the device with: - four operating modes - 12-bit voltage conversion from QOM inputs - 9-bit temperature conversion from milli-degree Celsius QOM inputs - switchable internal or external voltage reference - per-channel high/low limit registers - interrupt support - software reset - one-shot conversion support in shutdown mode Reviewed-by: Alexander Hansen Tested-by: Alexander Hansen Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-2-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- hw/sensor/Kconfig | 4 + hw/sensor/adc128d818.c | 696 +++++++++++++++++++++++++++++++++ hw/sensor/meson.build | 1 + hw/sensor/trace-events | 8 + include/hw/sensor/adc128d818.h | 14 + 5 files changed, 723 insertions(+) create mode 100644 hw/sensor/adc128d818.c create mode 100644 include/hw/sensor/adc128d818.h diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig index bc6331b4ab..b459ac2240 100644 --- a/hw/sensor/Kconfig +++ b/hw/sensor/Kconfig @@ -1,3 +1,7 @@ +config ADC128D818 + bool + depends on I2C + config TMP105 bool depends on I2C diff --git a/hw/sensor/adc128d818.c b/hw/sensor/adc128d818.c new file mode 100644 index 0000000000..c65508cba1 --- /dev/null +++ b/hw/sensor/adc128d818.c @@ -0,0 +1,696 @@ +/* + * Texas Instruments ADC128D818 12-bit 8-channel ADC with I2C interface + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "qom/object.h" +#include "hw/sensor/adc128d818.h" +#include "hw/core/irq.h" +#include "hw/core/qdev-properties.h" +#include "hw/i2c/i2c.h" +#include "migration/vmstate.h" +#include "trace.h" + + +/* Register addresses */ +#define REG_CONFIG 0x00 +#define REG_INT_STATUS 0x01 +#define REG_INT_MASK 0x03 +#define REG_CONV_RATE 0x07 +#define REG_CH_DISABLE 0x08 +#define REG_ONE_SHOT 0x09 +#define REG_DEEP_SHUTDOWN 0x0a +#define REG_ADV_CONFIG 0x0b +#define REG_BUSY_STATUS 0x0c + +/* Channel Reading Registers (16-bit, read-only) */ +#define REG_CH_READING_BASE 0x20 +#define REG_CH_READING_LAST 0x27 + +/* Limit Registers (8-bit, read/write) */ +#define REG_LIMIT_BASE 0x2a +#define REG_LIMIT_LAST 0x39 + +/* ID Registers (read-only) */ +#define REG_MANUFACTURER_ID 0x3e +#define REG_REVISION_ID 0x3f + +/* Configuration Register (0x00) bitfields */ +#define CONFIG_START BIT(0) +#define CONFIG_INT_ENABLE BIT(1) +#define CONFIG_INT_CLEAR BIT(3) +#define CONFIG_INITIALIZATION BIT(7) +#define CONFIG_WR_MASK \ + (CONFIG_START | CONFIG_INT_ENABLE | CONFIG_INT_CLEAR) + +/* Advanced Configuration Register (0x0B) bitfields */ +#define ADV_CONFIG_EXT_REF_EN BIT(0) +#define ADV_CONFIG_MODE_SHIFT 1 +#define ADV_CONFIG_MODE_MASK (0x3 << ADV_CONFIG_MODE_SHIFT) +#define ADV_CONFIG_WR_MASK \ + (ADV_CONFIG_EXT_REF_EN | ADV_CONFIG_MODE_MASK) + +/* Busy Status Register (0x0C) bitfields */ +#define BUSY_STATUS_NOT_READY BIT(1) + +/* Conversion Rate Register (0x07) bitfields */ +#define CONV_RATE_MASK 0x01 + +/* Deep Shutdown Register (0x0A) bitfields */ +#define DEEP_SHUTDOWN_EN 0x01 + +/* Device constants */ +#define ADC128D818_NUM_CHANNELS 8 +#define ADC128D818_NUM_REGS 0x40 + +#define ADC128D818_INTERNAL_VREF_MV 2560 +#define ADC128D818_MAX_VDD_MV 5500 +#define ADC128D818_MANUFACTURER_ID_VAL 0x01 +#define ADC128D818_REVISION_ID_VAL 0x09 + +/* ADC resolution */ +#define ADC128D818_ADC_RESOLUTION 4096 +#define ADC128D818_ADC_MAX 4095 + +/* Temperature: 0.5 deg C per LSb = 500 milli-degrees per LSb */ +#define ADC128D818_TEMP_LSB_MC 500 +#define ADC128D818_TEMP_RAW_MIN (-256) +#define ADC128D818_TEMP_RAW_MAX 255 + + +OBJECT_DECLARE_SIMPLE_TYPE(ADC128D818State, ADC128D818) + +struct ADC128D818State { + I2CSlave parent_obj; + + qemu_irq irq; + + uint8_t len; + uint8_t pointer; + uint8_t rx_byte; + + uint8_t regs[ADC128D818_NUM_REGS]; + uint16_t channel[ADC128D818_NUM_CHANNELS]; + + int16_t ain[ADC128D818_NUM_CHANNELS]; /* mV */ + int32_t temperature; /* milli-degrees Celsius */ + uint16_t ext_vref; /* mV, 0 means not connected */ + bool temp_alarm; /* temperature high-limit alarm latched */ + + char *description; +}; + +static uint16_t adc128d818_get_vref(const ADC128D818State *s) +{ + if (s->regs[REG_ADV_CONFIG] & ADV_CONFIG_EXT_REF_EN) { + if (s->ext_vref > 0u) { + return s->ext_vref; + } + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: external VREF selected but not" + " connected, falling back to internal\n", + __func__, s->description); + } + + return ADC128D818_INTERNAL_VREF_MV; +} + +static uint8_t adc128d818_get_mode(const ADC128D818State *s) +{ + return (s->regs[REG_ADV_CONFIG] & ADV_CONFIG_MODE_MASK) >> + ADV_CONFIG_MODE_SHIFT; +} + +static bool adc128d818_is_temp_channel(const ADC128D818State *s, unsigned ch) +{ + if (ch != 7u) { + return false; + } + + return adc128d818_get_mode(s) != 1u; +} + +static bool adc128d818_is_reserved_channel(const ADC128D818State *s, + unsigned ch) +{ + switch (adc128d818_get_mode(s)) { + case 2u: + return ch >= 4u && ch <= 6u; + case 3u: + return ch == 6u; + default: + return false; + } +} + +static int16_t adc128d818_channel_voltage(const ADC128D818State *s, unsigned ch) +{ + switch (adc128d818_get_mode(s)) { + case 2u: + switch (ch) { + case 0u: + return (int16_t)(s->ain[0] - s->ain[1]); + case 1u: + return (int16_t)(s->ain[3] - s->ain[2]); + case 2u: + return (int16_t)(s->ain[4] - s->ain[5]); + case 3u: + return (int16_t)(s->ain[7] - s->ain[6]); + default: + return 0; + } + case 3u: + switch (ch) { + case 4u: + return (int16_t)(s->ain[4] - s->ain[5]); + case 5u: + return (int16_t)(s->ain[7] - s->ain[6]); + default: + return s->ain[ch]; + } + default: + return s->ain[ch]; + } +} + +static void adc128d818_update_irq(ADC128D818State *s) +{ + uint8_t cfg = s->regs[REG_CONFIG]; + uint8_t active; + bool level; + + active = s->regs[REG_INT_STATUS] & ~s->regs[REG_INT_MASK]; + + /* INT pin is active-low */ + level = !((cfg & CONFIG_INT_ENABLE) && !(cfg & CONFIG_INT_CLEAR) && + (active != 0u)); + + trace_adc128d818_irq(s->description, level); + qemu_set_irq(s->irq, level); +} + +static bool adc128d818_monitoring_active(const ADC128D818State *s) +{ + if (s->regs[REG_DEEP_SHUTDOWN] & DEEP_SHUTDOWN_EN) { + return false; + } + if (!(s->regs[REG_CONFIG] & CONFIG_START)) { + return false; + } + if (s->regs[REG_CONFIG] & CONFIG_INT_CLEAR) { + return false; + } + + return true; +} + +static void adc128d818_check_limits(ADC128D818State *s) +{ + uint8_t disabled = s->regs[REG_CH_DISABLE]; + uint8_t int_status = 0u; + + for (unsigned ch = 0u; ch < ADC128D818_NUM_CHANNELS; ch++) { + if ((disabled & (1u << ch)) || + adc128d818_is_reserved_channel(s, ch)) { + continue; + } + + if (adc128d818_is_temp_channel(s, ch)) { + int raw = s->temperature / ADC128D818_TEMP_LSB_MC; + int thot; + int thyst; + + raw = MAX(ADC128D818_TEMP_RAW_MIN, + MIN(ADC128D818_TEMP_RAW_MAX, raw)); + thot = (int)(int8_t)s->regs[REG_LIMIT_BASE + ch * 2u] * 2; + thyst = (int)(int8_t)s->regs[REG_LIMIT_BASE + ch * 2u + 1u] * 2; + + if (raw > thot) { + s->temp_alarm = true; + } else if (raw <= thyst) { + s->temp_alarm = false; + } + if (s->temp_alarm) { + int_status |= (1u << ch); + } + } else { + uint8_t msb = (uint8_t)(s->channel[ch] >> 8u); + uint8_t high_lim = s->regs[REG_LIMIT_BASE + ch * 2u]; + uint8_t low_lim = s->regs[REG_LIMIT_BASE + ch * 2u + 1u]; + + if (msb > high_lim || msb <= low_lim) { + int_status |= (1u << ch); + } + } + } + + s->regs[REG_INT_STATUS] = int_status; + adc128d818_update_irq(s); +} + +static void adc128d818_convert(ADC128D818State *s) +{ + uint8_t disabled; + uint16_t vref; + + disabled = s->regs[REG_CH_DISABLE]; + vref = adc128d818_get_vref(s); + + for (unsigned ch = 0u; ch < ADC128D818_NUM_CHANNELS; ch++) { + if ((disabled & (1u << ch)) || + adc128d818_is_reserved_channel(s, ch)) { + continue; + } + + if (adc128d818_is_temp_channel(s, ch)) { + int32_t raw = s->temperature / ADC128D818_TEMP_LSB_MC; + + raw = + MAX(ADC128D818_TEMP_RAW_MIN, MIN(ADC128D818_TEMP_RAW_MAX, raw)); + s->channel[ch] = (uint16_t)(((unsigned)raw & 0x1FFu) << 7u); + } else { + int16_t vin = adc128d818_channel_voltage(s, ch); + int32_t dout; + + dout = vin * (int32_t)ADC128D818_ADC_RESOLUTION / vref; + dout = MAX(0, MIN((int32_t)ADC128D818_ADC_MAX, dout)); + s->channel[ch] = (uint16_t)(dout << 4u); + } + + trace_adc128d818_convert(s->description, ch, s->channel[ch]); + } + + s->regs[REG_BUSY_STATUS] &= ~BUSY_STATUS_NOT_READY; + + adc128d818_check_limits(s); +} + +static uint8_t adc128d818_read_channel(ADC128D818State *s, unsigned ch) +{ + uint8_t val; + + if (s->rx_byte == 0u) { + val = (uint8_t)(s->channel[ch] >> 8u); + trace_adc128d818_read_channel(s->description, ch, s->channel[ch]); + } else { + val = (uint8_t)(s->channel[ch] & 0xFFu); + } + s->rx_byte ^= 1u; + + return val; +} + +static uint8_t adc128d818_read_reg(ADC128D818State *s, uint8_t reg) +{ + uint8_t val; + + switch (reg) { + case REG_INT_STATUS: + val = s->regs[REG_INT_STATUS]; + s->regs[REG_INT_STATUS] = 0x00u; + if (adc128d818_monitoring_active(s)) { + adc128d818_check_limits(s); + } else { + adc128d818_update_irq(s); + } + trace_adc128d818_read(s->description, reg, val); + return val; + case REG_CONFIG: + case REG_INT_MASK: + case REG_CONV_RATE: + case REG_CH_DISABLE: + case REG_ONE_SHOT: + case REG_DEEP_SHUTDOWN: + case REG_ADV_CONFIG: + case REG_BUSY_STATUS: + case REG_LIMIT_BASE ... REG_LIMIT_LAST: + case REG_MANUFACTURER_ID: + case REG_REVISION_ID: + trace_adc128d818_read(s->description, reg, s->regs[reg]); + return s->regs[reg]; + case REG_CH_READING_BASE ... REG_CH_READING_LAST: + return adc128d818_read_channel(s, reg - REG_CH_READING_BASE); + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: read from undefined register 0x%02x\n", + __func__, s->description, reg); + return 0x00u; + } +} + +static void adc128d818_write_reg(ADC128D818State *s, uint8_t reg, uint8_t val); + +static void adc128d818_reset_regs(ADC128D818State *s) +{ + memset(s->regs, 0, sizeof(s->regs)); + memset(s->channel, 0, sizeof(s->channel)); + s->temp_alarm = false; + + s->regs[REG_CONFIG] = 0x08u; + s->regs[REG_BUSY_STATUS] = 0x02u; + s->regs[REG_MANUFACTURER_ID] = ADC128D818_MANUFACTURER_ID_VAL; + s->regs[REG_REVISION_ID] = ADC128D818_REVISION_ID_VAL; + + for (unsigned ch = 0u; ch < ADC128D818_NUM_CHANNELS; ch++) { + s->regs[REG_LIMIT_BASE + ch * 2u] = 0xFFu; + } + + s->pointer = 0x00u; + s->len = 0u; + s->rx_byte = 0u; + + adc128d818_update_irq(s); +} + +static void adc128d818_write_reg(ADC128D818State *s, uint8_t reg, uint8_t val) +{ + trace_adc128d818_write(s->description, reg, val); + + switch (reg) { + case REG_CONFIG: + if (val & CONFIG_INITIALIZATION) { + trace_adc128d818_reset(s->description, "reg"); + adc128d818_reset_regs(s); + break; + } + s->regs[REG_CONFIG] = val & CONFIG_WR_MASK; + if ((val & CONFIG_START) && !(val & CONFIG_INT_CLEAR) && + !(s->regs[REG_DEEP_SHUTDOWN] & DEEP_SHUTDOWN_EN)) { + adc128d818_convert(s); + } + adc128d818_update_irq(s); + break; + case REG_INT_MASK: + s->regs[REG_INT_MASK] = val; + adc128d818_update_irq(s); + break; + case REG_CONV_RATE: + if (s->regs[REG_CONFIG] & CONFIG_START) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: CONV_RATE written while running\n", + __func__, s->description); + break; + } + s->regs[REG_CONV_RATE] = val & CONV_RATE_MASK; + break; + case REG_CH_DISABLE: + if (s->regs[REG_CONFIG] & CONFIG_START) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: CH_DISABLE written while running\n", + __func__, s->description); + break; + } + s->regs[REG_CH_DISABLE] = val; + memset(s->channel, 0, sizeof(s->channel)); + s->regs[REG_INT_STATUS] = 0x00u; + s->temp_alarm = false; + adc128d818_update_irq(s); + break; + case REG_ONE_SHOT: + if (!(s->regs[REG_CONFIG] & CONFIG_START)) { + adc128d818_convert(s); + } + break; + case REG_DEEP_SHUTDOWN: + if ((val & DEEP_SHUTDOWN_EN) && (s->regs[REG_CONFIG] & CONFIG_START)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: DEEP_SHUTDOWN set while running\n", + __func__, s->description); + break; + } + s->regs[REG_DEEP_SHUTDOWN] = val & DEEP_SHUTDOWN_EN; + break; + case REG_ADV_CONFIG: + if (s->regs[REG_CONFIG] & CONFIG_START) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: ADV_CONFIG written while running\n", + __func__, s->description); + break; + } + s->regs[REG_ADV_CONFIG] = val & ADV_CONFIG_WR_MASK; + memset(s->channel, 0, sizeof(s->channel)); + s->regs[REG_INT_STATUS] = 0x00u; + s->temp_alarm = false; + adc128d818_update_irq(s); + break; + case REG_LIMIT_BASE ... REG_LIMIT_LAST: + s->regs[reg] = val; + break; + case REG_INT_STATUS: + case REG_BUSY_STATUS: + case REG_MANUFACTURER_ID: + case REG_REVISION_ID: + case REG_CH_READING_BASE ... REG_CH_READING_LAST: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: write to read-only register 0x%02x\n", + __func__, s->description, reg); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: %s: write to undefined register 0x%02x\n", + __func__, s->description, reg); + break; + } +} + +static uint8_t adc128d818_recv(I2CSlave *i2c) +{ + ADC128D818State *s = ADC128D818(i2c); + + return adc128d818_read_reg(s, s->pointer); +} + +static int adc128d818_send(I2CSlave *i2c, uint8_t data) +{ + ADC128D818State *s = ADC128D818(i2c); + + if (s->len == 0u) { + s->pointer = data; + s->len++; + } else { + adc128d818_write_reg(s, s->pointer, data); + } + + return 0; +} + +static int adc128d818_event(I2CSlave *i2c, enum i2c_event event) +{ + ADC128D818State *s = ADC128D818(i2c); + + s->len = 0u; + s->rx_byte = 0u; + + return 0; +} + +static void adc128d818_get_ain(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value; + int ch_num; + int rc; + + rc = sscanf(name, "ain%d", &ch_num); + if (rc != 1 || ch_num < 0 || ch_num >= (int)ADC128D818_NUM_CHANNELS) { + error_setg(errp, "%s: %s: invalid channel '%s'", __func__, + s->description, name); + return; + } + + value = s->ain[ch_num]; + visit_type_int(v, name, &value, errp); +} + +static void adc128d818_set_ain(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value; + int ch_num; + int rc; + + if (!visit_type_int(v, name, &value, errp)) { + return; + } + + rc = sscanf(name, "ain%d", &ch_num); + if (rc != 1 || ch_num < 0 || ch_num >= (int)ADC128D818_NUM_CHANNELS) { + error_setg(errp, "%s: %s: invalid channel '%s'", __func__, + s->description, name); + return; + } + + if (value < INT16_MIN || value > INT16_MAX) { + error_setg(errp, "%s: %s: value %" PRId64 " out of range for '%s'", + __func__, s->description, value, name); + return; + } + + s->ain[ch_num] = (int16_t)value; + + if (adc128d818_monitoring_active(s)) { + adc128d818_convert(s); + } +} + +static void adc128d818_get_temperature( + Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value = s->temperature; + + visit_type_int(v, name, &value, errp); +} + +static void adc128d818_set_temperature( + Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value; + + if (!visit_type_int(v, name, &value, errp)) { + return; + } + + if (value < INT32_MIN || value > INT32_MAX) { + error_setg(errp, "%s: %s: value %" PRId64 " out of range", __func__, + s->description, value); + return; + } + + s->temperature = (int32_t)value; + + if (adc128d818_monitoring_active(s)) { + adc128d818_convert(s); + } +} + +static const VMStateDescription adc128d818_vmstate = { + .name = "ADC128D818", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(len, ADC128D818State), + VMSTATE_UINT8(pointer, ADC128D818State), + VMSTATE_UINT8(rx_byte, ADC128D818State), + VMSTATE_UINT8_ARRAY(regs, ADC128D818State, + ADC128D818_NUM_REGS), + VMSTATE_UINT16_ARRAY(channel, ADC128D818State, + ADC128D818_NUM_CHANNELS), + VMSTATE_INT16_ARRAY(ain, ADC128D818State, + ADC128D818_NUM_CHANNELS), + VMSTATE_INT32(temperature, ADC128D818State), + VMSTATE_UINT16(ext_vref, ADC128D818State), + VMSTATE_BOOL(temp_alarm, ADC128D818State), + VMSTATE_I2C_SLAVE(parent_obj, ADC128D818State), + VMSTATE_END_OF_LIST() + } +}; + +static void adc128d818_reset_hold(Object *obj, ResetType type) +{ + ADC128D818State *s = ADC128D818(obj); + + trace_adc128d818_reset(s->description, "hw"); + adc128d818_reset_regs(s); +} + +static void adc128d818_get_ext_vref( + Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value = (int64_t)s->ext_vref; + + visit_type_int(v, name, &value, errp); +} + +static void adc128d818_set_ext_vref( + Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) +{ + ADC128D818State *s = ADC128D818(obj); + int64_t value; + + if (!visit_type_int(v, name, &value, errp)) { + return; + } + + if (value < 0 || value > ADC128D818_MAX_VDD_MV) { + error_setg(errp, + "%s: %s: ext-vref-mv %" PRId64 " out of range (0..%u mV)", + __func__, s->description, value, ADC128D818_MAX_VDD_MV); + return; + } + + s->ext_vref = (uint16_t)value; + + if (adc128d818_monitoring_active(s)) { + adc128d818_convert(s); + } +} + +static void adc128d818_initfn(Object *obj) +{ + for (unsigned ch = 0u; ch < ADC128D818_NUM_CHANNELS; ch++) { + char *name = g_strdup_printf("ain%u", ch); + + object_property_add(obj, name, "int", adc128d818_get_ain, + adc128d818_set_ain, NULL, NULL); + g_free(name); + } + + object_property_add(obj, "temperature", "int", adc128d818_get_temperature, + adc128d818_set_temperature, NULL, NULL); + object_property_add(obj, "ext-vref-mv", "int", adc128d818_get_ext_vref, + adc128d818_set_ext_vref, NULL, NULL); +} + +static void adc128d818_realize(DeviceState *dev, Error **errp) +{ + ADC128D818State *s = ADC128D818(dev); + + if (!s->description) { + s->description = g_strdup(object_get_typename(OBJECT(dev))); + } + + qdev_init_gpio_out(dev, &s->irq, 1u); +} + +static const Property adc128d818_properties[] = { + DEFINE_PROP_STRING("description", ADC128D818State, description), +}; + +static void adc128d818_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *ic = I2C_SLAVE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + ic->event = adc128d818_event; + ic->recv = adc128d818_recv; + ic->send = adc128d818_send; + dc->realize = adc128d818_realize; + rc->phases.hold = adc128d818_reset_hold; + dc->vmsd = &adc128d818_vmstate; + device_class_set_props(dc, adc128d818_properties); +} + +static const TypeInfo adc128d818_types[] = { + { + .name = TYPE_ADC128D818, + .parent = TYPE_I2C_SLAVE, + .instance_init = adc128d818_initfn, + .instance_size = sizeof(ADC128D818State), + .class_init = adc128d818_class_init, + }, +}; + +DEFINE_TYPES(adc128d818_types) diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build index 420fdc3359..fe36c9ef91 100644 --- a/hw/sensor/meson.build +++ b/hw/sensor/meson.build @@ -1,3 +1,4 @@ +system_ss.add(when: 'CONFIG_ADC128D818', if_true: files('adc128d818.c')) system_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c')) system_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c')) system_ss.add(when: 'CONFIG_DPS310', if_true: files('dps310.c')) diff --git a/hw/sensor/trace-events b/hw/sensor/trace-events index a3fe54fa6d..5a3630f7bb 100644 --- a/hw/sensor/trace-events +++ b/hw/sensor/trace-events @@ -1,5 +1,13 @@ # See docs/devel/tracing.rst for syntax documentation. +# adc128d818.c +adc128d818_read(const char *id, uint8_t reg, uint8_t value) "%s reg 0x%02x val 0x%02x" +adc128d818_read_channel(const char *id, uint8_t channel, uint16_t value) "%s ch %u val 0x%04x" +adc128d818_write(const char *id, uint8_t reg, uint8_t value) "%s reg 0x%02x val 0x%02x" +adc128d818_convert(const char *id, uint8_t channel, uint16_t value) "%s ch %u val 0x%04x" +adc128d818_irq(const char *id, bool level) "%s level %u" +adc128d818_reset(const char *id, const char *source) "%s %s" + # tmp105.c tmp105_read(uint8_t dev, uint8_t addr) "device: 0x%02x, addr: 0x%02x" tmp105_write(uint8_t dev, uint8_t addr) "device: 0x%02x, addr 0x%02x" diff --git a/include/hw/sensor/adc128d818.h b/include/hw/sensor/adc128d818.h new file mode 100644 index 0000000000..10c34b9646 --- /dev/null +++ b/include/hw/sensor/adc128d818.h @@ -0,0 +1,14 @@ +/* + * Texas Instruments ADC128D818 12-bit 8-channel ADC with I2C interface + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_SENSOR_ADC128D818_H +#define HW_SENSOR_ADC128D818_H + +#define TYPE_ADC128D818 "adc128d818" + +#endif From 464e6551430d4d6e515f8a53a493b6fc860732c3 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:15:55 +0200 Subject: [PATCH 100/627] tests/qtest: adc128d818: add test harness and register access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the QOS test node and QMP property helpers for the ADC128D818, and cover basic register access: manufacturer and revision IDs, power-on-reset defaults, software reset, and the ain and temperature property readback. Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-3-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/adc128d818-test.c | 169 ++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 1 + 2 files changed, 170 insertions(+) create mode 100644 tests/qtest/adc128d818-test.c diff --git a/tests/qtest/adc128d818-test.c b/tests/qtest/adc128d818-test.c new file mode 100644 index 0000000000..9a8811256f --- /dev/null +++ b/tests/qtest/adc128d818-test.c @@ -0,0 +1,169 @@ +/* + * QTest testcase for the ADC128D818 ADC + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "libqos/i2c.h" +#include "libqos/qgraph.h" +#include "libqtest-single.h" +#include "qobject/qdict.h" + +#define ADC128D818_TEST_ID "adc128d818-test" +#define ADC128D818_TEST_ADDR 0x1f + +/* Register addresses */ +#define REG_CONFIG 0x00 +#define REG_INT_STATUS 0x01 +#define REG_INT_MASK 0x03 +#define REG_CONV_RATE 0x07 +#define REG_CH_DISABLE 0x08 +#define REG_ONE_SHOT 0x09 +#define REG_DEEP_SHUTDOWN 0x0a +#define REG_ADV_CONFIG 0x0b +#define REG_BUSY_STATUS 0x0c + +/* Channel Reading Registers (16-bit, read-only) */ +#define REG_CH_READING_BASE 0x20 + +/* Limit Registers (8-bit, read/write) */ +#define REG_LIMIT_BASE 0x2a + +/* ID Registers (read-only) */ +#define REG_MANUFACTURER_ID 0x3e +#define REG_REVISION_ID 0x3f + +/* Configuration Register (0x00) bitfields */ +#define CONFIG_START BIT(0) +#define CONFIG_INT_ENABLE BIT(1) +#define CONFIG_INT_CLEAR BIT(3) +#define CONFIG_INITIALIZATION BIT(7) + +/* Advanced Configuration Register (0x0b) bitfields */ +#define ADV_CONFIG_EXT_REF_EN BIT(0) +#define ADV_CONFIG_MODE_1 (1 << 1) +#define ADV_CONFIG_MODE_2 (2 << 1) +#define ADV_CONFIG_MODE_3 (3 << 1) + +/* Number of channels */ +#define NUM_CHANNELS 8 + +/* Internal VREF in mV */ +#define INTERNAL_VREF_MV 2560 + +/* QMP helpers for setting device properties */ + +static void qmp_adc128d818_set(const char *property, int value) +{ + QDict *resp; + + resp = qmp("{ 'execute': 'qom-set', 'arguments':" + " { 'path': %s, 'property': %s, 'value': %d } }", + ADC128D818_TEST_ID, property, value); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); +} + +static int qmp_adc128d818_get(const char *property) +{ + QDict *resp; + int ret; + + resp = qmp("{ 'execute': 'qom-get', 'arguments':" + " { 'path': %s, 'property': %s } }", + ADC128D818_TEST_ID, property); + g_assert(qdict_haskey(resp, "return")); + ret = qdict_get_int(resp, "return"); + qobject_unref(resp); + return ret; +} + +/* Manufacturer and Revision ID registers */ +static void test_id_registers(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, REG_MANUFACTURER_ID), ==, 0x01); + g_assert_cmphex(i2c_get8(dev, REG_REVISION_ID), ==, 0x09); +} + +/* Power-on-reset default values */ +static void test_defaults(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + unsigned ch; + + g_assert_cmphex(i2c_get8(dev, REG_CONFIG), ==, 0x08); + g_assert_cmphex(i2c_get8(dev, REG_INT_STATUS), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_ADV_CONFIG), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS), ==, 0x02); + + for (ch = 0u; ch < NUM_CHANNELS; ch++) { + g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE + ch * 2u), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE + ch * 2u + 1u), ==, 0x00); + } +} + +/* Software reset via INITIALIZATION bit */ +static void test_soft_reset(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, REG_INT_MASK, 0xAA); + i2c_set8(dev, REG_CH_DISABLE, 0x55); + i2c_set8(dev, REG_LIMIT_BASE, 0x42); + + g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0xAA); + g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x55); + g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0x42); + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + g_assert_cmphex(i2c_get8(dev, REG_CONFIG), ==, 0x08); + g_assert_cmphex(i2c_get8(dev, REG_INT_MASK), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_CH_DISABLE), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS), ==, 0x02); +} + +/* Verify ain property readback via QMP */ +static void test_ain_property(void *obj, void *data, QGuestAllocator *alloc) +{ + int value; + + qmp_adc128d818_set("ain3", 1500); + value = qmp_adc128d818_get("ain3"); + g_test_message("Set ain3 = 1500 mV, readback = %d mV", value); + g_assert_cmpint(value, ==, 1500); + + qmp_adc128d818_set("temperature", 37500); + value = qmp_adc128d818_get("temperature"); + g_test_message("Set temperature = 37500 mC, readback = %d mC", value); + g_assert_cmpint(value, ==, 37500); +} + +static void adc128d818_register_nodes(void) +{ + QOSGraphEdgeOptions opts = { + .extra_device_opts = "id=" ADC128D818_TEST_ID + ",address=0x1f" + }; + add_qi2c_address(&opts, &(QI2CAddress) { ADC128D818_TEST_ADDR }); + + qos_node_create_driver("adc128d818", i2c_device_create); + qos_node_consumes("adc128d818", "i2c-bus", &opts); + + qos_add_test("id-registers", "adc128d818", test_id_registers, NULL); + qos_add_test("defaults", "adc128d818", test_defaults, NULL); + qos_add_test("soft-reset", "adc128d818", test_soft_reset, NULL); + qos_add_test("ain-property", "adc128d818", test_ain_property, NULL); +} +libqos_init(adc128d818_register_nodes); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 56ff860e21..5e1fc597e6 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -304,6 +304,7 @@ qtests_hexagon = ['boot-serial-test'] qos_test_ss = ss.source_set() qos_test_ss.add( 'ac97-test.c', + 'adc128d818-test.c', 'adm1272-test.c', 'adm1266-test.c', 'ds1338-test.c', From c7300dca454f266a5cc52ea08775db50489cc755 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:15:56 +0200 Subject: [PATCH 101/627] tests/qtest: adc128d818: test voltage and temperature conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover single-ended voltage conversion across all channels, voltage and temperature boundary and clamping cases, and scaling against an external voltage reference. Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-4-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/adc128d818-test.c | 189 ++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/tests/qtest/adc128d818-test.c b/tests/qtest/adc128d818-test.c index 9a8811256f..891189f0bd 100644 --- a/tests/qtest/adc128d818-test.c +++ b/tests/qtest/adc128d818-test.c @@ -150,6 +150,186 @@ static void test_ain_property(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmpint(value, ==, 37500); } +/* Voltage conversion */ +static void test_voltage_conversion(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + qmp_adc128d818_set("ain0", 1280); + g_test_message("Injected ain0 = 1280 mV"); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Read ch0: raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain1", 2560); + g_test_message("Injected ain1 = 2560 mV"); + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("Read ch1: raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0xFFF0); + + qmp_adc128d818_set("ain2", 0); + g_test_message("Injected ain2 = 0 mV"); + reading = i2c_get16(dev, REG_CH_READING_BASE + 2u); + g_test_message("Read ch2: raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0x0000); +} + +/* Temperature conversion (mode 0, channel 7 = temperature) */ +static void +test_temperature_conversion(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + qmp_adc128d818_set("temperature", 25000); + g_test_message("Injected temperature = 25000 mC (25.0 deg C)"); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("Read ch7: raw 0x%04x -> %d mC", reading, + (int16_t)(reading & 0xFF80u) * 500 / 128); + g_assert_cmphex(reading, ==, 0x1900); +} + +/* Channels with distinct voltages */ +static void test_all_channels(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + static const uint16_t ain_mv[NUM_CHANNELS] = { + 0, 320, 640, 960, 1280, 1920, 2240, 2560 + }; + static const uint16_t expect[NUM_CHANNELS] = { + 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xC000, 0xE000, 0xFFF0 + }; + uint16_t reading; + unsigned ch; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1); + + for (ch = 0u; ch < NUM_CHANNELS; ch++) { + char name[8]; + snprintf(name, sizeof(name), "ain%u", ch); + qmp_adc128d818_set(name, ain_mv[ch]); + } + + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + for (ch = 0u; ch < NUM_CHANNELS; ch++) { + reading = i2c_get16(dev, REG_CH_READING_BASE + ch); + g_test_message("ch%u: ain %u mV -> raw 0x%04x (expect 0x%04x)", + ch, ain_mv[ch], reading, expect[ch]); + g_assert_cmphex(reading, ==, expect[ch]); + } +} + +/* Voltage conversion edge cases */ +static void test_voltage_edges(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1); + + qmp_adc128d818_set("ain0", 3000); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Over-range 3000 mV: raw 0x%04x (expect 0xFFF0)", reading); + g_assert_cmphex(reading, ==, 0xFFF0); + + qmp_adc128d818_set("ain1", 1); + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("1 mV: raw 0x%04x (expect 0x0010)", reading); + g_assert_cmphex(reading, ==, 0x0010); + + qmp_adc128d818_set("ain2", 640); + reading = i2c_get16(dev, REG_CH_READING_BASE + 2u); + g_test_message("640 mV (quarter): raw 0x%04x (expect 0x4000)", reading); + g_assert_cmphex(reading, ==, 0x4000); + + qmp_adc128d818_set("ain3", 1920); + reading = i2c_get16(dev, REG_CH_READING_BASE + 3u); + g_test_message("1920 mV (3/4): raw 0x%04x (expect 0xC000)", reading); + g_assert_cmphex(reading, ==, 0xC000); +} + +/* Temperature conversion edge cases */ +static void test_temperature_edges(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + qmp_adc128d818_set("temperature", 0); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("0 C: raw 0x%04x (expect 0x0000)", reading); + g_assert_cmphex(reading, ==, 0x0000); + + qmp_adc128d818_set("temperature", -25000); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("-25 C: raw 0x%04x (expect 0xE700)", reading); + g_assert_cmphex(reading, ==, 0xE700); + + qmp_adc128d818_set("temperature", 127500); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("+127.5 C: raw 0x%04x (expect 0x7F80)", reading); + g_assert_cmphex(reading, ==, 0x7F80); + + qmp_adc128d818_set("temperature", -128000); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("-128 C: raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("temperature", 200000); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("200 C (clamped): raw 0x%04x (expect 0x7F80)", reading); + g_assert_cmphex(reading, ==, 0x7F80); + + qmp_adc128d818_set("temperature", -200000); + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("-200 C (clamped): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* External voltage reference */ +static void test_ext_vref(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1); + + qmp_adc128d818_set("ext-vref-mv", 4096); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_EXT_REF_EN | ADV_CONFIG_MODE_1); + + qmp_adc128d818_set("ain0", 1000); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("1000 mV / 4096 mV VREF: raw 0x%04x (expect 0x3E80)", + reading); + g_assert_cmphex(reading, ==, 0x3E80); + + qmp_adc128d818_set("ain1", 2048); + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("2048 mV / 4096 mV VREF: raw 0x%04x (expect 0x8000)", + reading); + g_assert_cmphex(reading, ==, 0x8000); +} + static void adc128d818_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -165,5 +345,14 @@ static void adc128d818_register_nodes(void) qos_add_test("defaults", "adc128d818", test_defaults, NULL); qos_add_test("soft-reset", "adc128d818", test_soft_reset, NULL); qos_add_test("ain-property", "adc128d818", test_ain_property, NULL); + qos_add_test("voltage-conversion", "adc128d818", test_voltage_conversion, + NULL); + qos_add_test("temperature-conversion", "adc128d818", + test_temperature_conversion, NULL); + qos_add_test("all-channels", "adc128d818", test_all_channels, NULL); + qos_add_test("voltage-edges", "adc128d818", test_voltage_edges, NULL); + qos_add_test("temperature-edges", "adc128d818", test_temperature_edges, + NULL); + qos_add_test("ext-vref", "adc128d818", test_ext_vref, NULL); } libqos_init(adc128d818_register_nodes); From af685633f45a5ad9ed052cc5e58c7fe62bd0c631 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:15:57 +0200 Subject: [PATCH 102/627] tests/qtest: adc128d818: test limit interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover per-channel high- and low-limit interrupt status, the INT_CLEAR bit gating the monitoring loop, and the temperature high-limit alarm with hysteresis. Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-5-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/adc128d818-test.c | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/qtest/adc128d818-test.c b/tests/qtest/adc128d818-test.c index 891189f0bd..3e3fabb8d9 100644 --- a/tests/qtest/adc128d818-test.c +++ b/tests/qtest/adc128d818-test.c @@ -330,6 +330,123 @@ static void test_ext_vref(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(reading, ==, 0x8000); } +/* Interrupt status set on limit violation; persists while fault remains */ +static void test_interrupt_status(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t status; + + i2c_set8(dev, REG_LIMIT_BASE, 0x10); + g_test_message("Set ch0 high limit = 0x10"); + + qmp_adc128d818_set("ain0", 2560); + g_test_message("Injected ain0 = 2560 mV (exceeds limit)"); + + i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE); + + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS = 0x%02x (expect bit 0 set)", status); + g_assert_cmphex(status & 0x01u, ==, 0x01); + + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS after re-read = 0x%02x (expect bit 0 still set)", + status); + g_assert_cmphex(status & 0x01u, ==, 0x01); + + qmp_adc128d818_set("ain0", 80); + g_test_message("Injected ain0 = 80 mV (within limit)"); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS after fault cleared = 0x%02x " + "(expect bit 0 clear)", status); + g_assert_cmphex(status & 0x01u, ==, 0x00); +} + +/* INT_CLEAR stops the round-robin monitoring loop */ +static void test_int_clear(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t status; + + i2c_set8(dev, REG_LIMIT_BASE, 0x10); + qmp_adc128d818_set("ain0", 2560); + + i2c_set8(dev, REG_CONFIG, + CONFIG_START | CONFIG_INT_ENABLE | CONFIG_INT_CLEAR); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS with INT_CLEAR set = 0x%02x (expect 0x00)", + status); + g_assert_cmphex(status, ==, 0x00); + + i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS after INT_CLEAR cleared = 0x%02x (expect bit 0)", + status); + g_assert_cmphex(status & 0x01u, ==, 0x01); +} + +/* Low-limit interrupt triggers correctly */ +static void test_low_limit(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t status; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + i2c_set8(dev, REG_LIMIT_BASE + 3u, 0x80); + g_test_message("Set ch1 low limit = 0x80"); + + i2c_set8(dev, REG_LIMIT_BASE + 5u, 0x80); + g_test_message("Set ch2 low limit = 0x80"); + + qmp_adc128d818_set("ain1", 640); + qmp_adc128d818_set("ain2", 1280); + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START | CONFIG_INT_ENABLE); + + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("INT_STATUS = 0x%02x (expect bits 1 and 2 set)", status); + g_assert_cmphex(status & 0x02u, ==, 0x02); + g_assert_cmphex(status & 0x04u, ==, 0x04); + + g_assert_cmphex(status & 0x01u, ==, 0x00); +} + +/* Temperature high-limit interrupt with hysteresis */ +static void test_temp_hysteresis(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t status; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + i2c_set8(dev, REG_LIMIT_BASE + 7u * 2u, 0x32); + i2c_set8(dev, REG_LIMIT_BASE + 7u * 2u + 1u, 0x28); + + qmp_adc128d818_set("temperature", 25000); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("25 C: INT_STATUS = 0x%02x (temp bit expect clear)", status); + g_assert_cmphex(status & 0x80u, ==, 0x00); + + qmp_adc128d818_set("temperature", 55000); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("55 C: INT_STATUS = 0x%02x (temp bit expect set)", status); + g_assert_cmphex(status & 0x80u, ==, 0x80); + + qmp_adc128d818_set("temperature", 45000); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("45 C (hysteresis): INT_STATUS = 0x%02x " + "(temp bit expect set)", status); + g_assert_cmphex(status & 0x80u, ==, 0x80); + + qmp_adc128d818_set("temperature", 35000); + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("35 C: INT_STATUS = 0x%02x (temp bit expect clear)", status); + g_assert_cmphex(status & 0x80u, ==, 0x00); +} + static void adc128d818_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -354,5 +471,9 @@ static void adc128d818_register_nodes(void) qos_add_test("temperature-edges", "adc128d818", test_temperature_edges, NULL); qos_add_test("ext-vref", "adc128d818", test_ext_vref, NULL); + qos_add_test("interrupt-status", "adc128d818", test_interrupt_status, NULL); + qos_add_test("int-clear", "adc128d818", test_int_clear, NULL); + qos_add_test("low-limit", "adc128d818", test_low_limit, NULL); + qos_add_test("temp-hysteresis", "adc128d818", test_temp_hysteresis, NULL); } libqos_init(adc128d818_register_nodes); From 41bea707fef524b5457742d1786bece491d681d8 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:15:58 +0200 Subject: [PATCH 103/627] tests/qtest: adc128d818: test operating modes and power control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover advanced-configuration mode selection (single-ended, pseudo-differential pairs, and mixed) and the reset of readings on reconfiguration, plus channel disable, one-shot conversion, deep shutdown, BUSY_STATUS lifecycle, and conversion-rate gating. Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-6-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/adc128d818-test.c | 377 ++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) diff --git a/tests/qtest/adc128d818-test.c b/tests/qtest/adc128d818-test.c index 3e3fabb8d9..91eda5ca74 100644 --- a/tests/qtest/adc128d818-test.c +++ b/tests/qtest/adc128d818-test.c @@ -447,6 +447,368 @@ static void test_temp_hysteresis(void *obj, void *data, g_assert_cmphex(status & 0x80u, ==, 0x00); } +/* Channel disable prevents conversion */ +static void test_channel_disable(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CH_DISABLE, 0x01); + g_test_message("Disabled channel 0"); + + qmp_adc128d818_set("ain0", 1280); + g_test_message("Injected ain0 = 1280 mV (disabled)"); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Read ch0 (disabled): raw 0x%04x", reading); + g_assert_cmphex(reading, ==, 0x0000); + + qmp_adc128d818_set("ain1", 1280); + g_test_message("Injected ain1 = 1280 mV (enabled)"); + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("Read ch1 (enabled): raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* One-shot conversion in shutdown mode */ +static void test_one_shot(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + qmp_adc128d818_set("ain0", 1280); + g_test_message("Injected ain0 = 1280 mV (device stopped)"); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Read ch0 before one-shot: raw 0x%04x", reading); + g_assert_cmphex(reading, ==, 0x0000); + + g_assert_cmphex(i2c_get8(dev, REG_ONE_SHOT), ==, 0x00); + + i2c_set8(dev, REG_ONE_SHOT, 0x00); + g_test_message("Triggered one-shot conversion with value 0x00"); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Read ch0 after one-shot: raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* Mode 1 makes channel 7 a voltage input instead of temperature */ +static void test_mode_selection(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_1); + g_test_message("Set mode 1 (all voltage channels)"); + + qmp_adc128d818_set("ain7", 1280); + qmp_adc128d818_set("temperature", 50000); + g_test_message("Injected ain7 = 1280 mV, temperature = 50000 mC"); + + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("Read ch7 (mode 1): raw 0x%04x -> %u mV", reading, + (reading >> 4u) * INTERNAL_VREF_MV / 4096u); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* Mode 2 - 4 pseudo-differential pairs */ +static void test_mode2_diff(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2); + g_test_message("Set mode 2 (4 pseudo-differential pairs)"); + + qmp_adc128d818_set("ain0", 2000); + qmp_adc128d818_set("ain1", 720); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Pair 0 (IN0-IN1): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain3", 1920); + qmp_adc128d818_set("ain2", 640); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("Pair 1 (IN3-IN2): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain4", 1500); + qmp_adc128d818_set("ain5", 220); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 2u); + g_test_message("Pair 2 (IN4-IN5): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain7", 2560); + qmp_adc128d818_set("ain6", 1280); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 3u); + g_test_message("Pair 3 (IN7-IN6): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 4u); + g_test_message("Reserved ch4: raw 0x%04x (expect 0x0000)", reading); + g_assert_cmphex(reading, ==, 0x0000); + + qmp_adc128d818_set("ain0", 500); + qmp_adc128d818_set("ain1", 1000); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Pair 0 negative dV: raw 0x%04x (expect 0x0000)", reading); + g_assert_cmphex(reading, ==, 0x0000); +} + +/* Mode 3 - 4 single-ended + 2 pseudo-differential pairs */ +static void test_mode3_mixed(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_3); + g_test_message("Set mode 3 (4 single-ended + 2 differential)"); + + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Ch0 single-ended: raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain4", 1500); + qmp_adc128d818_set("ain5", 220); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 4u); + g_test_message("Ch4 diff (IN4-IN5): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain7", 2560); + qmp_adc128d818_set("ain6", 1280); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 5u); + g_test_message("Ch5 diff (IN7-IN6): raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 6u); + g_test_message("Reserved ch6: raw 0x%04x (expect 0x0000)", reading); + g_assert_cmphex(reading, ==, 0x0000); + + qmp_adc128d818_set("temperature", 25000); + + reading = i2c_get16(dev, REG_CH_READING_BASE + 7u); + g_test_message("Ch7 temperature: raw 0x%04x (expect 0x1900)", reading); + g_assert_cmphex(reading, ==, 0x1900); +} + +/* Mode change resets channel readings and interrupt status */ +static void test_mode_change_reset(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + uint8_t status; + + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Before mode change, ch0: raw 0x%04x", reading); + g_assert_cmphex(reading, !=, 0x0000); + + i2c_set8(dev, REG_CONFIG, 0x00); + i2c_set8(dev, REG_LIMIT_BASE, 0x10); + qmp_adc128d818_set("ain0", 2560); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + i2c_set8(dev, REG_CONFIG, 0x00); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After mode change, ch0: raw 0x%04x (expect 0x0000)", + reading); + g_assert_cmphex(reading, ==, 0x0000); + + status = i2c_get8(dev, REG_INT_STATUS); + g_test_message("After mode change, INT_STATUS: 0x%02x (expect 0x00)", + status); + g_assert_cmphex(status, ==, 0x00); + + g_assert_cmphex(i2c_get8(dev, REG_LIMIT_BASE), ==, 0x10); + g_test_message("Limit register preserved after mode change"); +} + +/* QOM property changes trigger correct differential conversion */ +static void test_diff_qom_trigger(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_MODE_2); + + qmp_adc128d818_set("ain0", 0); + qmp_adc128d818_set("ain1", 0); + qmp_adc128d818_set("ain2", 0); + qmp_adc128d818_set("ain3", 0); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + qmp_adc128d818_set("ain0", 2000); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After ain0=2000, ain1=0: pair0 = 0x%04x (expect 0xC800)", + reading); + g_assert_cmphex(reading, ==, 0xC800); + + qmp_adc128d818_set("ain1", 720); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After ain1=720: pair0 = 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); + + qmp_adc128d818_set("ain3", 1920); + qmp_adc128d818_set("ain2", 640); + reading = i2c_get16(dev, REG_CH_READING_BASE + 1u); + g_test_message("Pair 1 (IN3-IN2) via QOM: 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* One-shot conversion works in deep shutdown */ +static void test_deep_shutdown(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_assert_cmphex(reading, ==, 0x8000); + + i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x01); + g_test_message("DEEP_SHUTDOWN write while running rejected"); + g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x00); + + i2c_set8(dev, REG_CONFIG, 0x00); + i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x01); + qmp_adc128d818_set("ain0", 0); + + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Deep shutdown, no one-shot: raw 0x%04x (expect 0x8000)", + reading); + g_assert_cmphex(reading, ==, 0x8000); + + i2c_set8(dev, REG_ONE_SHOT, 0x01); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("Deep shutdown one-shot: raw 0x%04x (expect 0x0000)", + reading); + g_assert_cmphex(reading, ==, 0x0000); + + g_assert_cmphex(i2c_get8(dev, REG_DEEP_SHUTDOWN), ==, 0x01); + + i2c_set8(dev, REG_DEEP_SHUTDOWN, 0x00); + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_ONE_SHOT, 0x01); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After exit shutdown: raw 0x%04x (expect 0x8000)", reading); + g_assert_cmphex(reading, ==, 0x8000); +} + +/* BUSY_STATUS NOT_READY clears after first conversion */ +static void test_busy_status(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS) & 0x02, ==, 0x02); + g_test_message("After reset: BUSY_STATUS = 0x%02x (NOT_READY set)", + i2c_get8(dev, REG_BUSY_STATUS)); + + qmp_adc128d818_set("ain0", 0); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + + g_assert_cmphex(i2c_get8(dev, REG_BUSY_STATUS) & 0x02, ==, 0x00); + g_test_message("After conversion: BUSY_STATUS = 0x%02x (NOT_READY cleared)", + i2c_get8(dev, REG_BUSY_STATUS)); +} + +/* Programming Channel Disable resets channel readings */ +static void test_chan_disable_clears(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000); + + i2c_set8(dev, REG_CONFIG, 0x00); + i2c_set8(dev, REG_CH_DISABLE, 0x02); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After CH_DISABLE write: ch0 raw 0x%04x (expect 0x0000)", + reading); + g_assert_cmphex(reading, ==, 0x0000); +} + +/* Programming Advanced Configuration always resets channel readings */ +static void test_adv_config_clears(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint16_t reading; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + qmp_adc128d818_set("ain0", 1280); + i2c_set8(dev, REG_CONFIG, CONFIG_START); + g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000); + + i2c_set8(dev, REG_CONFIG, 0x00); + i2c_set8(dev, REG_ADV_CONFIG, 0x00); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After same-mode ADV_CONFIG: ch0 0x%04x (expect 0x0000)", + reading); + g_assert_cmphex(reading, ==, 0x0000); + + i2c_set8(dev, REG_CONFIG, CONFIG_START); + g_assert_cmphex(i2c_get16(dev, REG_CH_READING_BASE), ==, 0x8000); + i2c_set8(dev, REG_CONFIG, 0x00); + qmp_adc128d818_set("ext-vref-mv", 4096); + i2c_set8(dev, REG_ADV_CONFIG, ADV_CONFIG_EXT_REF_EN); + reading = i2c_get16(dev, REG_CH_READING_BASE); + g_test_message("After ext-vref toggle: ch0 0x%04x (expect 0x0000)", + reading); + g_assert_cmphex(reading, ==, 0x0000); +} + +/* Conversion Rate register may only be programmed while in shutdown */ +static void test_conv_rate(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, REG_CONFIG, CONFIG_INITIALIZATION); + + i2c_set8(dev, REG_CONV_RATE, 0x01); + g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x01); + + i2c_set8(dev, REG_CONFIG, CONFIG_START); + i2c_set8(dev, REG_CONV_RATE, 0x00); + g_test_message("CONV_RATE while running: 0x%02x (expect unchanged 0x01)", + i2c_get8(dev, REG_CONV_RATE)); + g_assert_cmphex(i2c_get8(dev, REG_CONV_RATE), ==, 0x01); +} + static void adc128d818_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -475,5 +837,20 @@ static void adc128d818_register_nodes(void) qos_add_test("int-clear", "adc128d818", test_int_clear, NULL); qos_add_test("low-limit", "adc128d818", test_low_limit, NULL); qos_add_test("temp-hysteresis", "adc128d818", test_temp_hysteresis, NULL); + qos_add_test("channel-disable", "adc128d818", test_channel_disable, NULL); + qos_add_test("one-shot", "adc128d818", test_one_shot, NULL); + qos_add_test("mode-selection", "adc128d818", test_mode_selection, NULL); + qos_add_test("mode2-diff", "adc128d818", test_mode2_diff, NULL); + qos_add_test("mode3-mixed", "adc128d818", test_mode3_mixed, NULL); + qos_add_test("mode-change-reset", "adc128d818", test_mode_change_reset, + NULL); + qos_add_test("diff-qom-trigger", "adc128d818", test_diff_qom_trigger, NULL); + qos_add_test("deep-shutdown", "adc128d818", test_deep_shutdown, NULL); + qos_add_test("busy-status", "adc128d818", test_busy_status, NULL); + qos_add_test("chan-disable-clears", "adc128d818", test_chan_disable_clears, + NULL); + qos_add_test("adv-config-clears", "adc128d818", test_adv_config_clears, + NULL); + qos_add_test("conv-rate", "adc128d818", test_conv_rate, NULL); } libqos_init(adc128d818_register_nodes); From b3e56ab9197283fdb911c0fe7cdc20f45ed2d789 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:16:00 +0200 Subject: [PATCH 104/627] hw/arm/aspeed: anacapa: use ASCII in comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The anacapa machine source contains a few comments using the U+2014 EM DASH character. Replace them with plain ASCII hyphens so the file stays ASCII-only. Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-8-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600_anacapa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed_ast2600_anacapa.c b/hw/arm/aspeed_ast2600_anacapa.c index a1c8111a93..bd6cc00686 100644 --- a/hw/arm/aspeed_ast2600_anacapa.c +++ b/hw/arm/aspeed_ast2600_anacapa.c @@ -242,7 +242,7 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) /* &i2c1 */ /* eeprom@50 */ at24c_eeprom_init(i2c[1], 0x50, 256 * KiB); - /* i2c-mux@70 (PCA9546) — 4 channels, empty */ + /* i2c-mux@70 (PCA9546) - 4 channels, empty */ i2c_slave_create_simple(i2c[1], TYPE_PCA9546, 0x70); /* &i2c4 */ @@ -259,7 +259,7 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) i2c_mux = i2c_slave_create_simple(i2c[8], TYPE_PCA9546, 0x72); /* i2c8mux ch0 */ - /* adc128d818@1f — no model */ + /* adc128d818@1f - no model */ /* pca9555@22 */ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), TYPE_PCA9552, 0x22); @@ -305,7 +305,7 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) /* i2c-mux@71 (PCA9548) */ i2c_mux = i2c_slave_create_simple(i2c[11], TYPE_PCA9548, 0x71); - /* i2c11mux ch0-ch4 — empty */ + /* i2c11mux ch0-ch4 - empty */ /* i2c11mux ch5 */ /* pca9555@22 */ @@ -328,7 +328,7 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) hpm_brd_id_eeprom, hpm_brd_id_eeprom_len); /* i2c13mux ch7 */ - /* nfc@28 — no model */ + /* nfc@28 - no model */ } static void aspeed_machine_anacapa_class_init(ObjectClass *oc, From 15d88540b83074807a483b35a7a6744571fcd9cb Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Tue, 7 Jul 2026 11:16:01 +0200 Subject: [PATCH 105/627] hw/arm: anacapa: add ADC128D818 devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire up the two ADC128D818 instances that appear in the Anacapa DTS: one on i2c8 mux channel 0 and one on i2c13 mux channel 3. Reviewed-by: Cédric Le Goater Signed-off-by: Emmanuel Blot Link: https://lore.kernel.org/qemu-devel/20260707091609.97759-9-emmanuel.blot@free.fr Signed-off-by: Cédric Le Goater --- hw/arm/Kconfig | 1 + hw/arm/aspeed_ast2600_anacapa.c | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5869f0f9e8..c502e82847 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -558,6 +558,7 @@ config ASPEED_SOC select LED select PMBUS select MAX31785 + select ADC128D818 select FSI_APB2OPB_ASPEED select AT24C select PCI_EXPRESS_ASPEED diff --git a/hw/arm/aspeed_ast2600_anacapa.c b/hw/arm/aspeed_ast2600_anacapa.c index bd6cc00686..65d6b0faa2 100644 --- a/hw/arm/aspeed_ast2600_anacapa.c +++ b/hw/arm/aspeed_ast2600_anacapa.c @@ -1,13 +1,14 @@ /* * Facebook Anacapa * - * Copyright (c) Meta Platforms, Inc. and affiliates. + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" #include "qapi/error.h" +#include "hw/sensor/adc128d818.h" #include "hw/arm/machines-qom.h" #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" @@ -15,7 +16,6 @@ #include "hw/gpio/pca9552.h" #include "hw/nvram/eeprom_at24c.h" -/* Anacapa hardware value */ #define ANACAPA_BMC_HW_STRAP1 0x00002002 #define ANACAPA_BMC_HW_STRAP2 0x00000000 #define ANACAPA_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) @@ -221,6 +221,17 @@ static const uint8_t hpm_brd_id_eeprom[] = { }; static const size_t hpm_brd_id_eeprom_len = sizeof(hpm_brd_id_eeprom); +static void anacapa_add_adc128d818(I2CBus *bus, uint8_t addr, + const char *description) +{ + DeviceState *dev = DEVICE(i2c_slave_new(TYPE_ADC128D818, addr)); + g_autofree char *childname = g_strdup_printf("0x%02x", addr); + + qdev_prop_set_string(dev, "description", description); + object_property_add_child(OBJECT(bus), childname, OBJECT(dev)); + i2c_slave_realize_and_unref(I2C_SLAVE(dev), bus, &error_fatal); +} + static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) { /* Reference: aspeed-bmc-facebook-anacapa.dts */ @@ -259,7 +270,8 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) i2c_mux = i2c_slave_create_simple(i2c[8], TYPE_PCA9546, 0x72); /* i2c8mux ch0 */ - /* adc128d818@1f - no model */ + /* adc128d818@1f - R-PDB ADC (mode 1: 8 voltage channels) */ + anacapa_add_adc128d818(pca954x_i2c_get_bus(i2c_mux, 0), 0x1f, "i2c8:0:1f"); /* pca9555@22 */ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), TYPE_PCA9552, 0x22); @@ -320,7 +332,8 @@ static void anacapa_bmc_i2c_init(AspeedMachineState *bmc) i2c_mux = i2c_slave_create_simple(i2c[13], TYPE_PCA9548, 0x70); /* i2c13mux ch3 */ - /* adc128d818@1f - no model */ + /* adc128d818@1f - MB ADC (mode 1: 8 voltage channels) */ + anacapa_add_adc128d818(pca954x_i2c_get_bus(i2c_mux, 3), 0x1f, "i2c13:3:1f"); /* i2c13mux ch4 */ /* eeprom@51 */ From 39cb912af93ebb64d4639ef4780ff0f08a0c1a60 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:39 +0200 Subject: [PATCH 106/627] hw/gpio: pca9552: register types with DEFINE_TYPES() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the separate TypeInfo definitions and pca955x_register_types() registration function with a single type array registered through the DEFINE_TYPES() macro, to prepare addition of new PCA955x-derived devices. No functional change. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-1-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 49 ++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index b13ac9fd9c..50e868a6e9 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -492,16 +492,6 @@ static void pca955x_class_init(ObjectClass *klass, const void *data) device_class_set_props(dc, pca955x_properties); } -static const TypeInfo pca955x_info = { - .name = TYPE_PCA955X, - .parent = TYPE_I2C_SLAVE, - .instance_init = pca955x_initfn, - .instance_size = sizeof(PCA955xState), - .class_init = pca955x_class_init, - .class_size = sizeof(PCA955xClass), - .abstract = true, -}; - static void pca9552_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -526,23 +516,26 @@ static void pca9535_class_init(ObjectClass *oc, const void *data) pc->has_led_support = false; } -static const TypeInfo pca9552_info = { - .name = TYPE_PCA9552, - .parent = TYPE_PCA955X, - .class_init = pca9552_class_init, +static const TypeInfo pca955x_types[] = { + { + .name = TYPE_PCA955X, + .parent = TYPE_I2C_SLAVE, + .instance_init = pca955x_initfn, + .instance_size = sizeof(PCA955xState), + .class_init = pca955x_class_init, + .class_size = sizeof(PCA955xClass), + .abstract = true, + }, + { + .name = TYPE_PCA9552, + .parent = TYPE_PCA955X, + .class_init = pca9552_class_init, + }, + { + .name = TYPE_PCA9535, + .parent = TYPE_PCA955X, + .class_init = pca9535_class_init, + } }; -static const TypeInfo pca9535_info = { - .name = TYPE_PCA9535, - .parent = TYPE_PCA955X, - .class_init = pca9535_class_init, -}; - -static void pca955x_register_types(void) -{ - type_register_static(&pca955x_info); - type_register_static(&pca9552_info); - type_register_static(&pca9535_info); -} - -type_init(pca955x_register_types) +DEFINE_TYPES(pca955x_types) From 9c995025830f1b1ee7941913dd178bf3e22a976a Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:40 +0200 Subject: [PATCH 107/627] hw/gpio: pca9552: move PCA955xState definition out of the header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing outside pca9552.c uses the PCA955xState structure, its instance checker, or the PCA955X_NR_REGS/PCA955X_PIN_COUNT_MAX defines: the board files and qtests only rely on the TYPE_* name macros (and the register macros in pca9552_regs.h). Move the state structure and the size defines into pca9552.c, leaving pca9552.h with just the type-name macros. While at it, replace the separate DECLARE_INSTANCE_CHECKER and DECLARE_CLASS_CHECKERS declarations with a single OBJECT_DECLARE_TYPE(). Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-2-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 29 ++++++++++++++++++++++++----- include/hw/gpio/pca9552.h | 30 ++++-------------------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 50e868a6e9..36bc4f86ed 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -1,7 +1,10 @@ /* - * PCA9552 I2C LED blinker + * PCA955X I2C LED blinker and I/O expanders * * https://www.nxp.com/docs/en/application-note/AN264.pdf + * https://www.nxp.com/docs/en/data-sheet/PCA9552.pdf + * https://www.nxp.com/docs/en/data-sheet/PCA9555.pdf + * https://www.nxp.com/docs/en/data-sheet/PCA9535_PCA9535C.pdf * * Copyright (c) 2017-2018, IBM Corporation. * Copyright (c) 2020 Philippe Mathieu-Daudé @@ -12,9 +15,9 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "qemu/module.h" #include "qemu/bitops.h" #include "hw/core/qdev-properties.h" +#include "hw/i2c/i2c.h" #include "hw/gpio/pca9552.h" #include "hw/gpio/pca9552_regs.h" #include "hw/core/irq.h" @@ -24,6 +27,25 @@ #include "trace.h" #include "qom/object.h" +#define PCA955X_NR_REGS 10 +#define PCA955X_PIN_COUNT_MAX 16 + +OBJECT_DECLARE_TYPE(PCA955xState, PCA955xClass, PCA955X) + +struct PCA955xState { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + + uint8_t len; + uint8_t pointer; + + uint8_t regs[PCA955X_NR_REGS]; + qemu_irq gpio_out[PCA955X_PIN_COUNT_MAX]; + uint8_t ext_state[PCA955X_PIN_COUNT_MAX]; + char *description; /* For debugging purpose only */ +}; + struct PCA955xClass { /*< private >*/ I2CSlaveClass parent_class; @@ -33,10 +55,7 @@ struct PCA955xClass { uint8_t max_reg; bool has_led_support; }; -typedef struct PCA955xClass PCA955xClass; -DECLARE_CLASS_CHECKERS(PCA955xClass, PCA955X, - TYPE_PCA955X) /* * Note: The LED_ON and LED_OFF configuration values for the PCA955X * chips are the reverse of the PCA953X family of chips. diff --git a/include/hw/gpio/pca9552.h b/include/hw/gpio/pca9552.h index 43b175235d..71479ea000 100644 --- a/include/hw/gpio/pca9552.h +++ b/include/hw/gpio/pca9552.h @@ -1,39 +1,17 @@ /* - * PCA9552 I2C LED blinker + * PCA955X I2C LED blinker and I/O expanders * * Copyright (c) 2017-2018, IBM Corporation. * * This work is licensed under the terms of the GNU GPL, version 2 or * later. See the COPYING file in the top-level directory. */ -#ifndef PCA9552_H -#define PCA9552_H -#include "hw/i2c/i2c.h" -#include "qom/object.h" +#ifndef HW_GPIO_PCA9552_H +#define HW_GPIO_PCA9552_H -#define TYPE_PCA9552 "pca9552" #define TYPE_PCA955X "pca955x" +#define TYPE_PCA9552 "pca9552" #define TYPE_PCA9535 "pca9535" -typedef struct PCA955xState PCA955xState; -DECLARE_INSTANCE_CHECKER(PCA955xState, PCA955X, - TYPE_PCA955X) - -#define PCA955X_NR_REGS 10 -#define PCA955X_PIN_COUNT_MAX 16 - -struct PCA955xState { - /*< private >*/ - I2CSlave i2c; - /*< public >*/ - - uint8_t len; - uint8_t pointer; - - uint8_t regs[PCA955X_NR_REGS]; - qemu_irq gpio_out[PCA955X_PIN_COUNT_MAX]; - uint8_t ext_state[PCA955X_PIN_COUNT_MAX]; - char *description; /* For debugging purpose only */ -}; #endif From 4618d0465a131a3b91a8d5d860cf18191deee8f2 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:41 +0200 Subject: [PATCH 108/627] hw/gpio: pca9552: rename I2CSlave member to parent_obj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the conventional parent_obj name for the embedded I2CSlave instance. Signed-off-by: Emmanuel Blot Signed-off-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-3-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 36bc4f86ed..da21e56aab 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -34,7 +34,7 @@ OBJECT_DECLARE_TYPE(PCA955xState, PCA955xClass, PCA955X) struct PCA955xState { /*< private >*/ - I2CSlave i2c; + I2CSlave parent_obj; /*< public >*/ uint8_t len; @@ -401,7 +401,7 @@ static const VMStateDescription pca9552_vmstate = { VMSTATE_UINT8(pointer, PCA955xState), VMSTATE_UINT8_ARRAY(regs, PCA955xState, PCA955X_NR_REGS), VMSTATE_UINT8_ARRAY(ext_state, PCA955xState, PCA955X_PIN_COUNT_MAX), - VMSTATE_I2C_SLAVE(i2c, PCA955xState), + VMSTATE_I2C_SLAVE(parent_obj, PCA955xState), VMSTATE_END_OF_LIST() } }; From 520ea63bd72d0b64fc150c92f48d5ce322712954 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:42 +0200 Subject: [PATCH 109/627] hw/gpio: pca9552: default description to the instantiated type name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no description is supplied, fall back to the actual QOM type name (pca9552 / pca9535 / pca9555) via object_get_typename() instead of the opaque "pca-unspecified" placeholder, matching the PCA9554 model and giving meaningful device labels in traces. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-4-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index da21e56aab..ffeb438d2a 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -488,7 +488,7 @@ static void pca955x_realize(DeviceState *dev, Error **errp) PCA955xState *s = PCA955X(dev); if (!s->description) { - s->description = g_strdup("pca-unspecified"); + s->description = g_strdup(object_get_typename(OBJECT(dev))); } qdev_init_gpio_out(dev, s->gpio_out, k->pin_count); From ee7042b317d9854d7ed221682ced4dba945dea04 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:43 +0200 Subject: [PATCH 110/627] hw/gpio: pca9552: declare pca9555 device as an alias of pca9535 device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCA9555 HW is mostly identical to PCA9535. PCA9555 HW features pull-up resistors that are not available on PCA9535. Pull-up are not handled by current PCA955x implementation and PCA9535 already initializes input as Hi-Z. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-5-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 9 +++++++-- include/hw/gpio/pca9552.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index ffeb438d2a..3b9b63eb17 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -523,7 +523,7 @@ static void pca9552_class_init(ObjectClass *oc, const void *data) pc->has_led_support = true; } -static void pca9535_class_init(ObjectClass *oc, const void *data) +static void pca95x5_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCA955xClass *pc = PCA955X_CLASS(oc); @@ -553,7 +553,12 @@ static const TypeInfo pca955x_types[] = { { .name = TYPE_PCA9535, .parent = TYPE_PCA955X, - .class_init = pca9535_class_init, + .class_init = pca95x5_class_init, + }, + { + .name = TYPE_PCA9555, + .parent = TYPE_PCA955X, + .class_init = pca95x5_class_init, } }; diff --git a/include/hw/gpio/pca9552.h b/include/hw/gpio/pca9552.h index 71479ea000..5299c13829 100644 --- a/include/hw/gpio/pca9552.h +++ b/include/hw/gpio/pca9552.h @@ -13,5 +13,6 @@ #define TYPE_PCA955X "pca955x" #define TYPE_PCA9552 "pca9552" #define TYPE_PCA9535 "pca9535" +#define TYPE_PCA9555 "pca9555" #endif From 0bfc57212e2ec42fd4b8da2d23b801224344304a Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:44 +0200 Subject: [PATCH 111/627] hw/gpio: pca9552: use the Resettable interface instead of legacy reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the PCA9552 and PCA9535/PCA9555 reset handlers from the legacy device reset hook to the Resettable interface: move each reset body into a ResettableHoldPhase handler and register it through the class's ResettableClass::phases.hold instead of device_class_set_legacy_reset(). No functional change. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-6-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 3b9b63eb17..66f699bf6a 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -406,9 +406,9 @@ static const VMStateDescription pca9552_vmstate = { } }; -static void pca9552_reset(DeviceState *dev) +static void pca9552_reset_hold(Object *obj, ResetType type) { - PCA955xState *s = PCA955X(dev); + PCA955xState *s = PCA955X(obj); s->regs[PCA9552_PSC0] = 0xFF; s->regs[PCA9552_PWM0] = 0x80; @@ -426,9 +426,9 @@ static void pca9552_reset(DeviceState *dev) s->len = 0; } -static void pca9535_reset(DeviceState *dev) +static void pca9535_reset_hold(Object *obj, ResetType type) { - PCA955xState *s = PCA955X(dev); + PCA955xState *s = PCA955X(obj); s->regs[PCA9535_INPUT0] = 0xFF; /* All inputs high (pull-ups) */ s->regs[PCA9535_INPUT1] = 0xFF; /* All inputs high (pull-ups) */ @@ -514,9 +514,10 @@ static void pca955x_class_init(ObjectClass *klass, const void *data) static void pca9552_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); PCA955xClass *pc = PCA955X_CLASS(oc); - device_class_set_legacy_reset(dc, pca9552_reset); + rc->phases.hold = pca9552_reset_hold; dc->vmsd = &pca9552_vmstate; pc->max_reg = PCA9552_LS3; pc->pin_count = 16; @@ -526,9 +527,10 @@ static void pca9552_class_init(ObjectClass *oc, const void *data) static void pca95x5_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); PCA955xClass *pc = PCA955X_CLASS(oc); - device_class_set_legacy_reset(dc, pca9535_reset); + rc->phases.hold = pca9535_reset_hold; dc->vmsd = &pca9552_vmstate; pc->max_reg = PCA9535_CONFIG1; pc->pin_count = 16; From 469daf3eeff15d43c3d28d07555b4f134909b49e Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:45 +0200 Subject: [PATCH 112/627] hw/gpio: pca9552: apply input polarity inversion on read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9535 polarity inversion register inverts the value read back from the input port for every pin, regardless of its direction, and does not affect the output drive or the physical pin level. Store the raw pin level in the input register and apply the polarity inversion when the input port is read, instead of XORing it into the stored value of output-configured pins only. The interrupt output now reflects the raw pin level, matching the datasheet. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-7-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 66f699bf6a..24f6465415 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -167,9 +167,12 @@ static void pca955x_update_pin_input(PCA955xState *s) /* PCA9535: Simple GPIO behavior */ uint8_t config_reg = PCA9535_CONFIG0 + (i / 8); uint8_t output_reg = PCA9535_OUTPUT0 + (i / 8); - uint8_t polarity_reg = PCA9535_POLARITY0 + (i / 8); - /* Check if pin is configured as input */ + /* + * The input register holds the raw pin logic level; the + * polarity inversion register is only applied when the input + * port is read (see pca955x_read()). + */ if (s->regs[config_reg] & bit_mask) { /* Input mode - reflect external state */ if (s->ext_state[i] == PCA9552_PIN_LOW) { @@ -179,12 +182,8 @@ static void pca955x_update_pin_input(PCA955xState *s) } } else { /* Output mode - reflect output register value */ - uint8_t output_bit = s->regs[output_reg] & bit_mask; - uint8_t polarity_bit = s->regs[polarity_reg] & bit_mask; - - /* Apply polarity inversion if set */ s->regs[input_reg] = (s->regs[input_reg] & ~bit_mask) | - ((output_bit ^ polarity_bit) & bit_mask); + (s->regs[output_reg] & bit_mask); } } @@ -206,6 +205,18 @@ static uint8_t pca955x_read(PCA955xState *s, uint8_t reg) return 0xFF; } + /* + * On the GPIO variants, reading an input port returns the raw pin + * levels XORed with the polarity inversion register, as specified by + * the datasheet. + */ + if (!k->has_led_support && + (reg == PCA9535_INPUT0 || reg == PCA9535_INPUT1)) { + uint8_t polarity_reg = PCA9535_POLARITY0 + (reg - PCA9535_INPUT0); + + return s->regs[reg] ^ s->regs[polarity_reg]; + } + return s->regs[reg]; } From f8e1f6488f2b9f79b37c9c40db17f9be1beea032 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:46 +0200 Subject: [PATCH 113/627] hw/gpio: pca9552: conform GPIO command handling to the datasheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9535/PCA9555 GPIO expanders share the PCA955X command dispatch path with the PCA9552 LED blinker, but their register access differs from the LED variant: - Auto-increment happens on every access and toggles bit 0 so the pointer stays within the addressed register pair (input, output, polarity, config); there is no AI enable bit. - The command byte only decodes 3 bits, so addresses beyond the last register alias back into the 8-register window instead of faulting. Branch the auto-increment and command-decode logic on has_led_support so the GPIO variants follow their datasheet while the PCA9552 behaviour is left untouched. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-8-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 24f6465415..54a5945d92 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -259,14 +259,26 @@ static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data) } /* - * When Auto-Increment is on, the register address is incremented - * after each byte is sent to or received by the device. The index - * rollovers to 0 when the maximum register address is reached. + * Advance the command pointer after each byte sent to or received from the + * device. + * + * The LED variant auto-increments only when the AI bit (bit 4) is set in the + * command byte, rolling over to 0 once the maximum register address is + * reached. + * + * The GPIO variants auto-increment on every access, toggling bit 0 so the + * pointer stays within the addressed register pair + * (input/output/polarity/config), as specified by their datasheet. */ static void pca955x_autoinc(PCA955xState *s) { PCA955xClass *k = PCA955X_GET_CLASS(s); + if (!k->has_led_support) { + s->pointer ^= 0x1; + return; + } + if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) { uint8_t reg = s->pointer & 0xf; @@ -275,12 +287,25 @@ static void pca955x_autoinc(PCA955xState *s) } } +/* + * The LED variant addresses its registers with a 4-bit command field, while + * the GPIO variants only decode 3 bits (the command wraps into the 8-register + * window). + */ +static inline uint8_t pca955x_cmd_reg(PCA955xState *s) +{ + PCA955xClass *k = PCA955X_GET_CLASS(s); + + return s->pointer & (k->has_led_support ? 0xf : 0x7); +} + static uint8_t pca955x_recv(I2CSlave *i2c) { PCA955xState *s = PCA955X(i2c); + PCA955xClass *k = PCA955X_GET_CLASS(s); uint8_t ret; - ret = pca955x_read(s, s->pointer & 0xf); + ret = pca955x_read(s, pca955x_cmd_reg(s)); /* * From the Specs: @@ -292,7 +317,7 @@ static uint8_t pca955x_recv(I2CSlave *i2c) * I don't know what should be done in this case, so throw an * error. */ - if (s->pointer == PCA9552_AUTOINC) { + if (k->has_led_support && s->pointer == PCA9552_AUTOINC) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Autoincrement read starting with register 0\n", __func__); @@ -312,7 +337,7 @@ static int pca955x_send(I2CSlave *i2c, uint8_t data) s->pointer = data; s->len++; } else { - pca955x_write(s, s->pointer & 0xf, data); + pca955x_write(s, pca955x_cmd_reg(s), data); pca955x_autoinc(s); } From a11babc63217a5e3e8a9a7350654e35755f6ad11 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:47 +0200 Subject: [PATCH 114/627] hw/gpio: pca9552: expose GPIO pins as pin%d QOM properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9552 exposes its LED channels as led%d QOM string properties, but the GPIO variants (PCA9535/PCA9555) inherited the same led%d interface, which drives the LED selector registers and is meaningless for a plain I/O expander. Add pin%d string properties ("low"/"high") for the GPIO variants, mirroring the standalone pca9555 model: - reading returns the raw pin logic level from the INPUT register; - writing drives the external input level, but only for pins the guest has configured as inputs (writes to output pins are ignored with a LOG_UNIMP message). The LED variant keeps its led%d properties. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-9-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9552.c | 91 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 54a5945d92..719149b717 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -68,6 +68,7 @@ struct PCA955xClass { #define PCA9552_PIN_HIZ 0x1 static const char *led_state[] = {"on", "off", "pwm0", "pwm1"}; +static const char *pin_state[] = {"low", "high"}; static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin) { @@ -428,6 +429,79 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name, pca955x_write(s, reg, val); } +static void pca955x_set_ext_state(PCA955xState *s, int pin, int level); + +static void pca955x_get_pin(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + PCA955xClass *k = PCA955X_GET_CLASS(obj); + PCA955xState *s = PCA955X(obj); + int pin, rc; + uint8_t input_reg, state; + + rc = sscanf(name, "pin%2d", &pin); + if (rc != 1) { + error_setg(errp, "%s: error reading %s", __func__, name); + return; + } + if (pin < 0 || pin >= k->pin_count) { + error_setg(errp, "%s invalid pin %s", __func__, name); + return; + } + + /* + * Report the raw pin logic level; polarity inversion is a read-time + * transform applied to the INPUT register, not to the pin state itself. + */ + input_reg = PCA9535_INPUT0 + (pin / 8); + state = (s->regs[input_reg] >> (pin % 8)) & 0x1; + visit_type_str(v, name, (char **)&pin_state[state], errp); +} + +static void pca955x_set_pin(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + PCA955xClass *k = PCA955X_GET_CLASS(obj); + PCA955xState *s = PCA955X(obj); + int pin, rc; + uint8_t state, config_reg; + g_autofree char *state_str = NULL; + + if (!visit_type_str(v, name, &state_str, errp)) { + return; + } + rc = sscanf(name, "pin%2d", &pin); + if (rc != 1) { + error_setg(errp, "%s: error reading %s", __func__, name); + return; + } + if (pin < 0 || pin >= k->pin_count) { + error_setg(errp, "%s invalid pin %s", __func__, name); + return; + } + + for (state = 0; state < ARRAY_SIZE(pin_state); state++) { + if (!strcmp(state_str, pin_state[state])) { + break; + } + } + if (state >= ARRAY_SIZE(pin_state)) { + error_setg(errp, "%s invalid pin state %s", __func__, state_str); + return; + } + + /* Only input-configured pins can be driven by an external device. */ + config_reg = PCA9535_CONFIG0 + (pin / 8); + if (!((s->regs[config_reg] >> (pin % 8)) & 0x1)) { + qemu_log_mask(LOG_UNIMP, + "%s: pin %d is configured as output, ignoring set\n", + s->description, pin); + return; + } + + pca955x_set_ext_state(s, pin, state != PCA9552_PIN_LOW); +} + static const VMStateDescription pca9552_vmstate = { .name = "PCA9552", .version_id = 0, @@ -485,15 +559,22 @@ static void pca9535_reset_hold(Object *obj, ResetType type) static void pca955x_initfn(Object *obj) { PCA955xClass *k = PCA955X_GET_CLASS(obj); - int led; assert(k->pin_count <= PCA955X_PIN_COUNT_MAX); - for (led = 0; led < k->pin_count; led++) { + for (int ix = 0; ix < k->pin_count; ix++) { char *name; - name = g_strdup_printf("led%d", led); - object_property_add(obj, name, "bool", pca955x_get_led, pca955x_set_led, - NULL, NULL); + if (k->has_led_support) { + /* LED variant: expose the LED selector state as led%d. */ + name = g_strdup_printf("led%d", ix); + object_property_add(obj, name, "bool", + pca955x_get_led, pca955x_set_led, NULL, NULL); + } else { + /* GPIO variant: expose the pin logic level as pin%d. */ + name = g_strdup_printf("pin%d", ix); + object_property_add(obj, name, "str", + pca955x_get_pin, pca955x_set_pin, NULL, NULL); + } g_free(name); } } From 71aa15068ccaa8b330f4f324c33315557d54742c Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:48 +0200 Subject: [PATCH 115/627] tests/qtest: add PCA9555 register access tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a qtest for the PCA9555 16-bit I/O port expander. This first set covers the power-on reset defaults and the read/write behaviour of the OUTPUT, CONFIG and POLARITY register pairs. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-10-814575bc076b@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/meson.build | 1 + tests/qtest/pca9555-test.c | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/qtest/pca9555-test.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 5e1fc597e6..e92130bd04 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -319,6 +319,7 @@ qos_test_ss.add( 'tulip-test.c', 'nvme-test.c', 'pca9552-test.c', + 'pca9555-test.c', 'pci-test.c', 'pcnet-test.c', 'rs5c372-test.c', diff --git a/tests/qtest/pca9555-test.c b/tests/qtest/pca9555-test.c new file mode 100644 index 0000000000..5945c3441e --- /dev/null +++ b/tests/qtest/pca9555-test.c @@ -0,0 +1,44 @@ +/* + * QTest testcase for the PCA9555 16-bit I/O port expander + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/gpio/pca9552_regs.h" +#include "libqos/i2c.h" +#include "libqos/qgraph.h" + +#define PCA9555_TEST_ADDR 0x20 + +/* Verify power-on reset defaults match the PCA9555 datasheet. */ +static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_POLARITY0), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_POLARITY1), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG0), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xFF); +} + +static void pca9555_register_nodes(void) +{ + QOSGraphEdgeOptions opts = { + .extra_device_opts = "address=0x20" + }; + add_qi2c_address(&opts, &(QI2CAddress) { PCA9555_TEST_ADDR }); + + qos_node_create_driver("pca9555", i2c_device_create); + qos_node_consumes("pca9555", "i2c-bus", &opts); + + qos_add_test("reset-defaults", "pca9555", test_reset_defaults, NULL); +} + +libqos_init(pca9555_register_nodes); From 0e964386792dcd40e6657155db8545a814eefa4b Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:03 +0200 Subject: [PATCH 116/627] tests/qtest: pca9555: test output-to-input reflection and pull-ups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests covering the pin I/O semantics of the expander: output-driven pins reflected in the input register, the pull-up seen on input-configured pins, and the independence of the two 8-bit ports. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-11-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9555-test.c | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/qtest/pca9555-test.c b/tests/qtest/pca9555-test.c index 5945c3441e..6b085702c3 100644 --- a/tests/qtest/pca9555-test.c +++ b/tests/qtest/pca9555-test.c @@ -28,6 +28,77 @@ static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xFF); } +/* + * When a pin is configured as output and driven low (output=0, config=0), + * the input register should reflect 0 for that pin. + * When driven high (output=1, config=0), input should reflect 1. + * When configured as input (config=1), PCA5555 pull-up makes it read 1. + */ +static void test_output_drives_input(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9535_CONFIG0, 0xF0); + i2c_set8(dev, PCA9535_OUTPUT0, 0xFA); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFA); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF); + + i2c_set8(dev, PCA9535_CONFIG0, 0x00); + i2c_set8(dev, PCA9535_OUTPUT0, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00); + + i2c_set8(dev, PCA9535_OUTPUT0, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF); +} + +/* + * When all pins are inputs (config=0xFF) and no external driver, + * PCA9555 pull-ups should make the input register read all ones. + * Switching a pin to output mode with output=0 should drive it low. + */ +static void test_input_pullup(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF); + + i2c_set8(dev, PCA9535_OUTPUT0, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF); + + i2c_set8(dev, PCA9535_CONFIG0, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00); +} + +/* + * Test that both ports are independent: changing port 0 registers + * should not affect port 1 and vice versa. + */ +static void test_port_independence(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9535_CONFIG0, 0x00); + i2c_set8(dev, PCA9535_OUTPUT0, 0x00); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xFF); + + i2c_set8(dev, PCA9535_CONFIG1, 0x00); + i2c_set8(dev, PCA9535_OUTPUT1, 0xAA); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xAA); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xAA); +} + static void pca9555_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -39,6 +110,10 @@ static void pca9555_register_nodes(void) qos_node_consumes("pca9555", "i2c-bus", &opts); qos_add_test("reset-defaults", "pca9555", test_reset_defaults, NULL); + qos_add_test("output-drives-input", "pca9555", test_output_drives_input, + NULL); + qos_add_test("input-pullup", "pca9555", test_input_pullup, NULL); + qos_add_test("port-independence", "pca9555", test_port_independence, NULL); } libqos_init(pca9555_register_nodes); From f2fa57afffde5885d69d2db3a7a22a8c5d1eba1a Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:04 +0200 Subject: [PATCH 117/627] tests/qtest: pca9555: test polarity inversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for the polarity inversion register: the inversion is applied when reading the INPUT register, both for input pins (pull-up) and for output-driven pins, and it does not affect the OUTPUT register readback. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-12-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9555-test.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/qtest/pca9555-test.c b/tests/qtest/pca9555-test.c index 6b085702c3..2afa061bd2 100644 --- a/tests/qtest/pca9555-test.c +++ b/tests/qtest/pca9555-test.c @@ -99,6 +99,46 @@ static void test_port_independence(void *obj, void *data, g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0xAA); } +/* + * Polarity inversion: reading INPUT with polarity bits set should + * return the XOR of the actual input state and the polarity register. + */ +static void test_polarity_inversion(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xFF); + + i2c_set8(dev, PCA9535_POLARITY0, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x00); + + i2c_set8(dev, PCA9535_POLARITY0, 0x0F); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xF0); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0xFF); + + i2c_set8(dev, PCA9535_POLARITY1, 0xAA); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT1), ==, 0x55); +} + +/* Polarity inversion combined with output-driven pins. */ +static void test_polarity_with_output(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9535_CONFIG0, 0x00); + i2c_set8(dev, PCA9535_OUTPUT0, 0xA5); + + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0xA5); + + i2c_set8(dev, PCA9535_POLARITY0, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9535_INPUT0), ==, 0x5A); + + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0xA5); +} + static void pca9555_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -114,6 +154,10 @@ static void pca9555_register_nodes(void) NULL); qos_add_test("input-pullup", "pca9555", test_input_pullup, NULL); qos_add_test("port-independence", "pca9555", test_port_independence, NULL); + qos_add_test("polarity-inversion", "pca9555", test_polarity_inversion, + NULL); + qos_add_test("polarity-with-output", "pca9555", test_polarity_with_output, + NULL); } libqos_init(pca9555_register_nodes); From f43ee338662b02827c61c033fcc35be68eae952c Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:05 +0200 Subject: [PATCH 118/627] tests/qtest: pca9555: test auto-increment and command wrapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for the I2C command protocol of the GPIO variant: the auto-increment that toggles bit 0 within a register pair on reads and writes, and the 3-bit command wrapping that aliases out-of-range register addresses back into the register window. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-13-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9555-test.c | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/qtest/pca9555-test.c b/tests/qtest/pca9555-test.c index 2afa061bd2..84d771bcbb 100644 --- a/tests/qtest/pca9555-test.c +++ b/tests/qtest/pca9555-test.c @@ -139,6 +139,87 @@ static void test_polarity_with_output(void *obj, void *data, g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0xA5); } +/* + * The PCA9555 auto-increments by toggling bit 0 of the command pointer + * within a register pair. Reading two bytes from INPUT0 should yield + * INPUT0 then INPUT1. + */ +static void test_auto_increment_read(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t buf[2]; + + i2c_set8(dev, PCA9535_CONFIG0, 0x00); + i2c_set8(dev, PCA9535_CONFIG1, 0x00); + i2c_set8(dev, PCA9535_OUTPUT0, 0xAA); + i2c_set8(dev, PCA9535_OUTPUT1, 0x55); + + i2c_read_block(dev, PCA9535_INPUT0, buf, 2); + g_assert_cmphex(buf[0], ==, 0xAA); + g_assert_cmphex(buf[1], ==, 0x55); + + i2c_read_block(dev, PCA9535_OUTPUT0, buf, 2); + g_assert_cmphex(buf[0], ==, 0xAA); + g_assert_cmphex(buf[1], ==, 0x55); +} + +/* + * Auto-increment write: writing two data bytes after a command byte + * should write to port 0 then port 1 of the addressed register pair. + */ +static void test_auto_increment_write(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t buf[2]; + + buf[0] = 0x12; + buf[1] = 0x34; + i2c_write_block(dev, PCA9535_OUTPUT0, buf, 2); + + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT0), ==, 0x12); + g_assert_cmphex(i2c_get8(dev, PCA9535_OUTPUT1), ==, 0x34); + + buf[0] = 0x0F; + buf[1] = 0xF0; + i2c_write_block(dev, PCA9535_CONFIG0, buf, 2); + + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG0), ==, 0x0F); + g_assert_cmphex(i2c_get8(dev, PCA9535_CONFIG1), ==, 0xF0); +} + +/* + * Auto-increment toggles within the pair: starting from port 1 should + * wrap back to port 0 (toggle bit 0). + */ +static void test_auto_increment_toggle(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t buf[2]; + + i2c_set8(dev, PCA9535_OUTPUT0, 0xAA); + i2c_set8(dev, PCA9535_OUTPUT1, 0x55); + + i2c_read_block(dev, PCA9535_OUTPUT1, buf, 2); + g_assert_cmphex(buf[0], ==, 0x55); + g_assert_cmphex(buf[1], ==, 0xAA); +} + +/* + * Verify the command byte wraps at 3 bits: register addresses + * beyond 7 should alias to the same register (bits [2:0] only). + */ +static void test_command_wrapping(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9535_OUTPUT0, 0x42); + + g_assert_cmphex(i2c_get8(dev, 0x0A), ==, 0x42); +} + static void pca9555_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -158,6 +239,13 @@ static void pca9555_register_nodes(void) NULL); qos_add_test("polarity-with-output", "pca9555", test_polarity_with_output, NULL); + qos_add_test("auto-increment-read", "pca9555", test_auto_increment_read, + NULL); + qos_add_test("auto-increment-write", "pca9555", test_auto_increment_write, + NULL); + qos_add_test("auto-increment-toggle", "pca9555", test_auto_increment_toggle, + NULL); + qos_add_test("command-wrapping", "pca9555", test_command_wrapping, NULL); } libqos_init(pca9555_register_nodes); From f41bc13152c29261202c1394e3429188ac6c0fdd Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:06 +0200 Subject: [PATCH 119/627] tests/qtest: pca9552: test behaviour specific to the LED variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9552 shares its device model with the PCA9535/PCA9555 GPIO expanders but decodes registers differently. Add tests for the behaviour that is specific to the LED variant and diverges from the PCA9555: - the power-on reset defaults of the prescaler, PWM and LED-selector registers; - the prescaler/PWM registers (2-5), which are OUTPUT/POLARITY on the PCA9555, as plain read/write storage; - the auto-increment, which only advances when the AI command bit is set and wraps modulo the full 10-register map (rather than toggling bit 0 within a register pair); - the 4-bit command decode, where an out-of-range register reads back 0xFF instead of aliasing into the register window. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-14-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9552-test.c | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/qtest/pca9552-test.c b/tests/qtest/pca9552-test.c index 7474957692..3718dfbd22 100644 --- a/tests/qtest/pca9552-test.c +++ b/tests/qtest/pca9552-test.c @@ -77,6 +77,76 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(value, ==, 0xEF); } +/* Verify the power-on reset defaults. */ +static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + /* Prescalers, PWM duty cycles and LED selectors (all LEDs off) */ + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PSC0), ==, 0xFF); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PWM0), ==, 0x80); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PSC1), ==, 0xFF); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_PWM1), ==, 0x80); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS0), ==, 0x55); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS1), ==, 0x55); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS2), ==, 0x55); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_LS3), ==, 0x55); + + /* All LEDs off, so every pin floats high through its pull-up */ + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_INPUT0), ==, 0xFF); + g_assert_cmphex(i2c_get8(i2cdev, PCA9552_INPUT1), ==, 0xFF); +} + +/* + * The PCA9552 only advances the command pointer when the AI bit is set, and + * it wraps modulo the full 10-register map. + */ +static void test_autoinc_requires_ai_bit(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + uint8_t reg; + uint8_t resp; + + /* + * With the AI bit, reading from LS3 (register 9) rolls over to INPUT0 + * (register 0), not to a sibling in a register pair. All LEDs are off + * after reset so the input ports read 0xFF. + */ + reg = PCA9552_LS3 | PCA9552_AUTOINC; + qi2c_send(i2cdev, ®, 1); + qi2c_recv(i2cdev, &resp, 1); /* LS3 */ + g_assert_cmphex(resp, ==, 0x55); + qi2c_recv(i2cdev, &resp, 1); /* wraps to INPUT0 */ + g_assert_cmphex(resp, ==, 0xFF); + qi2c_recv(i2cdev, &resp, 1); /* INPUT1 */ + g_assert_cmphex(resp, ==, 0xFF); + + /* + * Without the AI bit the pointer must not advance: repeated reads keep + * returning the same register. + */ + i2c_set8(i2cdev, PCA9552_LS0, 0x54); + reg = PCA9552_LS0; + qi2c_send(i2cdev, ®, 1); + qi2c_recv(i2cdev, &resp, 1); + g_assert_cmphex(resp, ==, 0x54); + qi2c_recv(i2cdev, &resp, 1); + g_assert_cmphex(resp, ==, 0x54); +} + +/* + * The PCA9552 decodes a 4-bit command and has no register past LS3 (9), so + * addressing register 0x0A reads back 0xFF. + */ +static void test_command_out_of_range(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *i2cdev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(i2cdev, 0x0A), ==, 0xFF); +} + static void pca9552_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -89,5 +159,11 @@ static void pca9552_register_nodes(void) qos_add_test("tx-rx", "pca9552", send_and_receive, NULL); qos_add_test("rx-autoinc", "pca9552", receive_autoinc, NULL); + qos_add_test("reset-defaults", "pca9552", test_reset_defaults, NULL); + qos_add_test("autoinc-requires-ai-bit", "pca9552", + test_autoinc_requires_ai_bit, NULL); + qos_add_test("command-out-of-range", "pca9552", test_command_out_of_range, + NULL); } + libqos_init(pca9552_register_nodes); From 5eceb48bbe86f4ef5fa59aa9896d2b09d5aae11a Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:07 +0200 Subject: [PATCH 120/627] hw/gpio: pca9554: add PCA9536 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9536 is a 4-bit I/O expander that's register-compatible with the PCA9554 but only has 4 pins. Rather than duplicating the whole driver, make the existing PCA9554 model parameterizable and register PCA9536 as a subtype. Introduce a PCA9554Class with a pin_count property, and replace every hard-coded PCA9554_PIN_COUNT reference in the driver with the class value. The reset function now computes the correct pin mask from pin_count instead of assuming 0xFF. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-15-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9554.c | 81 +++++++++++++++++++++++++-------------- include/hw/gpio/pca9554.h | 2 + 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index 8427e01e9b..b44ec0d999 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -24,6 +24,8 @@ struct PCA9554Class { /*< private >*/ I2CSlaveClass parent_class; /*< public >*/ + + uint8_t pin_count; }; typedef struct PCA9554Class PCA9554Class; @@ -37,12 +39,13 @@ static const char *pin_state[] = {"low", "high"}; static void pca9554_update_pin_input(PCA9554State *s) { + PCA9554Class *pc = PCA9554_GET_CLASS(s); int i; uint8_t config = s->regs[PCA9554_CONFIG]; uint8_t output = s->regs[PCA9554_OUTPUT]; uint8_t internal_state = config | output; - for (i = 0; i < PCA9554_PIN_COUNT; i++) { + for (i = 0; i < pc->pin_count; i++) { uint8_t bit_mask = 1 << i; uint8_t internal_pin_state = (internal_state >> i) & 0x1; uint8_t old_value = s->regs[PCA9554_INPUT] & bit_mask; @@ -67,7 +70,7 @@ static void pca9554_update_pin_input(PCA9554State *s) break; } - /* update irq state only if pin state changed */ + /* drive the per-pin GPIO output only if the pin level changed */ new_value = s->regs[PCA9554_INPUT] & bit_mask; if (new_value != old_value) { if (new_value) { @@ -99,6 +102,12 @@ static uint8_t pca9554_read(PCA9554State *s, uint8_t reg) static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data) { + PCA9554Class *pc = PCA9554_GET_CLASS(s); + uint8_t pin_mask = (1 << pc->pin_count) - 1; + + /* Variants narrower than 8 bits ignore the unimplemented upper pins. */ + data &= pin_mask; + switch (reg) { case PCA9554_OUTPUT: case PCA9554_CONFIG: @@ -157,7 +166,7 @@ static void pca9554_get_pin(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (pin < 0 || pin >= PCA9554_PIN_COUNT) { + if (pin < 0 || pin >= PCA9554_GET_CLASS(s)->pin_count) { error_setg(errp, "%s invalid pin %s", __func__, name); return; } @@ -184,7 +193,7 @@ static void pca9554_set_pin(Object *obj, Visitor *v, const char *name, error_setg(errp, "%s: error reading %s", __func__, name); return; } - if (pin < 0 || pin >= PCA9554_PIN_COUNT) { + if (pin < 0 || pin >= PCA9554_GET_CLASS(s)->pin_count) { error_setg(errp, "%s invalid pin %s", __func__, name); return; } @@ -232,13 +241,15 @@ static const VMStateDescription pca9554_vmstate = { static void pca9554_reset(DeviceState *dev) { PCA9554State *s = PCA9554(dev); + PCA9554Class *pc = PCA9554_GET_CLASS(s); + uint8_t pin_mask = (1 << pc->pin_count) - 1; - s->regs[PCA9554_INPUT] = 0xFF; - s->regs[PCA9554_OUTPUT] = 0xFF; + s->regs[PCA9554_INPUT] = pin_mask; + s->regs[PCA9554_OUTPUT] = pin_mask; s->regs[PCA9554_POLARITY] = 0x0; /* No pins are inverted */ - s->regs[PCA9554_CONFIG] = 0xFF; /* All pins are inputs */ + s->regs[PCA9554_CONFIG] = pin_mask; /* All pins are inputs */ - memset(s->ext_state, PCA9554_PIN_HIZ, PCA9554_PIN_COUNT); + memset(s->ext_state, PCA9554_PIN_HIZ, pc->pin_count); pca9554_update_pin_input(s); s->pointer = 0x0; @@ -247,9 +258,10 @@ static void pca9554_reset(DeviceState *dev) static void pca9554_initfn(Object *obj) { + PCA9554Class *pc = PCA9554_GET_CLASS(obj); int pin; - for (pin = 0; pin < PCA9554_PIN_COUNT; pin++) { + for (pin = 0; pin < pc->pin_count; pin++) { char *name; name = g_strdup_printf("pin%d", pin); @@ -269,23 +281,24 @@ static void pca9554_set_ext_state(PCA9554State *s, int pin, int level) static void pca9554_gpio_in_handler(void *opaque, int pin, int level) { - PCA9554State *s = PCA9554(opaque); + PCA9554Class *pc = PCA9554_GET_CLASS(s); - assert((pin >= 0) && (pin < PCA9554_PIN_COUNT)); + assert((pin >= 0) && (pin < pc->pin_count)); pca9554_set_ext_state(s, pin, level); } static void pca9554_realize(DeviceState *dev, Error **errp) { PCA9554State *s = PCA9554(dev); + PCA9554Class *pc = PCA9554_GET_CLASS(s); if (!s->description) { - s->description = g_strdup("pca9554"); + s->description = g_strdup(object_get_typename(OBJECT(dev))); } - qdev_init_gpio_out(dev, s->gpio_out, PCA9554_PIN_COUNT); - qdev_init_gpio_in(dev, pca9554_gpio_in_handler, PCA9554_PIN_COUNT); + qdev_init_gpio_out(dev, s->gpio_out, pc->pin_count); + qdev_init_gpio_in(dev, pca9554_gpio_in_handler, pc->pin_count); } static const Property pca9554_properties[] = { @@ -296,6 +309,7 @@ static void pca9554_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + PCA9554Class *pc = PCA9554_CLASS(klass); k->event = pca9554_event; k->recv = pca9554_recv; @@ -304,21 +318,32 @@ static void pca9554_class_init(ObjectClass *klass, const void *data) device_class_set_legacy_reset(dc, pca9554_reset); dc->vmsd = &pca9554_vmstate; device_class_set_props(dc, pca9554_properties); + + pc->pin_count = PCA9554_PIN_COUNT; } -static const TypeInfo pca9554_info = { - .name = TYPE_PCA9554, - .parent = TYPE_I2C_SLAVE, - .instance_init = pca9554_initfn, - .instance_size = sizeof(PCA9554State), - .class_init = pca9554_class_init, - .class_size = sizeof(PCA9554Class), - .abstract = false, +static void pca9536_class_init(ObjectClass *klass, const void *data) +{ + PCA9554Class *pc = PCA9554_CLASS(klass); + + pc->pin_count = PCA9536_PIN_COUNT; +} + +static const TypeInfo pca9554_types[] = { + { + .name = TYPE_PCA9554, + .parent = TYPE_I2C_SLAVE, + .instance_init = pca9554_initfn, + .instance_size = sizeof(PCA9554State), + .class_init = pca9554_class_init, + .class_size = sizeof(PCA9554Class), + .abstract = false, + }, + { + .name = TYPE_PCA9536, + .parent = TYPE_PCA9554, + .class_init = pca9536_class_init, + } }; -static void pca9554_register_types(void) -{ - type_register_static(&pca9554_info); -} - -type_init(pca9554_register_types) +DEFINE_TYPES(pca9554_types); diff --git a/include/hw/gpio/pca9554.h b/include/hw/gpio/pca9554.h index 54bfc4c4c7..c09108e8b6 100644 --- a/include/hw/gpio/pca9554.h +++ b/include/hw/gpio/pca9554.h @@ -12,12 +12,14 @@ #include "qom/object.h" #define TYPE_PCA9554 "pca9554" +#define TYPE_PCA9536 "pca9536" typedef struct PCA9554State PCA9554State; DECLARE_INSTANCE_CHECKER(PCA9554State, PCA9554, TYPE_PCA9554) #define PCA9554_NR_REGS 4 #define PCA9554_PIN_COUNT 8 +#define PCA9536_PIN_COUNT 4 struct PCA9554State { /*< private >*/ From 0d02f7b87789f95393dcaa4b9109e29a061ae120 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:08 +0200 Subject: [PATCH 121/627] hw/gpio: pca9554: add hw-dir property honoring the configured pin direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pinN QOM accessors are meant to let external agents observe and stimulate the expander's pins, but their default behaviour does not match real hardware: - to "drive" a pin, set_pin writes the OUTPUT register and then clears the pin's Configuration bit to force it into output mode. On a real device the pin direction is owned solely by the host (programmed through the Configuration register over I2C); an external agent can neither flip a pin's direction nor impose a level on a pin the host drives as an output -- the latter is a voltage conflict, not a legal operation. - get_pin returns a CONFIG|OUTPUT composite, i.e. the guest's intent, rather than the level actually sampled on the pin. The PCA9555 GPIO variant (hw/gpio/pca9552.c) already models this correctly and unconditionally: only input-configured pins can be driven from outside, and reads return the sampled INPUT register. Add a "hw-dir" property to bring the pca9554 pin accessors in line with the hardware (and with the PCA9555 model), without changing the behaviour seen by existing users: - hw-dir=true: set_pin only drives pins the guest has configured as inputs; a set on an output pin is refused with a LOG_UNIMP warning. get_pin returns the sampled INPUT register. - hw-dir=false (default): keeps the legacy, non-conformant behaviour for backward compatibility. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-16-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9554.c | 65 +++++++++++++++++++++++++-------------- include/hw/gpio/pca9554.h | 1 + 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index b44ec0d999..ed38fe102b 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -154,6 +154,14 @@ static int pca9554_event(I2CSlave *i2c, enum i2c_event event) return 0; } +static void pca9554_set_ext_state(PCA9554State *s, int pin, int level) +{ + if (s->ext_state[pin] != level) { + s->ext_state[pin] = level; + pca9554_update_pin_input(s); + } +} + static void pca9554_get_pin(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -171,9 +179,13 @@ static void pca9554_get_pin(Object *obj, Visitor *v, const char *name, return; } - state = pca9554_read(s, PCA9554_CONFIG); - state |= pca9554_read(s, PCA9554_OUTPUT); - state = (state >> pin) & 0x1; + /* + * Report the physical pin level. The input register is kept in sync by + * pca9554_update_pin_input(): output pins mirror the OUTPUT register and + * input pins reflect the externally driven (or pulled-up) level, so it + * holds the wire level regardless of the configured direction. + */ + state = (s->regs[PCA9554_INPUT] >> pin) & 0x1; visit_type_str(v, name, (char **)&pin_state[state], errp); } @@ -208,20 +220,34 @@ static void pca9554_set_pin(Object *obj, Visitor *v, const char *name, return; } - /* First, modify the output register bit */ - val = pca9554_read(s, PCA9554_OUTPUT); - mask = 0x1 << pin; - if (state == PCA9554_PIN_LOW) { - val &= ~(mask); + if (s->hw_dir) { + /* Warn and ignore if the guest has configured this pin as output */ + if (!((s->regs[PCA9554_CONFIG] >> pin) & 0x1)) { + qemu_log_mask(LOG_UNIMP, + "%s: pin %d is configured as output, " + "ignoring external set\n", + s->description, pin); + return; + } + /* Drive the external input level */ + pca9554_set_ext_state(s, pin, state != PCA9554_PIN_LOW); } else { - val |= mask; - } - pca9554_write(s, PCA9554_OUTPUT, val); + /* Legacy behavior: force output mode and drive */ + /* First, modify the output register bit */ + val = pca9554_read(s, PCA9554_OUTPUT); + mask = 0x1 << pin; + if (state == PCA9554_PIN_LOW) { + val &= ~(mask); + } else { + val |= mask; + } + pca9554_write(s, PCA9554_OUTPUT, val); - /* Then, clear the config register bit for output mode */ - val = pca9554_read(s, PCA9554_CONFIG); - val &= ~mask; - pca9554_write(s, PCA9554_CONFIG, val); + /* Then, clear the config register bit for output mode */ + val = pca9554_read(s, PCA9554_CONFIG); + val &= ~mask; + pca9554_write(s, PCA9554_CONFIG, val); + } } static const VMStateDescription pca9554_vmstate = { @@ -271,14 +297,6 @@ static void pca9554_initfn(Object *obj) } } -static void pca9554_set_ext_state(PCA9554State *s, int pin, int level) -{ - if (s->ext_state[pin] != level) { - s->ext_state[pin] = level; - pca9554_update_pin_input(s); - } -} - static void pca9554_gpio_in_handler(void *opaque, int pin, int level) { PCA9554State *s = PCA9554(opaque); @@ -303,6 +321,7 @@ static void pca9554_realize(DeviceState *dev, Error **errp) static const Property pca9554_properties[] = { DEFINE_PROP_STRING("description", PCA9554State, description), + DEFINE_PROP_BOOL("hw-dir", PCA9554State, hw_dir, false), }; static void pca9554_class_init(ObjectClass *klass, const void *data) diff --git a/include/hw/gpio/pca9554.h b/include/hw/gpio/pca9554.h index c09108e8b6..ac835371aa 100644 --- a/include/hw/gpio/pca9554.h +++ b/include/hw/gpio/pca9554.h @@ -33,6 +33,7 @@ struct PCA9554State { qemu_irq gpio_out[PCA9554_PIN_COUNT]; uint8_t ext_state[PCA9554_PIN_COUNT]; char *description; /* For debugging purpose only */ + bool hw_dir; /* Honor pin direction */ }; #endif From ed8e011b922c5ae23804d6dccbde1152af3a5381 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:09 +0200 Subject: [PATCH 122/627] hw/gpio: pca9554: reflect push-pull outputs in the input register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pca9554_update_pin_input() derived the pin level from CONFIG | OUTPUT, which treated an output driven high as Hi-Z and let ext_state pull it low. The PCA9554/PCA9536 output stage is push-pull, so a pin configured as an output drives the OUTPUT register level regardless of any external agent. Reflect the output value directly for output pins and keep the pull-up/ext_state behaviour for input pins, matching the PCA9555 GPIO variant. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-17-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9554.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index ed38fe102b..d4746719f9 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -43,43 +43,32 @@ static void pca9554_update_pin_input(PCA9554State *s) int i; uint8_t config = s->regs[PCA9554_CONFIG]; uint8_t output = s->regs[PCA9554_OUTPUT]; - uint8_t internal_state = config | output; for (i = 0; i < pc->pin_count; i++) { uint8_t bit_mask = 1 << i; - uint8_t internal_pin_state = (internal_state >> i) & 0x1; uint8_t old_value = s->regs[PCA9554_INPUT] & bit_mask; uint8_t new_value; - switch (internal_pin_state) { - case PCA9554_PIN_LOW: - s->regs[PCA9554_INPUT] &= ~bit_mask; - break; - case PCA9554_PIN_HIZ: + if (config & bit_mask) { /* - * pullup sets it to a logical 1 unless - * external device drives it low. + * Input: the pin is Hi-Z with a pull-up, so it reads high + * unless an external device drives it low. */ if (s->ext_state[i] == PCA9554_PIN_LOW) { s->regs[PCA9554_INPUT] &= ~bit_mask; } else { - s->regs[PCA9554_INPUT] |= bit_mask; + s->regs[PCA9554_INPUT] |= bit_mask; } - break; - default: - break; + } else { + /* Output: the push-pull stage drives the output register level. */ + s->regs[PCA9554_INPUT] = (s->regs[PCA9554_INPUT] & ~bit_mask) | + (output & bit_mask); } /* drive the per-pin GPIO output only if the pin level changed */ new_value = s->regs[PCA9554_INPUT] & bit_mask; if (new_value != old_value) { - if (new_value) { - /* changed from 0 to 1 */ - qemu_set_irq(s->gpio_out[i], 1); - } else { - /* changed from 1 to 0 */ - qemu_set_irq(s->gpio_out[i], 0); - } + qemu_set_irq(s->gpio_out[i], !!new_value); } } } From a52cf5a1826535f838d30be835613bf16f60fff5 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:10 +0200 Subject: [PATCH 123/627] hw/gpio: pca9554: expose pin%d as a string property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pinN properties are accessed with visit_type_str() (values "low" and "high"), but were registered as type "bool", so introspection advertised a boolean while the accessors require a string. Register them as "str", matching the PCA9555 GPIO variant. Fixes: de0c7d543bca ("misc: Add a pca9554 GPIO device model") Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-18-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/gpio/pca9554.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index d4746719f9..904698cdce 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -280,7 +280,7 @@ static void pca9554_initfn(Object *obj) char *name; name = g_strdup_printf("pin%d", pin); - object_property_add(obj, name, "bool", pca9554_get_pin, pca9554_set_pin, + object_property_add(obj, name, "str", pca9554_get_pin, pca9554_set_pin, NULL, NULL); g_free(name); } From ab707882d83b013521ab15d266ab41dbb6c9efbc Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:11 +0200 Subject: [PATCH 124/627] tests/qtest: add PCA9554 register access tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a qtest for the PCA9554 8-bit I/O port expander exercising the basic register access: power-on reset defaults and read/write of the OUTPUT, CONFIG and POLARITY registers. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-19-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/meson.build | 1 + tests/qtest/pca9554-test.c | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/qtest/pca9554-test.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index e92130bd04..4d81857174 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -319,6 +319,7 @@ qos_test_ss.add( 'tulip-test.c', 'nvme-test.c', 'pca9552-test.c', + 'pca9554-test.c', 'pca9555-test.c', 'pci-test.c', 'pcnet-test.c', diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c new file mode 100644 index 0000000000..a5f213a59c --- /dev/null +++ b/tests/qtest/pca9554-test.c @@ -0,0 +1,41 @@ +/* + * QTest testcase for the PCA9554/PCA9536 I/O port expanders + * + * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com) + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/gpio/pca9554_regs.h" +#include "libqos/i2c.h" +#include "libqos/qgraph.h" + +#define PCA9554_TEST_ADDR 0x20 + +/* Verify power-on reset defaults match the PCA9554 datasheet. */ +static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + /* All pins are inputs, pulled high, with no polarity inversion. */ + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0xFF); +} + +static void pca9554_register_nodes(void) +{ + QOSGraphEdgeOptions opts = { + .extra_device_opts = "address=0x20" + }; + add_qi2c_address(&opts, &(QI2CAddress) { PCA9554_TEST_ADDR }); + + qos_node_create_driver("pca9554", i2c_device_create); + qos_node_consumes("pca9554", "i2c-bus", &opts); + + qos_add_test("reset-defaults", "pca9554", test_reset_defaults, NULL); +} + +libqos_init(pca9554_register_nodes); From e5f73c36dbf0f52e1006d907d5ef283c9c01b52c Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:12 +0200 Subject: [PATCH 125/627] tests/qtest: pca9554: test output-to-input reflection and pull-ups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that a pin configured as output drives its OUTPUT register level onto the pin (push-pull) as reflected by the INPUT register, and that a pin configured as input floats high through its pull-up. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-20-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9554-test.c | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c index a5f213a59c..ce6e90f3f8 100644 --- a/tests/qtest/pca9554-test.c +++ b/tests/qtest/pca9554-test.c @@ -25,6 +25,48 @@ static void test_reset_defaults(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0xFF); } +/* + * A pin configured as output (config=0) drives its OUTPUT register level onto + * the pin (push-pull), which the INPUT register reflects. A pin configured as + * input (config=1) floats high through its pull-up. + */ +static void test_output_drives_input(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + /* Low nibble output, high nibble input (pull-up). */ + i2c_set8(dev, PCA9554_CONFIG, 0xF0); + i2c_set8(dev, PCA9554_OUTPUT, 0xFA); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFA); + + /* All outputs, driven low then high. */ + i2c_set8(dev, PCA9554_CONFIG, 0x00); + i2c_set8(dev, PCA9554_OUTPUT, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00); + + i2c_set8(dev, PCA9554_OUTPUT, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF); +} + +/* + * With all pins configured as inputs the pull-ups make the INPUT register read + * all ones regardless of the OUTPUT register; switching a pin to output with + * output=0 drives it low. + */ +static void test_input_pullup(void *obj, void *data, QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF); + + i2c_set8(dev, PCA9554_OUTPUT, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF); + + i2c_set8(dev, PCA9554_CONFIG, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00); +} + static void pca9554_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -36,6 +78,9 @@ static void pca9554_register_nodes(void) qos_node_consumes("pca9554", "i2c-bus", &opts); qos_add_test("reset-defaults", "pca9554", test_reset_defaults, NULL); + qos_add_test("output-drives-input", "pca9554", test_output_drives_input, + NULL); + qos_add_test("input-pullup", "pca9554", test_input_pullup, NULL); } libqos_init(pca9554_register_nodes); From e1338eb6da3041be64c096ba60e8680dbcd51a68 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:13 +0200 Subject: [PATCH 126/627] tests/qtest: pca9554: test polarity inversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verify that the polarity register inverts the value read back from the INPUT register, both on pulled-up inputs and on output-driven pins, while leaving the OUTPUT register itself unchanged. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-21-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9554-test.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c index ce6e90f3f8..74237df611 100644 --- a/tests/qtest/pca9554-test.c +++ b/tests/qtest/pca9554-test.c @@ -67,6 +67,41 @@ static void test_input_pullup(void *obj, void *data, QGuestAllocator *alloc) g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00); } +/* + * Polarity inversion: reading INPUT returns the XOR of the pin levels and the + * polarity register. + */ +static void test_polarity_inversion(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xFF); + + i2c_set8(dev, PCA9554_POLARITY, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00); + + i2c_set8(dev, PCA9554_POLARITY, 0x0F); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xF0); +} + +/* Polarity inversion combined with output-driven pins. */ +static void test_polarity_with_output(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9554_CONFIG, 0x00); + i2c_set8(dev, PCA9554_OUTPUT, 0xA5); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0xA5); + + i2c_set8(dev, PCA9554_POLARITY, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x5A); + + /* Inversion only affects the INPUT read, not the OUTPUT register. */ + g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0xA5); +} + static void pca9554_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -81,6 +116,10 @@ static void pca9554_register_nodes(void) qos_add_test("output-drives-input", "pca9554", test_output_drives_input, NULL); qos_add_test("input-pullup", "pca9554", test_input_pullup, NULL); + qos_add_test("polarity-inversion", "pca9554", test_polarity_inversion, + NULL); + qos_add_test("polarity-with-output", "pca9554", test_polarity_with_output, + NULL); } libqos_init(pca9554_register_nodes); From f9bf753b58c83d689f535f6b1ab217f4a46aa35f Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:14 +0200 Subject: [PATCH 127/627] tests/qtest: pca9554: test absence of command auto-increment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9554 selects one of its four registers with a single command byte and does not auto-increment the register pointer, so a multi-byte I2C transfer keeps addressing the register chosen by the command byte instead of walking through the register map. Add a test covering this: a two-byte read returns the addressed register twice, and a two-byte write updates only that register, leaving its neighbour untouched. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-22-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9554-test.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c index 74237df611..0da1f3304b 100644 --- a/tests/qtest/pca9554-test.c +++ b/tests/qtest/pca9554-test.c @@ -102,6 +102,33 @@ static void test_polarity_with_output(void *obj, void *data, g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0xA5); } +/* + * The PCA9554 has no auto-increment: the command pointer never advances, so + * multi-byte reads and writes all target the addressed register. + */ +static void test_no_autoincrement(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + uint8_t buf[2]; + + /* Distinct values in adjacent registers. */ + i2c_set8(dev, PCA9554_OUTPUT, 0xAA); + i2c_set8(dev, PCA9554_POLARITY, 0x33); + + /* Two reads from OUTPUT return OUTPUT twice, not OUTPUT then POLARITY. */ + i2c_read_block(dev, PCA9554_OUTPUT, buf, 2); + g_assert_cmphex(buf[0], ==, 0xAA); + g_assert_cmphex(buf[1], ==, 0xAA); + + /* The second written byte overwrites OUTPUT; POLARITY is untouched. */ + buf[0] = 0x12; + buf[1] = 0x34; + i2c_write_block(dev, PCA9554_OUTPUT, buf, 2); + g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0x34); + g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x33); +} + static void pca9554_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -120,6 +147,7 @@ static void pca9554_register_nodes(void) NULL); qos_add_test("polarity-with-output", "pca9554", test_polarity_with_output, NULL); + qos_add_test("no-autoincrement", "pca9554", test_no_autoincrement, NULL); } libqos_init(pca9554_register_nodes); From b3fa8825086dcf217ea34dd1073cfd2fc0a790c2 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:15 +0200 Subject: [PATCH 128/627] tests/qtest: pca9554: test the PCA9536 4-bit variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCA9536 shares the PCA9554 register map and code path but exposes only four pins. Add a pca9536 node and check its reset defaults and output-to-input reflection are masked to the low nibble. Signed-off-by: Emmanuel Blot Reviewed-by: Glenn Miles Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-23-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- tests/qtest/pca9554-test.c | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/qtest/pca9554-test.c b/tests/qtest/pca9554-test.c index 0da1f3304b..5366e71984 100644 --- a/tests/qtest/pca9554-test.c +++ b/tests/qtest/pca9554-test.c @@ -129,6 +129,66 @@ static void test_no_autoincrement(void *obj, void *data, g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x33); } +/* + * The PCA9536 shares the PCA9554 register map but only has four pins, so its + * reset defaults and pin logic are masked to the low nibble. + */ +static void test_pca9536_reset_defaults(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0F); + g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0x0F); + g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0x0F); +} + +/* Only the four low pins are driven; the upper nibble stays low. */ +static void test_pca9536_output_drives_input(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + i2c_set8(dev, PCA9554_CONFIG, 0x00); + + i2c_set8(dev, PCA9554_OUTPUT, 0x0A); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0A); + + i2c_set8(dev, PCA9554_OUTPUT, 0x00); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x00); +} + +/* + * The four upper bits address pins that do not exist on the PCA9536, so writes + * to the register map discard them: the writable registers read back with bits + * [7:4] cleared, and driving them onto the pins never surfaces in INPUT. + */ +static void test_pca9536_ignores_upper_bits(void *obj, void *data, + QGuestAllocator *alloc) +{ + QI2CDevice *dev = (QI2CDevice *)obj; + + /* Bits [7:4] are dropped on write; bits [3:0] survive. */ + i2c_set8(dev, PCA9554_OUTPUT, 0xFA); + g_assert_cmphex(i2c_get8(dev, PCA9554_OUTPUT), ==, 0x0A); + + i2c_set8(dev, PCA9554_POLARITY, 0xF5); + g_assert_cmphex(i2c_get8(dev, PCA9554_POLARITY), ==, 0x05); + + i2c_set8(dev, PCA9554_CONFIG, 0xF3); + g_assert_cmphex(i2c_get8(dev, PCA9554_CONFIG), ==, 0x03); + + /* + * With all four pins as outputs, driving 0xFF only affects the low + * nibble. + */ + i2c_set8(dev, PCA9554_POLARITY, 0x00); + i2c_set8(dev, PCA9554_CONFIG, 0x00); + i2c_set8(dev, PCA9554_OUTPUT, 0xFF); + g_assert_cmphex(i2c_get8(dev, PCA9554_INPUT), ==, 0x0F); +} + static void pca9554_register_nodes(void) { QOSGraphEdgeOptions opts = { @@ -148,6 +208,16 @@ static void pca9554_register_nodes(void) qos_add_test("polarity-with-output", "pca9554", test_polarity_with_output, NULL); qos_add_test("no-autoincrement", "pca9554", test_no_autoincrement, NULL); + + qos_node_create_driver("pca9536", i2c_device_create); + qos_node_consumes("pca9536", "i2c-bus", &opts); + + qos_add_test("reset-defaults", "pca9536", test_pca9536_reset_defaults, + NULL); + qos_add_test("output-drives-input", "pca9536", + test_pca9536_output_drives_input, NULL); + qos_add_test("ignores-upper-bits", "pca9536", + test_pca9536_ignores_upper_bits, NULL); } libqos_init(pca9554_register_nodes); From 49ec283f15868eae0094f94844db9c5a171c7592 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:16 +0200 Subject: [PATCH 129/627] hw/arm: catalina: model PCA9555 IO expanders with their own type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Catalina BMC device tree describes several IO expanders as nxp,pca9555. These were previously instantiated as PCA9552 devices as no PCA9555 model existed. Now that a dedicated PCA9555 device is available, use it so the emulated IO expanders match the hardware. Signed-off-by: Emmanuel Blot Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-24-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600_catalina.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/arm/aspeed_ast2600_catalina.c b/hw/arm/aspeed_ast2600_catalina.c index 65495a524e..f3b22e9aa9 100644 --- a/hw/arm/aspeed_ast2600_catalina.c +++ b/hw/arm/aspeed_ast2600_catalina.c @@ -533,7 +533,7 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) TYPE_PCA9554, 0x27); /* io_expander6 - pca9555@25 */ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 6), - TYPE_PCA9552, 0x25); + TYPE_PCA9555, 0x25); /* eeprom@51 */ at24c_eeprom_init_rom(pca954x_i2c_get_bus(i2c_mux, 6), 0x51, 8 * KiB, osfp_eeprom, osfp_eeprom_len); @@ -547,11 +547,11 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) /* &i2c2 */ /* io_expander0 - pca9555@20 */ - i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x20); + i2c_slave_create_simple(i2c[2], TYPE_PCA9555, 0x20); /* io_expander0 - pca9555@21 */ - i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x21); + i2c_slave_create_simple(i2c[2], TYPE_PCA9555, 0x21); /* io_expander0 - pca9555@27 */ - i2c_slave_create_simple(i2c[2], TYPE_PCA9552, 0x27); + i2c_slave_create_simple(i2c[2], TYPE_PCA9555, 0x27); /* eeprom@50 */ at24c_eeprom_init(i2c[2], 0x50, 8 * KiB); /* eeprom@51 */ @@ -572,13 +572,13 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) /* &i2c6 */ /* io_expander3 - pca9555@21 */ - i2c_slave_create_simple(i2c[6], TYPE_PCA9552, 0x21); + i2c_slave_create_simple(i2c[6], TYPE_PCA9555, 0x21); /* rtc@6f - nct3018y */ i2c_slave_create_simple(i2c[6], TYPE_DS1338, 0x6f); /* &i2c9 */ /* io_expander4 - pca9555@4f */ - i2c_slave_create_simple(i2c[9], TYPE_PCA9552, 0x4f); + i2c_slave_create_simple(i2c[9], TYPE_PCA9555, 0x4f); /* temperature-sensor@4b - tpm75 */ i2c_slave_create_simple(i2c[9], TYPE_TMP75, 0x4b); /* eeprom@50 */ @@ -615,17 +615,17 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) /* &i2c14 */ /* io_expander9 - pca9555@10 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x10); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x10); /* io_expander10 - pca9555@11 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x11); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x11); /* io_expander11 - pca9555@12 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x12); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x12); /* io_expander12 - pca9555@13 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x13); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x13); /* io_expander13 - pca9555@14 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x14); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x14); /* io_expander14 - pca9555@15 */ - i2c_slave_create_simple(i2c[14], TYPE_PCA9552, 0x15); + i2c_slave_create_simple(i2c[14], TYPE_PCA9555, 0x15); /* &i2c15 */ /* temperature-sensor@1f - tmp421 */ From 508678167c0a6bfb325014d5bd06f946a3c0a7b4 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Thu, 9 Jul 2026 17:23:17 +0200 Subject: [PATCH 130/627] hw/arm: catalina: add NIC and FIO temperature sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model the temperature sensors described by the Catalina device tree that have existing QEMU device models but were not yet instantiated: the four IOB NIC TMP421 sensors behind the i2c0 PCA9546 muxes at 0x71 and 0x75, and the FIO remote TMP75 sensor at 0x4f on the i2c1 mux. Signed-off-by: Emmanuel Blot Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260709-catalina-upgrade-v1-25-82a63fead90c@free.fr Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600_catalina.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/hw/arm/aspeed_ast2600_catalina.c b/hw/arm/aspeed_ast2600_catalina.c index f3b22e9aa9..f714c9d1b3 100644 --- a/hw/arm/aspeed_ast2600_catalina.c +++ b/hw/arm/aspeed_ast2600_catalina.c @@ -472,7 +472,16 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) /* &i2c0 */ /* i2c-mux@71 (PCA9546) on i2c0 */ - i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x71); + i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x71); + + /* i2c0mux0ch0 */ + /* IOB0 NIC0 temperature-sensor@1f - tmp421 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), + TYPE_TMP421, 0x1f); + /* i2c0mux0ch2 */ + /* IOB0 NIC1 temperature-sensor@1f - tmp421 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), + TYPE_TMP421, 0x1f); /* i2c-mux@72 (PCA9546) on i2c0 */ i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x72); @@ -489,7 +498,16 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x73); /* i2c-mux@75 (PCA9546) on i2c0 */ - i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x75); + i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x75); + + /* i2c0mux3ch0 */ + /* IOB1 NIC0 temperature-sensor@1f - tmp421 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), + TYPE_TMP421, 0x1f); + /* i2c0mux3ch2 */ + /* IOB1 NIC1 temperature-sensor@1f - tmp421 */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 2), + TYPE_TMP421, 0x1f); /* i2c-mux@76 (PCA9546) on i2c0 */ i2c_mux = i2c_slave_create_simple(i2c[0], TYPE_PCA9546, 0x76); @@ -544,6 +562,8 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) fio_eeprom, fio_eeprom_len); /* temperature-sensor@4b - tmp75 */ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 7), TYPE_TMP75, 0x4b); + /* temperature-sensor@4f - tmp75 (FIO remote) */ + i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 7), TYPE_TMP75, 0x4f); /* &i2c2 */ /* io_expander0 - pca9555@20 */ @@ -564,11 +584,7 @@ static void catalina_bmc_i2c_init(AspeedMachineState *bmc) /* eeprom@52 */ at24c_eeprom_init_rom(pca954x_i2c_get_bus(i2c_mux, 6), 0x52, 8 * KiB, hdd_eeprom, hdd_eeprom_len); - /* i2c5mux0ch7 */ - /* ina230@40 - no model */ - /* ina230@41 - no model */ - /* ina230@44 - no model */ - /* ina230@45 - no model */ + /* i2c5mux0ch7 - empty */ /* &i2c6 */ /* io_expander3 - pca9555@21 */ From a5f7d655854a4da8767b2a17be698fb6cd68d709 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:19:57 +0000 Subject: [PATCH 131/627] hw/i2c/aspeed_i2c: Support the AST2700 master buffer mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2700 I2C controller can move master DMA payloads through its internal SRAM pool rather than DRAM. The Linux driver calls this "buffer mode" and selects it by default. Buffer mode reuses the master DMA command bits (TX/RX_DMA_EN) and the DMA length registers, so the only difference from a DRAM transfer is where the data comes from and goes to: an offset into the pool programmed in I2CM_DMA_TX/RX_ADDR. The I2CC_VERSION_CTRL FUNC_CFG_DMA_EN bit selects between the two. Implement I2CC_VERSION_CTRL and, when FUNC_CFG_DMA_EN is clear, move the payload through the pool buffer instead of DRAM. I2CC_VERSION_CTRL resets to all ones, so guests that never program it keep targeting DRAM and behave as before. The register sits above the register window of the earlier SoCs, which are therefore unaffected. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/i2c/aspeed_i2c.c | 79 +++++++++++++++++++++++++++++++++++++ include/hw/i2c/aspeed_i2c.h | 2 + 2 files changed, 81 insertions(+) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 27afcaecee..68bdcd0e25 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -159,6 +159,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, case A_I2CS_INTR_CTRL: case A_I2CS_DMA_LEN_STS: case A_I2CS_INTR_STS: + case A_I2CC_VERSION_CTRL: value = bus->regs[offset / sizeof(*bus->regs)]; break; case A_I2CC_DMA_ADDR: @@ -295,6 +296,65 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) return 0; } +/* + * In AST2700 buffer mode the master DMA command bits (TX/RX_DMA_EN) and the + * DMA length registers are reused, but data is moved through the controller + * internal SRAM pool at the offset programmed in I2CM_DMA_TX/RX_ADDR instead + * of DRAM. FUNC_CFG_DMA_EN selects between the two (set = DRAM). + */ +static bool aspeed_i2c_bus_dma_to_pool(AspeedI2CBus *bus) +{ + return aspeed_i2c_is_new_mode(bus->controller) && + !ARRAY_FIELD_EX32(bus->regs, I2CC_VERSION_CTRL, FUNC_CFG_DMA_EN); +} + +static int aspeed_i2c_bus_send_dma_pool(AspeedI2CBus *bus) +{ + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t offset = bus->regs[R_I2CM_DMA_TX_ADDR]; + uint8_t *pool_base = aic->bus_pool_base(bus); + int ret = -1; + int i; + + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); + for (i = 0; bus->regs[reg_dma_len] && + offset + i < ASPEED_I2C_BUS_POOL_SIZE; i++) { + trace_aspeed_i2c_bus_send("BUFF", i + 1, bus->regs[reg_dma_len], + pool_base[offset + i]); + ret = i2c_send(bus->bus, pool_base[offset + i]); + bus->regs[reg_dma_len]--; + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, i + 1); + if (ret) { + break; + } + } + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); + return ret; +} + +static void aspeed_i2c_bus_recv_dma_pool(AspeedI2CBus *bus) +{ + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); + uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); + uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); + uint32_t offset = bus->regs[R_I2CM_DMA_RX_ADDR]; + uint8_t *pool_base = aic->bus_pool_base(bus); + int i; + + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); + for (i = 0; bus->regs[reg_dma_len] && + offset + i < ASPEED_I2C_BUS_POOL_SIZE; i++) { + pool_base[offset + i] = i2c_recv(bus->bus); + trace_aspeed_i2c_bus_recv("BUFF", i + 1, bus->regs[reg_dma_len], + pool_base[offset + i]); + bus->regs[reg_dma_len]--; + ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, i + 1); + } + SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); +} + static int aspeed_i2c_bus_send(AspeedI2CBus *bus) { AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); @@ -320,6 +380,10 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus) } SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { + /* In buffer mode the DMA moves data through the pool, not DRAM */ + if (aspeed_i2c_bus_dma_to_pool(bus)) { + return aspeed_i2c_bus_send_dma_pool(bus); + } /* In new mode, clear how many bytes we TXed */ if (aspeed_i2c_is_new_mode(bus->controller)) { ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); @@ -385,6 +449,11 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { + /* In buffer mode the DMA moves data through the pool, not DRAM */ + if (aspeed_i2c_bus_dma_to_pool(bus)) { + aspeed_i2c_bus_recv_dma_pool(bus); + return; + } /* In new mode, clear how many bytes we RXed */ if (aspeed_i2c_is_new_mode(bus->controller)) { ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); @@ -854,6 +923,9 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, I2CS_DMA_RX_ADDR_HI, ADDR_HI); break; + case A_I2CC_VERSION_CTRL: + bus->regs[R_I2CC_VERSION_CTRL] = value; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -1497,6 +1569,13 @@ static void aspeed_i2c_bus_reset_hold(Object *obj, ResetType type) memset(s->regs, 0, sizeof(s->regs)); s->pending_intr_sts = 0; i2c_end_transfer(s->bus); + /* + * I2CC_VERSION_CTRL resets to all-ones. FUNC_CFG_DMA_EN is therefore set, + * so master DMA targets DRAM unless the guest clears it to select buffer + * mode. Guests unaware of buffer mode never touch this register and keep + * doing DRAM DMA. + */ + s->regs[R_I2CC_VERSION_CTRL] = 0xffffffff; } static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index 156998e7c1..05937a7a0b 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -231,6 +231,8 @@ REG32(I2CS_DMA_TX_ADDR_HI, 0x68) FIELD(I2CS_DMA_TX_ADDR_HI, ADDR_HI, 0, 7) REG32(I2CS_DMA_RX_ADDR_HI, 0x6c) FIELD(I2CS_DMA_RX_ADDR_HI, ADDR_HI, 0, 7) +REG32(I2CC_VERSION_CTRL, 0x94) + FIELD(I2CC_VERSION_CTRL, FUNC_CFG_DMA_EN, 2, 1) struct AspeedI2CState; From 809720039fb4d04c11eb3ee7fe87b9e0f1a5f5fc Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:19:59 +0000 Subject: [PATCH 132/627] tests/functional/aarch64/test_aspeed_ast2700a2: Update ASPEED SDK v11.03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- .../aarch64/test_aspeed_ast2700a2.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/functional/aarch64/test_aspeed_ast2700a2.py b/tests/functional/aarch64/test_aspeed_ast2700a2.py index 5f9073c897..01c7c4fdbe 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700a2.py +++ b/tests/functional/aarch64/test_aspeed_ast2700a2.py @@ -85,13 +85,13 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - ASSET_SDK_V1101_AST2700A2 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2700-default-image.tar.gz', - 'ce89dcd995cf284d41a6a4bd17a1b97d59939f0277bfe54fdaaf30e741ce7487') + ASSET_SDK_V1103_AST2700A2 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2700-default-image.tar.gz', + 'b91450d53da234591060cfb926fa30f7534ce20eaab766cb0f80ec332f8f0adb') - ASSET_SDK_V1101_AST2700A2_DCSCM = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2700-dcscm-image.tar.gz', - 'b92ece9ca733dfd7a20193a12582f743b77f1898116b6d6f1abe57ac8db01c56') + ASSET_SDK_V1103_AST2700A2_DCSCM = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2700-dcscm-image.tar.gz', + '7afd8323fc95097c14872b90d68c5cae5d078530c704591b192b74bd892c1dbf') def do_ast2700_i2c_test(self, bus_id): bus_str = str(bus_id) @@ -135,7 +135,8 @@ class AST2x00MachineSDK(QemuSystemTest): }, { 'addr': '0x430000000', - 'file': self.scratch_file(name, 'bl31.bin') + 'file': self.scratch_file(name, 'trusted-firmware-a', + 'bl31.bin') }, { 'addr': '0x430080000', @@ -162,11 +163,11 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc'), bus_id) - def test_aarch64_ast2700a2_evb_sdk_v11_01(self): + def test_aarch64_ast2700a2_evb_sdk_v11_03(self): self.set_machine('ast2700a2-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A2) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A2) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3') @@ -176,22 +177,22 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_ast2700_pcie_test() self.do_ast2700_usb_ehci_test() - def test_aarch64_ast2700a2_evb_sdk_vbootrom_v11_01(self): + def test_aarch64_ast2700a2_evb_sdk_vbootrom_v11_03(self): self.set_machine('ast2700a2-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A2) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A2) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') self.start_ast2700_test_vbootrom('ast2700-default-image', 1) self.verify_vbootrom_firmware_flow() self.verify_openbmc_boot_start() - def test_aarch64_ast2700a2_evb_ioexp_v11_01(self): + def test_aarch64_ast2700a2_evb_ioexp_v11_03(self): self.set_machine('ast2700a2-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A2_DCSCM) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A2_DCSCM) self.vm.set_machine('ast2700a2-evb,fmc-model=w25q512jv') self.vm.add_args('-device', 'tmp105,bus=ioexp0.0,address=0x4d,id=tmp-test-16') From 169d499d6554f6261776366f2e77444a14265764 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:00 +0000 Subject: [PATCH 133/627] tests/functional/aarch64/test_aspeed_ast2700a1: Update ASPEED SDK v11.03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- .../aarch64/test_aspeed_ast2700a1.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/functional/aarch64/test_aspeed_ast2700a1.py b/tests/functional/aarch64/test_aspeed_ast2700a1.py index adbbef5cf1..2113c78db2 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700a1.py +++ b/tests/functional/aarch64/test_aspeed_ast2700a1.py @@ -85,13 +85,13 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - ASSET_SDK_V1101_AST2700A1 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2700-a1-image.tar.gz', - '859808828531a51931aad3b4e70b28143eebb3cde1838ba7d8e7a2b844c8a1ab') + ASSET_SDK_V1103_AST2700A1 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2700-a1-image.tar.gz', + '540961dc380709d852e957c5817cd7ee0dbb0a66f3aa17413eac7b67518afbfe') - ASSET_SDK_V1101_AST2700A1_DCSCM = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2700-a1-dcscm-image.tar.gz', - '4654eabad75da3fd33635cd6d29b7635181daefee7294b68feb124b9d4c24116') + ASSET_SDK_V1103_AST2700A1_DCSCM = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2700-a1-dcscm-image.tar.gz', + '5f7c139330fcefa6025bc7565a20fd5ea42cacebf810d56dc9a76b07cf69b3e1') def do_ast2700_i2c_test(self, bus_id): bus_str = str(bus_id) @@ -132,7 +132,8 @@ class AST2x00MachineSDK(QemuSystemTest): }, { 'addr': '0x430000000', - 'file': self.scratch_file(name, 'bl31.bin') + 'file': self.scratch_file(name, 'trusted-firmware-a', + 'bl31.bin') }, { 'addr': '0x430080000', @@ -159,11 +160,11 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc'), bus_id) - def test_aarch64_ast2700a1_evb_sdk_v11_01(self): + def test_aarch64_ast2700a1_evb_sdk_v11_03(self): self.set_machine('ast2700a1-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A1) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A1) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') self.vm.add_args('-device', 'usb-kbd,bus=usb-bus.3') @@ -173,22 +174,22 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_ast2700_pcie_test() self.do_ast2700_usb_ehci_test() - def test_aarch64_ast2700a1_evb_sdk_vbootrom_v11_01(self): + def test_aarch64_ast2700a1_evb_sdk_vbootrom_v11_03(self): self.set_machine('ast2700a1-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A1) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A1) self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') self.vm.add_args('-netdev', 'user,id=net1') self.start_ast2700_test_vbootrom('ast2700-a1-image', 1) self.verify_vbootrom_firmware_flow() self.verify_openbmc_boot_start() - def test_aarch64_ast2700a1_evb_ioexp_v11_01(self): + def test_aarch64_ast2700a1_evb_ioexp_v11_03(self): self.set_machine('ast2700a1-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700A1_DCSCM) + self.archive_extract(self.ASSET_SDK_V1103_AST2700A1_DCSCM) self.vm.set_machine('ast2700a1-evb,fmc-model=w25q512jv') self.vm.add_args('-device', 'tmp105,bus=ioexp0.0,address=0x4d,id=tmp-test-16') From ea2387e2115092dc1acfb69c8f979c2eb0849801 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:01 +0000 Subject: [PATCH 134/627] tests/functional/aarch64/test_aspeed_ast2700fc: Update ASPEED SDK v11.03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- .../aarch64/test_aspeed_ast2700fc.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/functional/aarch64/test_aspeed_ast2700fc.py b/tests/functional/aarch64/test_aspeed_ast2700fc.py index 86270e6111..704477d7c5 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700fc.py +++ b/tests/functional/aarch64/test_aspeed_ast2700fc.py @@ -66,9 +66,9 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.add_args('-device', f'loader,file={file},cpu-num={cpu_num}') - ASSET_SDK_V1101_AST2700 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2700-default-image.tar.gz', - 'ce89dcd995cf284d41a6a4bd17a1b97d59939f0277bfe54fdaaf30e741ce7487') + ASSET_SDK_V1103_AST2700 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2700-default-image.tar.gz', + 'b91450d53da234591060cfb926fa30f7534ce20eaab766cb0f80ec332f8f0adb') def do_ast2700_i2c_test(self): exec_command_and_wait_for_pattern(self, @@ -101,7 +101,7 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, '\012', 'ssp_tsp:~$') exec_command_and_wait_for_pattern(self, 'version', - 'Zephyr version 3.7.1') + 'Zephyr version 3.7.2') exec_command_and_wait_for_pattern(self, 'md 72c02000 1', '[72c02000] 06020103') @@ -112,7 +112,7 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, '\012', 'tsp:~$') exec_command_and_wait_for_pattern(self, 'version', - 'Zephyr version 3.7.1') + 'Zephyr version 3.7.2') exec_command_and_wait_for_pattern(self, 'md 72c02000 1', '[72c02000] 06020103') @@ -125,7 +125,8 @@ class AST2x00MachineSDK(QemuSystemTest): }, { 'addr': '0x430000000', - 'file': self.scratch_file(name, 'bl31.bin') + 'file': self.scratch_file(name, 'trusted-firmware-a', + 'bl31.bin') }, { 'addr': '0x430080000', @@ -153,11 +154,11 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) - def test_aarch64_ast2700fc_sdk_v11_01(self): + def test_aarch64_ast2700fc_sdk_v11_03(self): self.set_machine('ast2700fc') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2700) + self.archive_extract(self.ASSET_SDK_V1103_AST2700) self.start_ast2700fc_test('ast2700-default-image') self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test() @@ -165,10 +166,10 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_ast2700fc_ssp_test() self.do_ast2700fc_tsp_test() - def test_aarch64_ast2700fc_sdk_vbootrom_v11_01(self): + def test_aarch64_ast2700fc_sdk_vbootrom_v11_03(self): self.set_machine('ast2700fc') - self.archive_extract(self.ASSET_SDK_V1101_AST2700) + self.archive_extract(self.ASSET_SDK_V1103_AST2700) self.start_ast2700fc_test_vbootrom('ast2700-default-image') self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700fc_ssp_test() From 769661a1ac97e8abc11c041eba2de6d317543cc1 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:02 +0000 Subject: [PATCH 135/627] tests/functional/arm/test_aspeed_ast2600_sdk: Update ASPEED SDK v11.03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/arm/test_aspeed_ast2600_sdk.py | 8 ++++---- tests/functional/arm/test_aspeed_ast2600_sdk_515.py | 8 ++++---- tests/functional/arm/test_aspeed_ast2600_sdk_otp.py | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/functional/arm/test_aspeed_ast2600_sdk.py b/tests/functional/arm/test_aspeed_ast2600_sdk.py index cabbe230c4..4fc594dfd5 100755 --- a/tests/functional/arm/test_aspeed_ast2600_sdk.py +++ b/tests/functional/arm/test_aspeed_ast2600_sdk.py @@ -14,9 +14,9 @@ from qemu_test import exec_command_and_wait_for_pattern class AST2600Machine(AspeedTest): - ASSET_SDK_V1101_AST2600 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2600-default-image.tar.gz', - '3c5b4d4ccf27b0d208a073f98426db54cd751b96143180cd15df1a83978f832c') + ASSET_SDK_V1103_AST2600 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2600-default-image.tar.gz', + '47e3656a14bf7a4de28d3dfbf48bc2325443bc42d270f3bc82646f92f6dea165') def do_ast2600_pcie_test(self): exec_command_and_wait_for_pattern(self, @@ -49,7 +49,7 @@ class AST2600Machine(AspeedTest): self.set_machine('ast2600-evb') self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V1101_AST2600) + self.archive_extract(self.ASSET_SDK_V1103_AST2600) self.vm.add_args('-device', 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test') diff --git a/tests/functional/arm/test_aspeed_ast2600_sdk_515.py b/tests/functional/arm/test_aspeed_ast2600_sdk_515.py index a8e7faff48..f5b14de083 100755 --- a/tests/functional/arm/test_aspeed_ast2600_sdk_515.py +++ b/tests/functional/arm/test_aspeed_ast2600_sdk_515.py @@ -10,14 +10,14 @@ from aspeed import AspeedTest class AST2600Machine(AspeedTest): - ASSET_SDK_V1101_AST2600_515 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2600-default-515-image.tar.gz', - 'f3ccf1c08db71cf891637fc73131b80b2c0c0e005c06d5dcae0cf74fc458b43c') + ASSET_SDK_V1103_AST2600_515 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2600-default-515-image.tar.gz', + 'c79d0197106f146476e82bb878e5438f6569bd30f3b53fbb520b59bc54f6b7dc') def test_arm_ast2600_evb_sdk_515(self): self.set_machine('ast2600-evb') - self.archive_extract(self.ASSET_SDK_V1101_AST2600_515) + self.archive_extract(self.ASSET_SDK_V1103_AST2600_515) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2600-default-515-image", "image-bmc")) diff --git a/tests/functional/arm/test_aspeed_ast2600_sdk_otp.py b/tests/functional/arm/test_aspeed_ast2600_sdk_otp.py index f24dea1e8f..5813c59bd6 100755 --- a/tests/functional/arm/test_aspeed_ast2600_sdk_otp.py +++ b/tests/functional/arm/test_aspeed_ast2600_sdk_otp.py @@ -12,15 +12,15 @@ from qemu_test import exec_command_and_wait_for_pattern class AST2600Machine(AspeedTest): - ASSET_SDK_V1101_AST2600 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2600-default-image.tar.gz', - '3c5b4d4ccf27b0d208a073f98426db54cd751b96143180cd15df1a83978f832c') + ASSET_SDK_V1103_AST2600 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2600-default-image.tar.gz', + '47e3656a14bf7a4de28d3dfbf48bc2325443bc42d270f3bc82646f92f6dea165') def test_arm_ast2600_otp_blockdev_device(self): self.vm.set_machine("ast2600-evb") self.require_netdev('user') - image_path = self.archive_extract(self.ASSET_SDK_V1101_AST2600) + image_path = self.archive_extract(self.ASSET_SDK_V1103_AST2600) otp_img = self.generate_otpmem_image() self.vm.set_console() From 41bb72aed926a149a24c09e0f2b6228eee186a56 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:03 +0000 Subject: [PATCH 136/627] tests/functional/arm/test_aspeed_ast2500_sdk: Update ASPEED SDK v11.03 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/arm/test_aspeed_ast2500_sdk.py | 8 ++++---- tests/functional/arm/test_aspeed_ast2500_sdk_515.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/functional/arm/test_aspeed_ast2500_sdk.py b/tests/functional/arm/test_aspeed_ast2500_sdk.py index 6ab498b3ff..95df32b84f 100755 --- a/tests/functional/arm/test_aspeed_ast2500_sdk.py +++ b/tests/functional/arm/test_aspeed_ast2500_sdk.py @@ -10,14 +10,14 @@ from aspeed import AspeedTest class AST2500Machine(AspeedTest): - ASSET_SDK_V1101_AST2500 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2500-default-obmc.tar.gz', - '3faa1188198da2216837be4b53861c483a58c3ad63784089720bf8421e157da1') + ASSET_SDK_V1103_AST2500 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2500-default-obmc.tar.gz', + '8e20cafddca04d73b799918d6f35b08c83c9f024e223a317b0ad71b97b84842f') def test_arm_ast2500_evb_sdk(self): self.set_machine('ast2500-evb') - self.archive_extract(self.ASSET_SDK_V1101_AST2500) + self.archive_extract(self.ASSET_SDK_V1103_AST2500) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2500-default", "image-bmc")) diff --git a/tests/functional/arm/test_aspeed_ast2500_sdk_515.py b/tests/functional/arm/test_aspeed_ast2500_sdk_515.py index 8d39dc65da..516e96e52d 100755 --- a/tests/functional/arm/test_aspeed_ast2500_sdk_515.py +++ b/tests/functional/arm/test_aspeed_ast2500_sdk_515.py @@ -10,14 +10,14 @@ from aspeed import AspeedTest class AST2500Machine(AspeedTest): - ASSET_SDK_V1101_AST2500_515 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.01/ast2500-default-515-obmc.tar.gz', - 'b848ff620d2e9c83e2fb4736b4d1c39b82fdb041058cd42be42c3b177bf38eb9') + ASSET_SDK_V1103_AST2500_515 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v11.03/ast2500-default-515-obmc.tar.gz', + 'f17d3b0a5157bcf73c21c4981f838ea0b76c6406cc4a6409267d57d61758ebb6') def test_arm_ast2500_evb_sdk_515(self): self.set_machine('ast2500-evb') - self.archive_extract(self.ASSET_SDK_V1101_AST2500_515) + self.archive_extract(self.ASSET_SDK_V1103_AST2500_515) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2500-default-515", "image-bmc")) From 274a9cfdeb6edaf3aec4aacae9f7187230042f00 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:05 +0000 Subject: [PATCH 137/627] tests/functional/arm/test_aspeed_ast1030: Update ASPEED Zephyr SDK v03.08 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/arm/test_aspeed_ast1030.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/functional/arm/test_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py index 03fee55b5f..83a96ec322 100755 --- a/tests/functional/arm/test_aspeed_ast1030.py +++ b/tests/functional/arm/test_aspeed_ast1030.py @@ -12,17 +12,17 @@ from qemu_test import Asset, exec_command_and_wait_for_pattern class AST1030Machine(AspeedTest): - ASSET_ZEPHYR_3_06 = Asset( + ASSET_ZEPHYR_3_08 = Asset( ('https://github.com/AspeedTech-BMC' - '/zephyr/releases/download/v00.03.06/ast1030-evb-demo.zip'), - '056f37fcd9f165308cedca3a08f2bed37ed40c0a1402c4fa515613b80a369f38') + '/zephyr/releases/download/v00.03.08/ast1030-evb-demo.zip'), + '9eac3691bc7bce1b912bbe2ae4e36608a6532ff8d607f4d1e44b88407a48d4e5') - def test_arm_ast1030_zephyros_3_06(self): + def test_arm_ast1030_zephyros_3_08(self): self.set_machine('ast1030-evb') kernel_name = "ast1030-evb-demo/zephyr.elf" kernel_file = self.archive_extract( - self.ASSET_ZEPHYR_3_06, member=kernel_name) + self.ASSET_ZEPHYR_3_08, member=kernel_name) self.vm.set_console() self.vm.add_args('-kernel', kernel_file, '-nographic') @@ -72,7 +72,7 @@ class AST1030Machine(AspeedTest): self.vm.set_machine("ast1030-evb") kernel_name = "ast1030-evb-demo/zephyr.elf" - kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_06, + kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_08, member=kernel_name) otp_img = self.generate_otpmem_image() From 007ae802b45dca42616bb2be3d076d0753f99179 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 4 Aug 2026 08:20:06 +0000 Subject: [PATCH 138/627] tests/functional/arm/test_aspeed_ast1060: Update ASPEED ZEPHYR PROJECT v03.07 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260804081955.1563537-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/arm/test_aspeed_ast1060.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/functional/arm/test_aspeed_ast1060.py b/tests/functional/arm/test_aspeed_ast1060.py index 833cfb8272..d7158259e6 100755 --- a/tests/functional/arm/test_aspeed_ast1060.py +++ b/tests/functional/arm/test_aspeed_ast1060.py @@ -11,18 +11,18 @@ from qemu_test import Asset, exec_command_and_wait_for_pattern class AST1060Machine(AspeedTest): - ASSET_ASPEED_AST1060_PROT_3_05 = Asset( + ASSET_ASPEED_AST1060_PROT_3_07 = Asset( ('https://github.com/AspeedTech-BMC' - '/aspeed-zephyr-project/releases/download/v03.05' - '/ast1060_prot_v03.05.tgz'), - '63b36d7420290726ca80477de254474b7cb79539a42819bb1fe2665d598dadb5') + '/aspeed-zephyr-project/releases/download/v03.07' + '/ast1060_prot_v03.07.tgz'), + '55a7f51f0b77051a0ef2ada993a16c5033768e1b8e8be3babfc52c303eecd07f') - def test_arm_ast1060_prot_3_05(self): + def test_arm_ast1060_prot_3_07(self): self.set_machine('ast1060-evb') kernel_name = "ast1060_prot/zephyr.bin" kernel_file = self.archive_extract( - self.ASSET_ASPEED_AST1060_PROT_3_05, member=kernel_name) + self.ASSET_ASPEED_AST1060_PROT_3_07, member=kernel_name) self.vm.set_console() self.vm.add_args('-kernel', kernel_file, '-nographic') @@ -35,7 +35,7 @@ class AST1060Machine(AspeedTest): self.vm.set_machine("ast1060-evb") kernel_name = "ast1060_prot/zephyr.bin" - kernel_file = self.archive_extract(self.ASSET_ASPEED_AST1060_PROT_3_05, + kernel_file = self.archive_extract(self.ASSET_ASPEED_AST1060_PROT_3_07, member=kernel_name) otp_img = self.generate_otpmem_image() From 1d06e84aa75e880ba1e859c6ee157306702ab3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Sun, 2 Aug 2026 09:28:28 -0700 Subject: [PATCH 139/627] hw/arm/aspeed: avoid sign mismatch on sscanf for uart property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit using "%u" with sscanf() was likely meant to indicate that a negative value was unexpected, but with a signed variable it could result in undefined behaviour. use "%d" and check for a negative input explicitly. Signed-off-by: Carlo Marcelo Arenas Belón Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260802162828.16880-1-carenas@gmail.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a48c442058..a9238e6217 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -327,7 +327,7 @@ static void aspeed_set_bmc_console(Object *obj, const char *value, Error **errp) int uart_first = aspeed_uart_first(sc->uarts_base); int uart_last = aspeed_uart_last(sc->uarts_base, sc->uarts_num); - if (sscanf(value, "uart%u", &val) != 1) { + if (sscanf(value, "uart%d", &val) != 1 || val < 0) { error_setg(errp, "Bad value for \"uart\" property"); return; } From c264c5175ee0672169923eb61d3bd3dd7018db1a Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:18 +0000 Subject: [PATCH 140/627] hw/misc/aspeed_hace: Support the crypto command in direct access mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The crypt command register was previously stubbed out. Implement it for the direct access mode, where HACE00/HACE04 point directly at contiguous source and destination buffers. AES-128/192/256, DES and 3DES are supported in ECB and CBC modes via the qcrypto cipher API; the IV and key are read from the context buffer (HACE08) and, for CBC, the resulting chaining IV is written back to the context. The completion interrupt is now raised for every HACE variant as the hardware does, which fixes the crypt command hang on the AST2500, AST2600 and AST1030. The AST2700 crypto engine still needs 64-bit DMA and AES-GCM, which are added later, so it keeps its temporary interrupt-only workaround until then. For debugging, the context, source and destination buffers are dumped through the existing aspeed_hace_hexdump trace event (disabled by default). CTR mode, scatter-gather mode and AES-GCM are added separately. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 283 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 268 insertions(+), 15 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index c61efe50c4..0f35d74137 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -18,11 +18,43 @@ #include "qapi/error.h" #include "migration/vmstate.h" #include "crypto/hash.h" +#include "crypto/cipher.h" #include "hw/core/qdev-properties.h" #include "hw/core/irq.h" #include "trace.h" -#define R_CRYPT_CMD (0x10 / 4) +/* Crypto engine registers */ +#define R_CRYPT_SRC (0x00 / 4) +#define R_CRYPT_DEST (0x04 / 4) +#define R_CRYPT_CONTEXT (0x08 / 4) +#define R_CRYPT_DATA_LEN (0x0c / 4) +/* HACE0C[27:0] holds the crypto data length */ +#define CRYPT_DATA_LEN_MASK 0x0FFFFFFF +#define R_CRYPT_CMD (0x10 / 4) +/* Crypto engine command register (HACE10) bits */ +#define CRYPT_CMD_ENCRYPT BIT(7) +#define CRYPT_CMD_ISR_EN BIT(12) +#define CRYPT_CMD_DES_SELECT BIT(16) +#define CRYPT_CMD_TRIPLE_DES BIT(17) +#define CRYPT_CMD_SRC_SG_CTRL BIT(18) +/* Operation mode HACE10[6:4] */ +#define CRYPT_CMD_OP_MODE_MASK (0x7 << 4) +#define CRYPT_CMD_ECB (0x0 << 4) +#define CRYPT_CMD_CBC (0x1 << 4) +/* AES key length HACE10[3:2] */ +#define CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2) +#define CRYPT_CMD_AES256 (0x2 << 2) +#define CRYPT_CMD_AES192 (0x1 << 2) +#define CRYPT_CMD_AES128 (0x0 << 2) + +/* + * Crypto context buffer layout (HACE08). The IV is at the start of the buffer + * (DES places its 8 byte IV at offset 8) and the cipher key at offset 0x10. + */ +#define CRYPT_CTX_IV_OFFSET 0x00 +#define CRYPT_CTX_DES_IV_OFFSET 0x08 +#define CRYPT_CTX_KEY_OFFSET 0x10 +#define CRYPT_CTX_SIZE 0x30 #define R_STATUS (0x1c / 4) #define HASH_IRQ BIT(9) @@ -65,7 +97,6 @@ /* Other cmd bits */ #define HASH_IRQ_EN BIT(9) #define HASH_SG_EN BIT(18) -#define CRYPT_IRQ_EN BIT(12) /* Scatter-gather data list */ #define SG_LIST_LEN_SIZE 4 #define SG_LIST_LEN_MASK 0x0FFFFFFF @@ -501,6 +532,216 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } } +static bool crypt_aes_alg(uint32_t cmd, QCryptoCipherAlgo *alg, size_t *keylen) +{ + switch (cmd & CRYPT_CMD_AES_KEY_LEN_MASK) { + case CRYPT_CMD_AES128: + *alg = QCRYPTO_CIPHER_ALGO_AES_128; + *keylen = 16; + break; + case CRYPT_CMD_AES192: + *alg = QCRYPTO_CIPHER_ALGO_AES_192; + *keylen = 24; + break; + case CRYPT_CMD_AES256: + *alg = QCRYPTO_CIPHER_ALGO_AES_256; + *keylen = 32; + break; + default: + return false; + } + + return true; +} + +/* + * Decode the crypto command register into a libqcrypto algorithm/mode pair + * and the block/IV geometry. Returns false for unsupported selections. + */ +static bool crypt_decode_cmd(uint32_t cmd, QCryptoCipherAlgo *alg, + QCryptoCipherMode *mode, size_t *keylen, + size_t *blocklen, size_t *iv_offset) +{ + if (cmd & CRYPT_CMD_DES_SELECT) { + *blocklen = 8; + *iv_offset = CRYPT_CTX_DES_IV_OFFSET; + if (cmd & CRYPT_CMD_TRIPLE_DES) { + *alg = QCRYPTO_CIPHER_ALGO_3DES; + *keylen = 24; + } else { + *alg = QCRYPTO_CIPHER_ALGO_DES; + *keylen = 8; + } + } else { + *blocklen = 16; + *iv_offset = CRYPT_CTX_IV_OFFSET; + if (!crypt_aes_alg(cmd, alg, keylen)) { + return false; + } + } + + switch (cmd & CRYPT_CMD_OP_MODE_MASK) { + case CRYPT_CMD_ECB: + *mode = QCRYPTO_CIPHER_MODE_ECB; + break; + case CRYPT_CMD_CBC: + *mode = QCRYPTO_CIPHER_MODE_CBC; + break; + default: + return false; + } + + return true; +} + +/* + * Direct access mode: the source/destination register (HACE00/HACE04) points + * at a single contiguous buffer in DRAM. Copy @len bytes between it and the + * bounce buffer @buf; when @to_dram is true @buf is written out, otherwise it + * is read in. Returns true on success. + */ +static bool crypt_prepare_direct(AspeedHACEState *s, uint64_t addr, + uint8_t *buf, uint32_t len, bool to_dram) +{ + return !address_space_rw(&s->dram_as, addr, MEMTXATTRS_UNSPECIFIED, + buf, len, to_dram); +} + +/* + * Perform an AES/DES/3DES ECB/CBC operation in direct access mode: the source + * and destination are single contiguous buffers (HACE00/HACE04) and the IV/key + * come from the context buffer (HACE08). For CBC the resulting chaining IV is + * written back to the context buffer so the driver can continue the chain. + */ +static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) +{ + uint32_t len = s->regs[R_CRYPT_DATA_LEN]; + bool encrypt = cmd & CRYPT_CMD_ENCRYPT; + g_autoptr(QCryptoCipher) cipher = NULL; + g_autofree uint8_t *src_buf = NULL; + g_autofree uint8_t *dst_buf = NULL; + uint8_t ctx[CRYPT_CTX_SIZE]; + Error *local_err = NULL; + QCryptoCipherMode mode; + QCryptoCipherAlgo alg; + const uint8_t *next_iv; + uint64_t ctx_addr; + uint64_t src_addr; + uint64_t dst_addr; + size_t iv_offset; + size_t blocklen; + size_t keylen; + + if (len == 0) { + return; + } + + if (!crypt_decode_cmd(cmd, &alg, &mode, &keylen, &blocklen, &iv_offset)) { + qemu_log_mask(LOG_UNIMP, + "%s: Unsupported crypt command 0x%x\n", __func__, cmd); + return; + } + + if (!qcrypto_cipher_supports(alg, mode)) { + qemu_log_mask(LOG_UNIMP, + "%s: cipher mode not supported by the crypto backend\n", + __func__); + return; + } + + /* Fetch the IV and key from the context buffer in DRAM. */ + ctx_addr = s->regs[R_CRYPT_CONTEXT]; + if (address_space_read(&s->dram_as, ctx_addr, MEMTXATTRS_UNSPECIFIED, + ctx, sizeof(ctx))) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read context, addr=0x%" HWADDR_PRIx "\n", + __func__, ctx_addr); + return; + } + + if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) { + hace_hexdump("context", (char *)ctx, sizeof(ctx)); + } + + cipher = qcrypto_cipher_new(alg, mode, ctx + CRYPT_CTX_KEY_OFFSET, keylen, + &local_err); + if (cipher == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher new failed: %s\n", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + + if (mode != QCRYPTO_CIPHER_MODE_ECB && + qcrypto_cipher_setiv(cipher, ctx + iv_offset, blocklen, + &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher setiv failed: %s\n", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + + src_buf = g_malloc0(len); + dst_buf = g_malloc0(len); + + src_addr = s->regs[R_CRYPT_SRC]; + if (!crypt_prepare_direct(s, src_addr, src_buf, len, false)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to read src, addr=0x%" HWADDR_PRIx "\n", + __func__, src_addr); + return; + } + + if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) { + hace_hexdump("src", (char *)src_buf, len); + } + + if (encrypt) { + if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, len, + &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: encrypt failed: %s\n", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + } else { + if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, len, + &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: decrypt failed: %s\n", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + } + + dst_addr = s->regs[R_CRYPT_DEST]; + if (!crypt_prepare_direct(s, dst_addr, dst_buf, len, true)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to write dst, addr=0x%" HWADDR_PRIx "\n", + __func__, dst_addr); + return; + } + + if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) { + hace_hexdump("dst", (char *)dst_buf, len); + } + + if (mode == QCRYPTO_CIPHER_MODE_CBC) { + /* + * CBC chains on the last ciphertext block: the final block of the + * output when encrypting, or of the input when decrypting. Write it + * back as the IV for the next request. + */ + next_iv = (encrypt ? dst_buf : src_buf) + len - blocklen; + if (address_space_write(&s->dram_as, ctx_addr + iv_offset, + MEMTXATTRS_UNSPECIFIED, next_iv, blocklen)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to write IV, addr=0x%" HWADDR_PRIx "\n", + __func__, ctx_addr + iv_offset); + } + } +} + static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) { AspeedHACEState *s = ASPEED_HACE(opaque); @@ -531,16 +772,22 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, qemu_irq_lower(s->irq); } } - if (ahc->raise_crypt_interrupt_workaround) { - if (data & CRYPT_IRQ) { - data &= ~CRYPT_IRQ; + if (data & CRYPT_IRQ) { + data &= ~CRYPT_IRQ; - if (s->regs[addr] & CRYPT_IRQ) { - qemu_irq_lower(s->irq); - } + if (s->regs[addr] & CRYPT_IRQ) { + qemu_irq_lower(s->irq); } } break; + case R_CRYPT_SRC: + case R_CRYPT_DEST: + case R_CRYPT_CONTEXT: + data &= ahc->src_mask; + break; + case R_CRYPT_DATA_LEN: + data &= CRYPT_DATA_LEN_MASK; + break; case R_HASH_SRC: data &= ahc->src_mask; break; @@ -589,13 +836,19 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, break; } case R_CRYPT_CMD: - qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n", - __func__); - if (ahc->raise_crypt_interrupt_workaround) { - s->regs[R_STATUS] |= CRYPT_IRQ; - if (data & CRYPT_IRQ_EN) { - qemu_irq_raise(s->irq); - } + /* + * The AST2700 crypto engine needs 64-bit DMA and AES-GCM, which are + * added later; until then it keeps the temporary workaround of only + * raising the completion interrupt without running the command. + */ + if (!ahc->raise_crypt_interrupt_workaround) { + do_crypt_operation(s, data); + } + + /* Hardware raises the crypt interrupt once the command finishes. */ + s->regs[R_STATUS] |= CRYPT_IRQ; + if (data & CRYPT_CMD_ISR_EN) { + qemu_irq_raise(s->irq); } break; case R_HASH_SRC_HI: From d566fb6b1e1fb68007e72c221a54fcc1d7bc056c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:19 +0000 Subject: [PATCH 141/627] tests/qtest/aspeed-hace: Test the crypto command on the AST2500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a crypto known-answer test harness and exercise the AST2500, which uses the crypto engine's direct access mode. Each mode (AES/DES/3DES in ECB and CBC) is a separate test that checks the ciphertext, the plaintext round-trip and, for CBC, the chaining IV written back to the context buffer. The key/IV/plaintext/ciphertext values are taken verbatim from the Linux kernel crypto self-test templates in crypto/testmgr.h. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 325 ++++++++++++++++++++++++++++++++ tests/qtest/aspeed-hace-utils.h | 16 ++ tests/qtest/aspeed_hace-test.c | 6 + tests/qtest/meson.build | 6 +- 4 files changed, 351 insertions(+), 2 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 25450a296b..0355dd47af 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -9,6 +9,7 @@ #include "libqtest.h" #include "qemu/bitops.h" #include "qemu/bswap.h" +#include "crypto/cipher.h" #include "aspeed-hace-utils.h" /* @@ -645,3 +646,327 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, qtest_quit(s); } +/* + * Crypto engine register layout (offsets from the HACE base). + */ +#define HACE_CRYPTO_SRC 0x00 +#define HACE_CRYPTO_DEST 0x04 +#define HACE_CRYPTO_CONTEXT 0x08 +#define HACE_CRYPTO_DATA_LEN 0x0c +#define HACE_CRYPTO_CMD 0x10 + +/* Crypto command bits */ +#define HACE_CMD_ENCRYPT BIT(7) +#define HACE_CMD_ISR_EN BIT(12) +#define HACE_CMD_DES_SELECT BIT(16) +#define HACE_CMD_TRIPLE_DES BIT(17) +#define HACE_CMD_SRC_SG_CTRL BIT(18) +#define HACE_CMD_DST_SG_CTRL BIT(19) +#define HACE_CMD_OP_MODE_MASK (0x7 << 4) +#define HACE_CMD_ECB (0x0 << 4) +#define HACE_CMD_CBC (0x1 << 4) +#define HACE_CMD_AES128 (0x0 << 2) + +/* Context buffer layout: IV (DES at +8), key at +0x10 */ +#define HACE_CTX_KEY_OFFSET 0x10 +#define HACE_CTX_SIZE 0x30 + +/* + * Crypto known-answer test vectors, taken verbatim from the Linux kernel + * crypto self-test templates in crypto/testmgr.h: + * + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/crypto/testmgr.h?h=v6.18 + * + * The originating template is noted above each block. CTR and the longer CBC + * vectors are truncated to a single block (still a valid known-answer test as + * the first block only depends on the IV). + */ + +/* aes_tv_template[0] (FIPS-197) */ +static const uint8_t aes128_ecb_key[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; +static const uint8_t aes128_ecb_ptext[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; +static const uint8_t aes128_ecb_ctext[16] = { + 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }; + +/* aes_cbc_tv_template[0] (RFC 3602) */ +static const uint8_t aes128_cbc_key[16] = { + 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, + 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }; +static const uint8_t aes128_cbc_iv[16] = { + 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, + 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }; +static const uint8_t aes128_cbc_ptext[16] = { + 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x6d, 0x73, 0x67 }; +static const uint8_t aes128_cbc_ctext[16] = { + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }; +static const uint8_t aes128_cbc_ivout[16] = { + 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8, + 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a }; + +/* des_tv_template[0] (Applied Cryptography) */ +static const uint8_t des_ecb_key[8] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; +static const uint8_t des_ecb_ptext[8] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7 }; +static const uint8_t des_ecb_ctext[8] = { + 0xc9, 0x57, 0x44, 0x25, 0x6a, 0x5e, 0xd3, 0x1d }; + +/* des_cbc_tv_template[0] (OpenSSL), first block */ +static const uint8_t des_cbc_key[8] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; +static const uint8_t des_cbc_iv[8] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; +static const uint8_t des_cbc_ptext[8] = { + 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20 }; +static const uint8_t des_cbc_ctext[8] = { + 0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4 }; + +/* des3_ede_tv_template[0] (OpenSSL) */ +static const uint8_t tdes_ecb_key[24] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; +static const uint8_t tdes_ecb_ptext[8] = { + 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x61, 0x74, 0x61 }; +static const uint8_t tdes_ecb_ctext[8] = { + 0x18, 0xd7, 0x48, 0xe5, 0x63, 0x62, 0x05, 0x72 }; + +/* des3_ede_cbc_tv_template[0] (OpenSSL), first block */ +static const uint8_t tdes_cbc_key[24] = { + 0xe9, 0xc0, 0xff, 0x2e, 0x76, 0x0b, 0x64, 0x24, + 0x44, 0x4d, 0x99, 0x5a, 0x12, 0xd6, 0x40, 0xc0, + 0xea, 0xc2, 0x84, 0xe8, 0x14, 0x95, 0xdb, 0xe8 }; +static const uint8_t tdes_cbc_iv[8] = { + 0x7d, 0x33, 0x88, 0x93, 0x0f, 0x93, 0xb2, 0x42 }; +static const uint8_t tdes_cbc_ptext[8] = { + 0x6f, 0x54, 0x20, 0x6f, 0x61, 0x4d, 0x79, 0x6e }; +static const uint8_t tdes_cbc_ctext[8] = { + 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 }; + +typedef struct CryptTest { + QCryptoCipherMode mode; + QCryptoCipherAlgo alg; + /* expected context IV after encrypt, or NULL */ + const uint8_t *iv_out; + const uint8_t *ptext; + const uint8_t *ctext; + const uint8_t *key; + const uint8_t *iv; + const char *name; + size_t keylen; + /* algorithm | mode | key size selection */ + uint32_t cmd; + size_t ivlen; + size_t len; +} CryptTest; + +static const CryptTest crypt_tests[] = { + { + .name = "aes128-ecb", + .cmd = HACE_CMD_AES128 | HACE_CMD_ECB, + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = aes128_ecb_key, + .keylen = sizeof(aes128_ecb_key), + .ptext = aes128_ecb_ptext, + .ctext = aes128_ecb_ctext, + .len = sizeof(aes128_ecb_ptext), + }, + { + .name = "aes128-cbc", + .cmd = HACE_CMD_AES128 | HACE_CMD_CBC, + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = aes128_cbc_key, + .keylen = sizeof(aes128_cbc_key), + .iv = aes128_cbc_iv, + .ivlen = sizeof(aes128_cbc_iv), + .ptext = aes128_cbc_ptext, + .ctext = aes128_cbc_ctext, + .iv_out = aes128_cbc_ivout, + .len = sizeof(aes128_cbc_ptext), + }, + { + .name = "des-ecb", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_ECB, + .alg = QCRYPTO_CIPHER_ALGO_DES, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = des_ecb_key, + .keylen = sizeof(des_ecb_key), + .ptext = des_ecb_ptext, + .ctext = des_ecb_ctext, + .len = sizeof(des_ecb_ptext), + }, + { + .name = "des-cbc", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CBC, + .alg = QCRYPTO_CIPHER_ALGO_DES, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = des_cbc_key, + .keylen = sizeof(des_cbc_key), + .iv = des_cbc_iv, + .ivlen = sizeof(des_cbc_iv), + .ptext = des_cbc_ptext, + .ctext = des_cbc_ctext, + .len = sizeof(des_cbc_ptext), + }, + { + .name = "des3_ede-ecb", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_ECB, + .alg = QCRYPTO_CIPHER_ALGO_3DES, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = tdes_ecb_key, + .keylen = sizeof(tdes_ecb_key), + .ptext = tdes_ecb_ptext, + .ctext = tdes_ecb_ctext, + .len = sizeof(tdes_ecb_ptext), + }, + { + .name = "des3_ede-cbc", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_CBC, + .alg = QCRYPTO_CIPHER_ALGO_3DES, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = tdes_cbc_key, + .keylen = sizeof(tdes_cbc_key), + .iv = tdes_cbc_iv, + .ivlen = sizeof(tdes_cbc_iv), + .ptext = tdes_cbc_ptext, + .ctext = tdes_cbc_ctext, + .len = sizeof(tdes_cbc_ptext), + }, +}; + +/* DRAM offsets for the crypto test source, destination and context buffers. */ +#define CRYPT_OFF_SRC 0x10000 +#define CRYPT_OFF_DST 0x20000 +#define CRYPT_OFF_CTX 0x30000 + +/* Describes one registered crypto test (qtest_add_data_func() data pointer). */ +typedef struct AspeedCryptoTest { + const char *machine; + uint64_t dram; + uint32_t base; + int index; +} AspeedCryptoTest; + +/* Map a command's operation mode (HACE10[6:4]) to a CRYPT_MODE_* flag. */ +static uint32_t crypt_mode_flag(uint32_t cmd) +{ + switch (cmd & HACE_CMD_OP_MODE_MASK) { + case HACE_CMD_ECB: + return CRYPT_MODE_ECB; + case HACE_CMD_CBC: + return CRYPT_MODE_CBC; + default: + return 0; + } +} + +static void crypt_write_ctx(QTestState *s, uint64_t ctx_addr, + const CryptTest *t) +{ + size_t iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0; + uint8_t ctx[HACE_CTX_SIZE] = { 0 }; + + if (t->iv) { + memcpy(ctx + iv_off, t->iv, t->ivlen); + } + memcpy(ctx + HACE_CTX_KEY_OFFSET, t->key, t->keylen); + qtest_memwrite(s, ctx_addr, ctx, sizeof(ctx)); +} + +/* Run one crypto operation in direct access mode and read back the result. */ +static void crypt_run_direct(QTestState *s, uint32_t base, uint64_t dram, + const CryptTest *t, bool encrypt, uint8_t *out) +{ + const uint8_t *in = encrypt ? t->ptext : t->ctext; + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN; + uint64_t src = dram + CRYPT_OFF_SRC; + uint64_t dst = dram + CRYPT_OFF_DST; + uint64_t ctx = dram + CRYPT_OFF_CTX; + + if (encrypt) { + cmd |= HACE_CMD_ENCRYPT; + } + + crypt_write_ctx(s, ctx, t); + qtest_memwrite(s, src, in, t->len); + + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src); + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst); + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx); + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len); + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd); + + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==, + HACE_CRYPTO_ISR); + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR); + + qtest_memread(s, dst, out, t->len); +} + +static void aspeed_test_crypto_direct(const void *data) +{ + const AspeedCryptoTest *c = data; + const CryptTest *t = &crypt_tests[c->index]; + QTestState *s = qtest_init(c->machine); + uint8_t out[64]; + uint8_t iv[16]; + size_t iv_off; + + g_assert_cmpuint(t->len, <=, sizeof(out)); + + /* Encrypt: ptext -> ctext */ + crypt_run_direct(s, c->base, c->dram, t, true, out); + g_assert_cmpmem(out, t->len, t->ctext, t->len); + + if (t->iv_out) { + iv_off = (t->cmd & HACE_CMD_DES_SELECT) ? 8 : 0; + qtest_memread(s, c->dram + CRYPT_OFF_CTX + iv_off, iv, t->ivlen); + g_assert_cmpmem(iv, t->ivlen, t->iv_out, t->ivlen); + } + + /* Decrypt: ctext -> ptext */ + crypt_run_direct(s, c->base, c->dram, t, false, out); + g_assert_cmpmem(out, t->len, t->ptext, t->len); + + qtest_quit(s); +} + +void aspeed_add_crypto_tests(const char *prefix, const char *machine, + uint32_t base, uint64_t dram, uint32_t modes) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) { + g_autofree char *path = NULL; + AspeedCryptoTest *t; + + if (!(modes & crypt_mode_flag(crypt_tests[i].cmd))) { + continue; + } + + if (!qcrypto_cipher_supports(crypt_tests[i].alg, + crypt_tests[i].mode)) { + g_printerr("# skip unsupported %s\n", crypt_tests[i].name); + continue; + } + + path = g_strdup_printf("%s/hace/crypto/%s", prefix, + crypt_tests[i].name); + t = g_new0(AspeedCryptoTest, 1); + t->machine = machine; + t->base = base; + t->dram = dram; + t->index = i; + qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, g_free); + } +} + diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index 27ab2bb975..13feaa61e4 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -79,5 +79,21 @@ void aspeed_test_sha512_accum(const char *machine, const uint32_t base, void aspeed_test_addresses(const char *machine, const uint32_t base, const struct AspeedMasks *expected); +/* + * Cipher modes a SoC's crypto engine supports, for aspeed_add_crypto_tests(). + */ +enum { + CRYPT_MODE_ECB = 1 << 0, + CRYPT_MODE_CBC = 1 << 1, +}; + +/* + * Register the crypto known-answer tests that @modes selects (a mask of + * CRYPT_MODE_*) for the given machine. Each test is named + * "/hace/crypto/". + */ +void aspeed_add_crypto_tests(const char *prefix, const char *machine, + uint32_t base, uint64_t dram, uint32_t modes); + #endif /* TESTS_ASPEED_HACE_UTILS_H */ diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 38777020ca..4cb4c475e9 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -229,6 +229,12 @@ int main(int argc, char **argv) qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); qtest_add_func("ast2500/hace/md5", test_md5_ast2500); + /* + * The AST2500 crypto engine uses direct access mode and supports ECB/CBC. + */ + aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", 0x1e6e3000, + 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC); + qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400); qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400); qtest_add_func("ast2400/hace/sha256", test_sha256_ast2400); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 4d81857174..dcdbfe2889 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -392,9 +392,11 @@ if get_option('replication').allowed() endif qtests = { - 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), + 'aspeed_hace-test': [files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), + crypto], 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), - 'ast2700-hace-test': files('aspeed-hace-utils.c', 'ast2700-hace-test.c'), + 'ast2700-hace-test': [files('aspeed-hace-utils.c', 'ast2700-hace-test.c'), + crypto], 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'cdrom-test': files('boot-sector.c'), From 604cec223c4bf20b8fef7788263b13d13fed3708 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:21 +0000 Subject: [PATCH 142/627] hw/misc/aspeed_hace: Support scatter-gather mode for the crypto command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600 and later crypto engines drive the source and destination through scatter-gather lists (HACE10[18]/[19]) rather than the single contiguous buffers used by the AST2500 direct access mode. Each SG list entry is a length word (SG_LIST_LEN_LAST marks the final entry) followed by a DRAM address, matching the hash engine layout. Add a crypt_prepare_sg() helper that gathers the source into / scatters the destination out of the bounce buffer by walking the SG list, and select it or the existing crypt_prepare_direct() from do_crypt_operation based on HACE10[18], mirroring the hash engine's direct/scatter-gather dispatch. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 70 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 0f35d74137..646ff50476 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -608,13 +608,58 @@ static bool crypt_prepare_direct(AspeedHACEState *s, uint64_t addr, } /* - * Perform an AES/DES/3DES ECB/CBC operation in direct access mode: the source - * and destination are single contiguous buffers (HACE00/HACE04) and the IV/key - * come from the context buffer (HACE08). For CBC the resulting chaining IV is - * written back to the context buffer so the driver can continue the chain. + * Scatter-gather mode: the source/destination register points at an SG list + * whose entries are a length word (SG_LIST_LEN_LAST flags the final entry) + * followed by a DRAM address, matching the hash engine layout. Gather @len + * bytes into @buf, or scatter @buf back out when @to_dram is true. + * Returns true on success. + */ +static bool crypt_prepare_sg(AspeedHACEState *s, uint64_t addr, + uint8_t *buf, uint32_t len, bool to_dram) +{ + uint32_t copied = 0; + uint32_t sg_addr; + uint32_t sg_len; + uint32_t entry; + int i; + + for (i = 0; i < ASPEED_HACE_MAX_SG && copied < len; i++) { + entry = address_space_ldl_le(&s->dram_as, addr, + MEMTXATTRS_UNSPECIFIED, NULL); + sg_addr = address_space_ldl_le(&s->dram_as, addr + SG_LIST_LEN_SIZE, + MEMTXATTRS_UNSPECIFIED, NULL); + sg_len = entry & SG_LIST_LEN_MASK; + + sg_addr &= SG_LIST_ADDR_MASK; + addr += SG_LIST_ENTRY_SIZE; + + if (sg_len > len - copied) { + sg_len = len - copied; + } + if (address_space_rw(&s->dram_as, sg_addr, MEMTXATTRS_UNSPECIFIED, + buf + copied, sg_len, to_dram)) { + return false; + } + copied += sg_len; + + if (entry & SG_LIST_LEN_LAST) { + break; + } + } + + return copied == len; +} + +/* + * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are + * either single contiguous buffers (direct access mode) or scatter-gather + * lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the IV/key come from + * the context buffer (HACE08). For CBC the resulting chaining IV is written + * back to the context buffer so the driver can continue the chain. */ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) { + bool sg_mode = cmd & CRYPT_CMD_SRC_SG_CTRL; uint32_t len = s->regs[R_CRYPT_DATA_LEN]; bool encrypt = cmd & CRYPT_CMD_ENCRYPT; g_autoptr(QCryptoCipher) cipher = NULL; @@ -631,6 +676,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) size_t iv_offset; size_t blocklen; size_t keylen; + bool status; if (len == 0) { return; @@ -684,8 +730,14 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) src_buf = g_malloc0(len); dst_buf = g_malloc0(len); + /* Gather the source into the bounce buffer, per the selected mode. */ src_addr = s->regs[R_CRYPT_SRC]; - if (!crypt_prepare_direct(s, src_addr, src_buf, len, false)) { + if (sg_mode) { + status = crypt_prepare_sg(s, src_addr, src_buf, len, false); + } else { + status = crypt_prepare_direct(s, src_addr, src_buf, len, false); + } + if (!status) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read src, addr=0x%" HWADDR_PRIx "\n", __func__, src_addr); @@ -714,8 +766,14 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) } } + /* Scatter the result back out, per the selected mode. */ dst_addr = s->regs[R_CRYPT_DEST]; - if (!crypt_prepare_direct(s, dst_addr, dst_buf, len, true)) { + if (sg_mode) { + status = crypt_prepare_sg(s, dst_addr, dst_buf, len, true); + } else { + status = crypt_prepare_direct(s, dst_addr, dst_buf, len, true); + } + if (!status) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write dst, addr=0x%" HWADDR_PRIx "\n", __func__, dst_addr); From 33399898b820f34f679f6740b1e0d73993e5d034 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:22 +0000 Subject: [PATCH 143/627] hw/misc/aspeed_hace: Support the CTR mode for the crypto command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600, AST1030 and later crypto engines add AES/DES/3DES CTR mode (HACE10[6:4] = 0b100) on top of the ECB/CBC modes shared with the AST2500. Decode the CTR selection, round the working buffers up to a whole block so the stream-like final block is still processed a block at a time, and write the counter advanced by the number of blocks consumed back to the context buffer so the driver can continue across requests. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 50 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 646ff50476..d84f7f9cec 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -41,6 +41,7 @@ #define CRYPT_CMD_OP_MODE_MASK (0x7 << 4) #define CRYPT_CMD_ECB (0x0 << 4) #define CRYPT_CMD_CBC (0x1 << 4) +#define CRYPT_CMD_CTR (0x4 << 4) /* AES key length HACE10[3:2] */ #define CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2) #define CRYPT_CMD_AES256 (0x2 << 2) @@ -587,6 +588,9 @@ static bool crypt_decode_cmd(uint32_t cmd, QCryptoCipherAlgo *alg, case CRYPT_CMD_CBC: *mode = QCRYPTO_CIPHER_MODE_CBC; break; + case CRYPT_CMD_CTR: + *mode = QCRYPTO_CIPHER_MODE_CTR; + break; default: return false; } @@ -650,6 +654,22 @@ static bool crypt_prepare_sg(AspeedHACEState *s, uint64_t addr, return copied == len; } +/* + * Add @add to the big-endian counter block @ctr (@len bytes) in place, so the + * CTR mode counter can be advanced by the number of blocks just consumed. + */ +static void crypt_be_add(uint8_t *ctr, size_t len, uint64_t add) +{ + size_t i = len; + + while (i > 0 && add) { + i--; + add += ctr[i]; + ctr[i] = add & 0xff; + add >>= 8; + } +} + /* * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are * either single contiguous buffers (direct access mode) or scatter-gather @@ -675,6 +695,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) uint64_t dst_addr; size_t iv_offset; size_t blocklen; + size_t buf_len; size_t keylen; bool status; @@ -727,8 +748,14 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) return; } - src_buf = g_malloc0(len); - dst_buf = g_malloc0(len); + /* + * Round the working buffers up to a whole block. Block modes are already + * block-aligned; the stream-like CTR mode may leave a partial final block + * that the engine still processes a full block at a time. + */ + buf_len = QEMU_ALIGN_UP(len, blocklen); + src_buf = g_malloc0(buf_len); + dst_buf = g_malloc0(buf_len); /* Gather the source into the bounce buffer, per the selected mode. */ src_addr = s->regs[R_CRYPT_SRC]; @@ -749,7 +776,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) } if (encrypt) { - if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, len, + if (qcrypto_cipher_encrypt(cipher, src_buf, dst_buf, buf_len, &local_err) < 0) { qemu_log_mask(LOG_GUEST_ERROR, "%s: encrypt failed: %s\n", __func__, error_get_pretty(local_err)); @@ -757,7 +784,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) return; } } else { - if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, len, + if (qcrypto_cipher_decrypt(cipher, src_buf, dst_buf, buf_len, &local_err) < 0) { qemu_log_mask(LOG_GUEST_ERROR, "%s: decrypt failed: %s\n", __func__, error_get_pretty(local_err)); @@ -790,13 +817,26 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) * output when encrypting, or of the input when decrypting. Write it * back as the IV for the next request. */ - next_iv = (encrypt ? dst_buf : src_buf) + len - blocklen; + next_iv = (encrypt ? dst_buf : src_buf) + buf_len - blocklen; if (address_space_write(&s->dram_as, ctx_addr + iv_offset, MEMTXATTRS_UNSPECIFIED, next_iv, blocklen)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write IV, addr=0x%" HWADDR_PRIx "\n", __func__, ctx_addr + iv_offset); } + } else if (mode == QCRYPTO_CIPHER_MODE_CTR) { + /* + * CTR chains on the counter, which advances by one per block. Add the + * number of blocks processed (buf_len / blocklen) and write it back. + */ + crypt_be_add(ctx + iv_offset, blocklen, buf_len / blocklen); + if (address_space_write(&s->dram_as, ctx_addr + iv_offset, + MEMTXATTRS_UNSPECIFIED, ctx + iv_offset, + blocklen)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to write IV, addr=0x%" HWADDR_PRIx "\n", + __func__, ctx_addr + iv_offset); + } } } From 48274cdb830f30bc573e089b94d0a061d7235081 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:23 +0000 Subject: [PATCH 144/627] tests/qtest/aspeed-hace: Test the crypto command on the AST2600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the crypto known-answer tests to cover the AST2600 crypto engine, which drives the source and destination through scatter-gather lists and adds CTR mode on top of the ECB/CBC modes shared with the AST2500. Add a scatter-gather runner that describes each buffer with three non-adjacent fragments to exercise the gather/scatter path, add AES/DES/3DES CTR vectors (verifying the counter written back to the context buffer), and give aspeed_add_crypto_tests() a mode mask and a scatter-gather flag so each SoC registers exactly the modes and transfer method it supports. Register the AST2600 with ECB/CBC/CTR in scatter-gather mode. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 217 +++++++++++++++++++++++++++++++- tests/qtest/aspeed-hace-utils.h | 7 +- tests/qtest/aspeed_hace-test.c | 8 +- 3 files changed, 224 insertions(+), 8 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 0355dd47af..f582c88ef5 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -665,6 +665,7 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, #define HACE_CMD_OP_MODE_MASK (0x7 << 4) #define HACE_CMD_ECB (0x0 << 4) #define HACE_CMD_CBC (0x1 << 4) +#define HACE_CMD_CTR (0x4 << 4) #define HACE_CMD_AES128 (0x0 << 2) /* Context buffer layout: IV (DES at +8), key at +0x10 */ @@ -750,6 +751,49 @@ static const uint8_t tdes_cbc_ptext[8] = { static const uint8_t tdes_cbc_ctext[8] = { 0x0e, 0x2d, 0xb6, 0x97, 0x3c, 0x56, 0x33, 0xf4 }; +/* aes_ctr_tv_template[0] (NIST SP800-38A F.5.1), first block */ +static const uint8_t aes128_ctr_key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; +static const uint8_t aes128_ctr_iv[16] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; +static const uint8_t aes128_ctr_ptext[16] = { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }; +static const uint8_t aes128_ctr_ctext[16] = { + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, + 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce }; +static const uint8_t aes128_ctr_ivout[16] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xff, 0x00 }; + +/* des_ctr_tv_template[0] (Crypto++), first block */ +static const uint8_t des_ctr_key[8] = { + 0xc9, 0x83, 0xa6, 0xc9, 0xec, 0x0f, 0x32, 0x55 }; +static const uint8_t des_ctr_iv[8] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd }; +static const uint8_t des_ctr_ptext[8] = { + 0x50, 0xb9, 0x22, 0xae, 0x17, 0x80, 0x0c, 0x75 }; +static const uint8_t des_ctr_ctext[8] = { + 0x2f, 0x96, 0x06, 0x0f, 0x50, 0xc9, 0x68, 0x03 }; +static const uint8_t des_ctr_ivout[8] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe }; + +/* des3_ede_ctr_tv_template[0] (Crypto++), first block */ +static const uint8_t tdes_ctr_key[24] = { + 0x9c, 0xd6, 0xf3, 0x9c, 0xb9, 0x5a, 0x67, 0x00, + 0x5a, 0x67, 0x00, 0x2d, 0xce, 0xeb, 0x2d, 0xce, + 0xeb, 0xb4, 0x51, 0x72, 0xb4, 0x51, 0x72, 0x1f }; +static const uint8_t tdes_ctr_iv[8] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static const uint8_t tdes_ctr_ptext[8] = { + 0x05, 0xec, 0x77, 0xfb, 0x42, 0xd5, 0x59, 0x20 }; +static const uint8_t tdes_ctr_ctext[8] = { + 0x07, 0xc2, 0x08, 0x20, 0x72, 0x1f, 0x49, 0xef }; +static const uint8_t tdes_ctr_ivout[8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + typedef struct CryptTest { QCryptoCipherMode mode; QCryptoCipherAlgo alg; @@ -841,12 +885,65 @@ static const CryptTest crypt_tests[] = { .ctext = tdes_cbc_ctext, .len = sizeof(tdes_cbc_ptext), }, + { + .name = "aes128-ctr", + .cmd = HACE_CMD_AES128 | HACE_CMD_CTR, + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .mode = QCRYPTO_CIPHER_MODE_CTR, + .key = aes128_ctr_key, + .keylen = sizeof(aes128_ctr_key), + .iv = aes128_ctr_iv, + .ivlen = sizeof(aes128_ctr_iv), + .ptext = aes128_ctr_ptext, + .ctext = aes128_ctr_ctext, + .iv_out = aes128_ctr_ivout, + .len = sizeof(aes128_ctr_ptext), + }, + { + .name = "des-ctr", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_CTR, + .alg = QCRYPTO_CIPHER_ALGO_DES, + .mode = QCRYPTO_CIPHER_MODE_CTR, + .key = des_ctr_key, + .keylen = sizeof(des_ctr_key), + .iv = des_ctr_iv, + .ivlen = sizeof(des_ctr_iv), + .ptext = des_ctr_ptext, + .ctext = des_ctr_ctext, + .iv_out = des_ctr_ivout, + .len = sizeof(des_ctr_ptext), + }, + { + .name = "des3_ede-ctr", + .cmd = HACE_CMD_DES_SELECT | HACE_CMD_TRIPLE_DES | HACE_CMD_CTR, + .alg = QCRYPTO_CIPHER_ALGO_3DES, + .mode = QCRYPTO_CIPHER_MODE_CTR, + .key = tdes_ctr_key, + .keylen = sizeof(tdes_ctr_key), + .iv = tdes_ctr_iv, + .ivlen = sizeof(tdes_ctr_iv), + .ptext = tdes_ctr_ptext, + .ctext = tdes_ctr_ctext, + .iv_out = tdes_ctr_ivout, + .len = sizeof(tdes_ctr_ptext), + }, }; /* DRAM offsets for the crypto test source, destination and context buffers. */ #define CRYPT_OFF_SRC 0x10000 #define CRYPT_OFF_DST 0x20000 #define CRYPT_OFF_CTX 0x30000 +/* Scatter-gather list offsets (each list has CRYPT_SG_FRAGS entries). */ +#define CRYPT_OFF_SRC_SG 0x40000 +#define CRYPT_OFF_DST_SG 0x50000 +/* + * The scatter-gather tests split each buffer into CRYPT_SG_FRAGS fragments, + * each placed CRYPT_SG_FRAG_STRIDE apart so the fragments never abut. The gaps + * make the test fail if the engine ignores the list and reads one contiguous + * block. + */ +#define CRYPT_SG_FRAGS 3 +#define CRYPT_SG_FRAG_STRIDE 0x1000 /* Describes one registered crypto test (qtest_add_data_func() data pointer). */ typedef struct AspeedCryptoTest { @@ -854,6 +951,7 @@ typedef struct AspeedCryptoTest { uint64_t dram; uint32_t base; int index; + bool sg; } AspeedCryptoTest; /* Map a command's operation mode (HACE10[6:4]) to a CRYPT_MODE_* flag. */ @@ -864,6 +962,8 @@ static uint32_t crypt_mode_flag(uint32_t cmd) return CRYPT_MODE_ECB; case HACE_CMD_CBC: return CRYPT_MODE_CBC; + case HACE_CMD_CTR: + return CRYPT_MODE_CTR; default: return 0; } @@ -912,7 +1012,104 @@ static void crypt_run_direct(QTestState *s, uint32_t base, uint64_t dram, qtest_memread(s, dst, out, t->len); } -static void aspeed_test_crypto_direct(const void *data) +/* + * Byte range [*frag_off, *frag_off + *frag_len) of fragment @index when an + * @len-byte buffer is split into CRYPT_SG_FRAGS pieces; the last piece takes + * the remainder of an uneven split. + */ +static void crypt_frag_range(uint32_t len, int index, + uint32_t *frag_off, uint32_t *frag_len) +{ + uint32_t base = len / CRYPT_SG_FRAGS; + + *frag_off = base * index; + *frag_len = (index == CRYPT_SG_FRAGS - 1) ? len - *frag_off : base; +} + +/* + * Scatter [in, len) across CRYPT_SG_FRAGS buffers based at @base_off and spaced + * CRYPT_SG_FRAG_STRIDE apart, then build the SG list describing them at @list. + * When @in is NULL only the list is built (used for the destination, which the + * engine fills in). + */ +static void crypt_make_sg(QTestState *s, uint64_t dram, uint32_t base_off, + uint64_t list, const uint8_t *in, uint32_t len) +{ + struct AspeedSgList sg[CRYPT_SG_FRAGS]; + uint32_t frag_off; + uint32_t frag_len; + uint64_t buf; + int i; + + for (i = 0; i < CRYPT_SG_FRAGS; i++) { + crypt_frag_range(len, i, &frag_off, &frag_len); + buf = dram + base_off + i * CRYPT_SG_FRAG_STRIDE; + + if (in) { + qtest_memwrite(s, buf, in + frag_off, frag_len); + } + sg[i].len = cpu_to_le32(frag_len | (i == CRYPT_SG_FRAGS - 1 ? + SG_LIST_LEN_LAST : 0)); + sg[i].addr = cpu_to_le32((uint32_t)buf); + } + + qtest_memwrite(s, list, sg, sizeof(sg)); +} + +/* Gather a scatter-gathered result back from the CRYPT_SG_FRAGS buffers. */ +static void crypt_gather_sg(QTestState *s, uint64_t dram, uint32_t base_off, + uint8_t *out, uint32_t len) +{ + uint32_t frag_off; + uint32_t frag_len; + int i; + + for (i = 0; i < CRYPT_SG_FRAGS; i++) { + crypt_frag_range(len, i, &frag_off, &frag_len); + qtest_memread(s, dram + base_off + i * CRYPT_SG_FRAG_STRIDE, + out + frag_off, frag_len); + } +} + +/* + * Run one block-cipher (ECB/CBC/CTR) operation in scatter-gather mode and read + * back the result. The source and destination are each split across + * CRYPT_SG_FRAGS non-adjacent DRAM buffers described by an SG list; the gaps + * ensure the test fails if the engine ignores the list and reads one + * contiguous block. + */ +static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram, + const CryptTest *t, bool encrypt, uint8_t *out) +{ + const uint8_t *in = encrypt ? t->ptext : t->ctext; + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG; + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG; + uint64_t ctx = dram + CRYPT_OFF_CTX; + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | HACE_CMD_SRC_SG_CTRL | + HACE_CMD_DST_SG_CTRL; + + if (encrypt) { + cmd |= HACE_CMD_ENCRYPT; + } + + crypt_write_ctx(s, ctx, t); + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len); + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len); + + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg); + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg); + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx); + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len); + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd); + + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==, + HACE_CRYPTO_ISR); + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR); + + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len); +} + +static void aspeed_test_crypto(const void *data) { const AspeedCryptoTest *c = data; const CryptTest *t = &crypt_tests[c->index]; @@ -924,7 +1121,11 @@ static void aspeed_test_crypto_direct(const void *data) g_assert_cmpuint(t->len, <=, sizeof(out)); /* Encrypt: ptext -> ctext */ - crypt_run_direct(s, c->base, c->dram, t, true, out); + if (c->sg) { + crypt_run_sg(s, c->base, c->dram, t, true, out); + } else { + crypt_run_direct(s, c->base, c->dram, t, true, out); + } g_assert_cmpmem(out, t->len, t->ctext, t->len); if (t->iv_out) { @@ -934,14 +1135,19 @@ static void aspeed_test_crypto_direct(const void *data) } /* Decrypt: ctext -> ptext */ - crypt_run_direct(s, c->base, c->dram, t, false, out); + if (c->sg) { + crypt_run_sg(s, c->base, c->dram, t, false, out); + } else { + crypt_run_direct(s, c->base, c->dram, t, false, out); + } g_assert_cmpmem(out, t->len, t->ptext, t->len); qtest_quit(s); } void aspeed_add_crypto_tests(const char *prefix, const char *machine, - uint32_t base, uint64_t dram, uint32_t modes) + uint32_t base, uint64_t dram, uint32_t modes, + bool sg) { int i; @@ -966,7 +1172,8 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine, t->base = base; t->dram = dram; t->index = i; - qtest_add_data_func_full(path, t, aspeed_test_crypto_direct, g_free); + t->sg = sg; + qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free); } } diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index 13feaa61e4..82b0b3f93d 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -85,15 +85,18 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, enum { CRYPT_MODE_ECB = 1 << 0, CRYPT_MODE_CBC = 1 << 1, + CRYPT_MODE_CTR = 1 << 2, }; /* * Register the crypto known-answer tests that @modes selects (a mask of * CRYPT_MODE_*) for the given machine. Each test is named - * "/hace/crypto/". + * "/hace/crypto/". @sg selects scatter-gather mode (used by the + * AST2600 and later) instead of the AST2500 direct access mode. */ void aspeed_add_crypto_tests(const char *prefix, const char *machine, - uint32_t base, uint64_t dram, uint32_t modes); + uint32_t base, uint64_t dram, uint32_t modes, + bool sg); #endif /* TESTS_ASPEED_HACE_UTILS_H */ diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 4cb4c475e9..61a3e3feb5 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -224,6 +224,12 @@ int main(int argc, char **argv) qtest_add_func("ast2600/hace/sha384_accum", test_sha384_accum_ast2600); qtest_add_func("ast2600/hace/sha256_accum", test_sha256_accum_ast2600); + /* The AST2600 crypto engine uses scatter-gather mode and adds CTR. */ + aspeed_add_crypto_tests("ast2600", "-machine ast2600-evb", 0x1e6d0000, + 0x80000000, + CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR, + true); + qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500); qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500); qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); @@ -233,7 +239,7 @@ int main(int argc, char **argv) * The AST2500 crypto engine uses direct access mode and supports ECB/CBC. */ aspeed_add_crypto_tests("ast2500", "-machine ast2500-evb", 0x1e6e3000, - 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC); + 0x80000000, CRYPT_MODE_ECB | CRYPT_MODE_CBC, false); qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400); qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400); From d030f3cabe74e0b3205b417ca061c3ac6e7a4334 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:24 +0000 Subject: [PATCH 145/627] tests/qtest/aspeed-hace: Test the crypto command on the AST1030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST1030 reuses the AST2600 crypto engine, so it drives the same scatter-gather transfers and supports the same ECB/CBC/CTR modes. Reuse the crypto known-answer tests to cover it, registering the AST1030 with the same modes and scatter-gather flag as the AST2600. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed_hace-test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 61a3e3feb5..42130df1e2 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -210,6 +210,12 @@ int main(int argc, char **argv) qtest_add_func("ast1030/hace/sha384_accum", test_sha384_accum_ast1030); qtest_add_func("ast1030/hace/sha256_accum", test_sha256_accum_ast1030); + /* The AST1030 reuses the AST2600 crypto engine (scatter-gather, CTR). */ + aspeed_add_crypto_tests("ast1030", "-machine ast1030-evb", 0x7e6d0000, + 0x00000000, + CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR, + true); + qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600); qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600); qtest_add_func("ast2600/hace/sha384", test_sha384_ast2600); From b781906fccf1e0668255f73fa9d96670a4f91ddb Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:26 +0000 Subject: [PATCH 146/627] crypto/cipher: Add GCM to QCryptoCipherMode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the GCM cipher mode so authenticated encryption can be built on top of the existing qcrypto_cipher API. GCM is an IV-based mode, so register it in mode_need_iv. No backend advertises it yet, so it stays unsupported until a backend and the AAD/tag helpers are added in the following patches. Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Acked-by: Daniel P. Berrangé Acked-by: Markus Armbruster Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- crypto/cipher.c | 1 + qapi/crypto.json | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crypto/cipher.c b/crypto/cipher.c index 229710f76b..64c2339d17 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -66,6 +66,7 @@ static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = { [QCRYPTO_CIPHER_MODE_CBC] = true, [QCRYPTO_CIPHER_MODE_XTS] = true, [QCRYPTO_CIPHER_MODE_CTR] = true, + [QCRYPTO_CIPHER_MODE_GCM] = true, }; diff --git a/qapi/crypto.json b/qapi/crypto.json index 2b55befef9..6e3a98ff68 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -121,10 +121,12 @@ # # @ctr: Counter (Since 2.8) # +# @gcm: Galois/Counter Mode (Since 11.2) +# # Since: 2.6 ## { 'enum': 'QCryptoCipherMode', - 'data': ['ecb', 'cbc', 'xts', 'ctr']} + 'data': ['ecb', 'cbc', 'xts', 'ctr', 'gcm']} ## # @QCryptoIVGenAlgo: From a4383c086228f8626f2318b7f4b984002ce820df Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:27 +0000 Subject: [PATCH 147/627] crypto/cipher: Add setaad/gettag for AEAD modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AEAD modes such as GCM authenticate optional associated data (AAD) and produce an authentication tag, which the block-cipher encrypt/decrypt interface cannot express. Add qcrypto_cipher_setaad() and qcrypto_cipher_gettag() plus the matching backend driver hooks. The generic front-end reports an error when the selected mode's driver does not implement them, so calling them on a non-AEAD mode fails cleanly. Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- crypto/cipher.c | 31 +++++++++++++++++++++++++++++++ crypto/cipherpriv.h | 8 ++++++++ include/crypto/cipher.h | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/crypto/cipher.c b/crypto/cipher.c index 64c2339d17..1dc912b217 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -205,6 +205,37 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher, } +int qcrypto_cipher_setaad(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp) +{ + const QCryptoCipherDriver *drv = cipher->driver; + + if (!drv->cipher_setaad) { + error_setg(errp, "The cipher mode does not support associated data"); + return -1; + } + + return drv->cipher_setaad(cipher, aad, len, errp); +} + + +int qcrypto_cipher_gettag(QCryptoCipher *cipher, + uint8_t *tag, size_t len, + Error **errp) +{ + const QCryptoCipherDriver *drv = cipher->driver; + + if (!drv->cipher_gettag) { + error_setg(errp, + "The cipher mode does not produce an authentication tag"); + return -1; + } + + return drv->cipher_gettag(cipher, tag, len, errp); +} + + void qcrypto_cipher_free(QCryptoCipher *cipher) { if (cipher) { diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h index 64737ce961..c4f995f369 100644 --- a/crypto/cipherpriv.h +++ b/crypto/cipherpriv.h @@ -34,6 +34,14 @@ struct QCryptoCipherDriver { const uint8_t *iv, size_t niv, Error **errp); + int (*cipher_setaad)(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp); + + int (*cipher_gettag)(QCryptoCipher *cipher, + uint8_t *tag, size_t len, + Error **errp); + void (*cipher_free)(QCryptoCipher *cipher); }; diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h index 92939310ef..2e361411b9 100644 --- a/include/crypto/cipher.h +++ b/include/crypto/cipher.h @@ -235,4 +235,40 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher, const uint8_t *iv, size_t niv, Error **errp); +/** + * qcrypto_cipher_setaad: + * @cipher: the cipher object + * @aad: the associated data to authenticate + * @len: the length of @aad + * @errp: pointer to a NULL-initialized error object + * + * For AEAD modes such as GCM, feed the associated data (AAD) that is + * authenticated but not encrypted. It must be called after + * qcrypto_cipher_setiv() and before the first encrypt/decrypt call. It is + * an error to call this on a mode that is not an AEAD mode. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_cipher_setaad(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp); + +/** + * qcrypto_cipher_gettag: + * @cipher: the cipher object + * @tag: buffer to receive the authentication tag + * @len: the length of @tag + * @errp: pointer to a NULL-initialized error object + * + * For AEAD modes such as GCM, read back the authentication tag computed + * over the associated data and the message. It must be called after the + * encrypt/decrypt operation. It is an error to call this on a mode that is + * not an AEAD mode. + * + * Returns: 0 on success, -1 on error + */ +int qcrypto_cipher_gettag(QCryptoCipher *cipher, + uint8_t *tag, size_t len, + Error **errp); + #endif /* QCRYPTO_CIPHER_H */ From 1429ef61c89672ef8c8eb3241c22ba46390b9003 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:28 +0000 Subject: [PATCH 148/627] crypto/cipher-gcrypt: Implement AES-GCM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map QCRYPTO_CIPHER_MODE_GCM to GCRY_CIPHER_MODE_GCM and advertise it in qcrypto_cipher_supports() for 128-bit block ciphers. Add a GCM driver whose setiv accepts the (typically 96-bit) nonce, whose encrypt/decrypt do not require block-aligned lengths, and which implements setaad via gcry_cipher_authenticate() and gettag via gcry_cipher_gettag(). Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Acked-by: Daniel P. Berrangé Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- crypto/cipher-gcrypt.c.inc | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc index 12eb9ddb5a..fce09a3c77 100644 --- a/crypto/cipher-gcrypt.c.inc +++ b/crypto/cipher-gcrypt.c.inc @@ -65,6 +65,8 @@ static int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode) return GCRY_CIPHER_MODE_CBC; case QCRYPTO_CIPHER_MODE_CTR: return GCRY_CIPHER_MODE_CTR; + case QCRYPTO_CIPHER_MODE_GCM: + return GCRY_CIPHER_MODE_GCM; default: return GCRY_CIPHER_MODE_NONE; } @@ -104,6 +106,10 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, case QCRYPTO_CIPHER_MODE_XTS: case QCRYPTO_CIPHER_MODE_CTR: return true; + case QCRYPTO_CIPHER_MODE_GCM: + /* GCM requires a 128-bit block cipher. */ + return gcry_cipher_get_algo_blklen( + qcrypto_cipher_alg_to_gcry_alg(alg)) == 16; default: return false; } @@ -228,6 +234,99 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = { .cipher_free = qcrypto_gcrypt_ctx_free, }; +/* + * GCM is an AEAD stream mode: the IV/nonce need not match the block size, + * the message length need not be a multiple of the block size, associated + * data is fed with gcry_cipher_authenticate() and the authentication tag is + * read back with gcry_cipher_gettag(). + */ +static int qcrypto_gcrypt_gcm_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); + gcry_error_t err; + + gcry_cipher_reset(ctx->handle); + err = gcry_cipher_setiv(ctx->handle, iv, niv); + if (err != 0) { + error_setg(errp, "Cannot set IV: %s", gcry_strerror(err)); + return -1; + } + + return 0; +} + +static int qcrypto_gcrypt_gcm_setaad(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp) +{ + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); + gcry_error_t err; + + err = gcry_cipher_authenticate(ctx->handle, aad, len); + if (err != 0) { + error_setg(errp, "Cannot set AAD: %s", gcry_strerror(err)); + return -1; + } + + return 0; +} + +static int qcrypto_gcrypt_gcm_encrypt(QCryptoCipher *cipher, const void *in, + void *out, size_t len, Error **errp) +{ + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); + gcry_error_t err; + + err = gcry_cipher_encrypt(ctx->handle, out, len, in, len); + if (err != 0) { + error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err)); + return -1; + } + + return 0; +} + +static int qcrypto_gcrypt_gcm_decrypt(QCryptoCipher *cipher, const void *in, + void *out, size_t len, Error **errp) +{ + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); + gcry_error_t err; + + err = gcry_cipher_decrypt(ctx->handle, out, len, in, len); + if (err != 0) { + error_setg(errp, "Cannot decrypt data: %s", gcry_strerror(err)); + return -1; + } + + return 0; +} + +static int qcrypto_gcrypt_gcm_gettag(QCryptoCipher *cipher, + uint8_t *tag, size_t len, Error **errp) +{ + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base); + gcry_error_t err; + + err = gcry_cipher_gettag(ctx->handle, tag, len); + if (err != 0) { + error_setg(errp, "Cannot get tag: %s", gcry_strerror(err)); + return -1; + } + + return 0; +} + +static const struct QCryptoCipherDriver qcrypto_gcrypt_gcm_driver = { + .cipher_encrypt = qcrypto_gcrypt_gcm_encrypt, + .cipher_decrypt = qcrypto_gcrypt_gcm_decrypt, + .cipher_setiv = qcrypto_gcrypt_gcm_setiv, + .cipher_setaad = qcrypto_gcrypt_gcm_setaad, + .cipher_gettag = qcrypto_gcrypt_gcm_gettag, + .cipher_free = qcrypto_gcrypt_ctx_free, +}; + static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, QCryptoCipherMode mode, const uint8_t *key, @@ -259,6 +358,8 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, if (mode == QCRYPTO_CIPHER_MODE_CTR) { drv = &qcrypto_gcrypt_ctr_driver; + } else if (mode == QCRYPTO_CIPHER_MODE_GCM) { + drv = &qcrypto_gcrypt_gcm_driver; } else { drv = &qcrypto_gcrypt_driver; } From b0f7e8cc97d16133bfd7ce344b525188d68e30f1 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:30 +0000 Subject: [PATCH 149/627] crypto/cipher-nettle: Implement AES-GCM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the AES-GCM AEAD mode to the nettle backend so it is available when QEMU is built with nettle instead of gcrypt. GCM is driven through nettle's generic gcm_* interface, using the AES encrypt function for both directions: gcm_set_iv() sets the (typically 96-bit) nonce, gcm_update() feeds the associated data, gcm_encrypt()/gcm_decrypt() need not be block aligned, and gcm_digest() produces the authentication tag. Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-11-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- crypto/cipher-nettle.c.inc | 128 +++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc index 1afdc391b4..d4847f0efe 100644 --- a/crypto/cipher-nettle.c.inc +++ b/crypto/cipher-nettle.c.inc @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_CRYPTO_SM4 #include #endif @@ -410,6 +411,125 @@ DEFINE_ECB(qcrypto_nettle_sm4, sm4_encrypt_native, sm4_decrypt_native) #endif +/* + * GCM is an AEAD mode built on AES (128-bit block only). Drive it through the + * generic gcm_* interface, using the block cipher's encrypt function for both + * directions; associated data is fed with gcm_update() and the authentication + * tag is produced by gcm_digest(). + */ +typedef struct QCryptoNettleAESGCM { + QCryptoCipher base; + struct gcm_key gcm_key; + struct gcm_ctx gcm_ctx; + union { + struct aes128_ctx aes128; + struct aes192_ctx aes192; + struct aes256_ctx aes256; + } cipher; + nettle_cipher_func *encrypt; +} QCryptoNettleAESGCM; + +static int qcrypto_nettle_aes_gcm_setiv(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base); + + gcm_set_iv(&ctx->gcm_ctx, &ctx->gcm_key, niv, iv); + return 0; +} + +static int qcrypto_nettle_aes_gcm_setaad(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp) +{ + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base); + + gcm_update(&ctx->gcm_ctx, &ctx->gcm_key, len, aad); + return 0; +} + +static int qcrypto_nettle_aes_gcm_encrypt(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base); + + gcm_encrypt(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt, + len, out, in); + return 0; +} + +static int qcrypto_nettle_aes_gcm_decrypt(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base); + + gcm_decrypt(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt, + len, out, in); + return 0; +} + +static int qcrypto_nettle_aes_gcm_gettag(QCryptoCipher *cipher, + uint8_t *tag, size_t len, + Error **errp) +{ + QCryptoNettleAESGCM *ctx = container_of(cipher, QCryptoNettleAESGCM, base); + + gcm_digest(&ctx->gcm_ctx, &ctx->gcm_key, &ctx->cipher, ctx->encrypt, + len, tag); + return 0; +} + +static const struct QCryptoCipherDriver qcrypto_nettle_aes_gcm_driver = { + .cipher_encrypt = qcrypto_nettle_aes_gcm_encrypt, + .cipher_decrypt = qcrypto_nettle_aes_gcm_decrypt, + .cipher_setiv = qcrypto_nettle_aes_gcm_setiv, + .cipher_setaad = qcrypto_nettle_aes_gcm_setaad, + .cipher_gettag = qcrypto_nettle_aes_gcm_gettag, + .cipher_free = qcrypto_cipher_ctx_free, +}; + +static QCryptoCipher *qcrypto_nettle_aes_gcm_ctx_new(QCryptoCipherAlgo alg, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + QCryptoNettleAESGCM *ctx; + + if (!qcrypto_cipher_validate_key_length(alg, QCRYPTO_CIPHER_MODE_GCM, + nkey, errp)) { + return NULL; + } + + ctx = g_new0(QCryptoNettleAESGCM, 1); + ctx->base.driver = &qcrypto_nettle_aes_gcm_driver; + + switch (alg) { + case QCRYPTO_CIPHER_ALGO_AES_128: + aes128_set_encrypt_key(&ctx->cipher.aes128, key); + ctx->encrypt = aes128_encrypt_native; + break; + case QCRYPTO_CIPHER_ALGO_AES_192: + aes192_set_encrypt_key(&ctx->cipher.aes192, key); + ctx->encrypt = aes192_encrypt_native; + break; + case QCRYPTO_CIPHER_ALGO_AES_256: + aes256_set_encrypt_key(&ctx->cipher.aes256, key); + ctx->encrypt = aes256_encrypt_native; + break; + default: + error_setg(errp, "Unsupported cipher algorithm %s with GCM mode", + QCryptoCipherAlgo_str(alg)); + g_free(ctx); + return NULL; + } + + gcm_set_key(&ctx->gcm_key, &ctx->cipher, ctx->encrypt); + return &ctx->base; +} + bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, QCryptoCipherMode mode) { @@ -440,6 +560,10 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, case QCRYPTO_CIPHER_MODE_XTS: case QCRYPTO_CIPHER_MODE_CTR: return true; + case QCRYPTO_CIPHER_MODE_GCM: + return alg == QCRYPTO_CIPHER_ALGO_AES_128 || + alg == QCRYPTO_CIPHER_ALGO_AES_192 || + alg == QCRYPTO_CIPHER_ALGO_AES_256; default: return false; } @@ -451,6 +575,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, size_t nkey, Error **errp) { + if (mode == QCRYPTO_CIPHER_MODE_GCM) { + return qcrypto_nettle_aes_gcm_ctx_new(alg, key, nkey, errp); + } + switch (mode) { case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_CBC: From 66c320fd5d492cc5287e4f5bde52def3efbd149e Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:31 +0000 Subject: [PATCH 150/627] crypto/cipher-gnutls: Implement AES-GCM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the AES-GCM AEAD mode to the gnutls backend so it is available when QEMU is built with gnutls (neither gcrypt nor nettle). GCM uses the incremental gnutls_cipher_* API with the GNUTLS_CIPHER_AES_*_GCM algorithms: gnutls_cipher_set_iv() sets the nonce, gnutls_cipher_add_auth() feeds the associated data, gnutls_cipher_encrypt2()/decrypt2() process the message, and gnutls_cipher_tag() reads back the authentication tag. Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-12-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- crypto/cipher-gnutls.c.inc | 154 +++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc index a8263fff6d..963b328fa1 100644 --- a/crypto/cipher-gnutls.c.inc +++ b/crypto/cipher-gnutls.c.inc @@ -48,6 +48,15 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, default: return false; } + case QCRYPTO_CIPHER_MODE_GCM: + switch (alg) { + case QCRYPTO_CIPHER_ALGO_AES_128: + case QCRYPTO_CIPHER_ALGO_AES_192: + case QCRYPTO_CIPHER_ALGO_AES_256: + return true; + default: + return false; + } default: return false; } @@ -223,6 +232,147 @@ static struct QCryptoCipherDriver gnutls_driver = { .cipher_free = qcrypto_gnutls_cipher_free, }; +/* + * GCM is an AEAD stream mode: the nonce need not match the block size, the + * message length need not be a multiple of the block size, associated data is + * fed with gnutls_cipher_add_auth() and the authentication tag is read back + * with gnutls_cipher_tag(). + */ +static int +qcrypto_gnutls_cipher_encrypt_gcm(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + err = gnutls_cipher_encrypt2(ctx->handle, in, len, out, len); + if (err != 0) { + error_setg(errp, "Cannot encrypt data: %s", gnutls_strerror(err)); + return -1; + } + + return 0; +} + +static int +qcrypto_gnutls_cipher_decrypt_gcm(QCryptoCipher *cipher, + const void *in, void *out, + size_t len, Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + err = gnutls_cipher_decrypt2(ctx->handle, in, len, out, len); + if (err != 0) { + error_setg(errp, "Cannot decrypt data: %s", gnutls_strerror(err)); + return -1; + } + + return 0; +} + +static int +qcrypto_gnutls_cipher_setiv_gcm(QCryptoCipher *cipher, + const uint8_t *iv, size_t niv, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + + gnutls_cipher_set_iv(ctx->handle, (void *)iv, niv); + + return 0; +} + +static int +qcrypto_gnutls_cipher_setaad_gcm(QCryptoCipher *cipher, + const uint8_t *aad, size_t len, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + err = gnutls_cipher_add_auth(ctx->handle, aad, len); + if (err != 0) { + error_setg(errp, "Cannot add associated data: %s", + gnutls_strerror(err)); + return -1; + } + + return 0; +} + +static int +qcrypto_gnutls_cipher_gettag_gcm(QCryptoCipher *cipher, + uint8_t *tag, size_t len, + Error **errp) +{ + QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base); + int err; + + err = gnutls_cipher_tag(ctx->handle, tag, len); + if (err != 0) { + error_setg(errp, "Cannot get authentication tag: %s", + gnutls_strerror(err)); + return -1; + } + + return 0; +} + +static struct QCryptoCipherDriver gnutls_gcm_driver = { + .cipher_encrypt = qcrypto_gnutls_cipher_encrypt_gcm, + .cipher_decrypt = qcrypto_gnutls_cipher_decrypt_gcm, + .cipher_setiv = qcrypto_gnutls_cipher_setiv_gcm, + .cipher_setaad = qcrypto_gnutls_cipher_setaad_gcm, + .cipher_gettag = qcrypto_gnutls_cipher_gettag_gcm, + .cipher_free = qcrypto_gnutls_cipher_free, +}; + +static QCryptoCipher * +qcrypto_gnutls_aes_gcm_ctx_new(QCryptoCipherAlgo alg, const uint8_t *key, + size_t nkey, Error **errp) +{ + gnutls_datum_t gkey = { (unsigned char *)key, nkey }; + gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN; + QCryptoCipherGnutls *ctx; + int err; + + switch (alg) { + case QCRYPTO_CIPHER_ALGO_AES_128: + galg = GNUTLS_CIPHER_AES_128_GCM; + break; + case QCRYPTO_CIPHER_ALGO_AES_192: + galg = GNUTLS_CIPHER_AES_192_GCM; + break; + case QCRYPTO_CIPHER_ALGO_AES_256: + galg = GNUTLS_CIPHER_AES_256_GCM; + break; + default: + error_setg(errp, "Unsupported cipher algorithm %s with GCM mode", + QCryptoCipherAlgo_str(alg)); + return NULL; + } + + if (!qcrypto_cipher_validate_key_length(alg, QCRYPTO_CIPHER_MODE_GCM, + nkey, errp)) { + return NULL; + } + + ctx = g_new0(QCryptoCipherGnutls, 1); + ctx->base.driver = &gnutls_gcm_driver; + ctx->blocksize = 16; + + err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize cipher: %s", gnutls_strerror(err)); + g_free(ctx); + return NULL; + } + + return &ctx->base; +} + static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, QCryptoCipherMode mode, const uint8_t *key, @@ -234,6 +384,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN; int err; + if (mode == QCRYPTO_CIPHER_MODE_GCM) { + return qcrypto_gnutls_aes_gcm_ctx_new(alg, key, nkey, errp); + } + switch (mode) { case QCRYPTO_CIPHER_MODE_XTS: switch (alg) { From 69ddeb2fac7454daa6b5cd896cc91df96566ee25 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:32 +0000 Subject: [PATCH 151/627] tests/unit/test-crypto-cipher: Test AES-GCM mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercise the new GCM mode and the setaad/gettag helpers with the canonical AES-GCM test vectors from the GCM specification (McGrew & Viega, also NIST SP 800-38D): AES-128 and AES-256, with and without associated data. Each vector is run through encrypt (checking the ciphertext and the generated tag) and decrypt (checking the recovered plaintext and the recomputed tag). Signed-off-by: Jamin Lin Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-13-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/unit/test-crypto-cipher.c | 240 ++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index 1331d558cf..420c826df9 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -810,6 +810,230 @@ static void test_cipher_short_plaintext(void) qcrypto_cipher_free(cipher); } +typedef struct QCryptoCipherGcmTestData QCryptoCipherGcmTestData; +struct QCryptoCipherGcmTestData { + const char *path; + QCryptoCipherAlgo alg; + const char *key; + const char *iv; + /* associated data, or NULL for none */ + const char *aad; + const char *plaintext; + const char *ciphertext; + const char *tag; +}; + +/* + * AES-GCM test vectors from "The Galois/Counter Mode of Operation (GCM)" + * (McGrew & Viega, also NIST SP 800-38D), with a 96-bit IV and a 128-bit + * tag. Each entry's "Test case N" label is the numbered test case from that + * document (Appendix B / the GCM specification's test vectors). + */ +static QCryptoCipherGcmTestData gcm_test_data[] = { + { + /* Test case 2 */ + .path = "/crypto/cipher/aes-gcm-128-2", + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .key = "00000000000000000000000000000000", + .iv = "000000000000000000000000", + .plaintext = "00000000000000000000000000000000", + .ciphertext = "0388dace60b6a392f328c2b971b2fe78", + .tag = "ab6e47d42cec13bdf53a67b21257bddf", + }, + { + /* Test case 3 (no AAD) */ + .path = "/crypto/cipher/aes-gcm-128-3", + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .key = "feffe9928665731c6d6a8f9467308308", + .iv = "cafebabefacedbaddecaf888", + .plaintext = + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", + .ciphertext = + "42831ec2217774244b7221b784d0d49c" + "e3aa212f2c02a4e035c17e2329aca12e" + "21d514b25466931c7d8f6a5aac84aa05" + "1ba30b396a0aac973d58e091473f5985", + .tag = "4d5c2af327cd64a62cf35abd2ba6fab4", + }, + { + /* Test case 4 (with AAD) */ + .path = "/crypto/cipher/aes-gcm-128-4", + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .key = "feffe9928665731c6d6a8f9467308308", + .iv = "cafebabefacedbaddecaf888", + .aad = "feedfacedeadbeeffeedfacedeadbeefabaddad2", + .plaintext = + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + .ciphertext = + "42831ec2217774244b7221b784d0d49c" + "e3aa212f2c02a4e035c17e2329aca12e" + "21d514b25466931c7d8f6a5aac84aa05" + "1ba30b396a0aac973d58e091", + .tag = "5bc94fbc3221a5db94fae95ae7121a47", + }, + { + /* Test case 15 (AES-256, no AAD) */ + .path = "/crypto/cipher/aes-gcm-256-15", + .alg = QCRYPTO_CIPHER_ALGO_AES_256, + .key = + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + .iv = "cafebabefacedbaddecaf888", + .plaintext = + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", + .ciphertext = + "522dc1f099567d07f47f37a32a84427d" + "643a8cdcbfe5c0c97598a2bd2555d1aa" + "8cb08e48590dbb3da7b08b1056828838" + "c5f61e6393ba7a0abcc9f662898015ad", + .tag = "b094dac5d93471bdec1a502270e3cc6c", + }, + { + /* Test case 16 (AES-256, with AAD) */ + .path = "/crypto/cipher/aes-gcm-256-16", + .alg = QCRYPTO_CIPHER_ALGO_AES_256, + .key = + "feffe9928665731c6d6a8f9467308308" + "feffe9928665731c6d6a8f9467308308", + .iv = "cafebabefacedbaddecaf888", + .aad = "feedfacedeadbeeffeedfacedeadbeefabaddad2", + .plaintext = + "d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b39", + .ciphertext = + "522dc1f099567d07f47f37a32a84427d" + "643a8cdcbfe5c0c97598a2bd2555d1aa" + "8cb08e48590dbb3da7b08b1056828838" + "c5f61e6393ba7a0abcc9f662", + .tag = "76fc6ece0f4e1768cddf8853bb2d551b", + }, +}; + +static void test_cipher_gcm(const void *opaque) +{ + const QCryptoCipherGcmTestData *data = opaque; + g_autofree uint8_t *key = NULL; + g_autofree uint8_t *iv = NULL; + g_autofree uint8_t *aad = NULL; + g_autofree uint8_t *ptext = NULL; + g_autofree uint8_t *ctext = NULL; + g_autofree uint8_t *tagexp = NULL; + g_autofree uint8_t *out = NULL; + uint8_t tag[16]; + size_t nkey; + size_t niv; + size_t naad = 0; + size_t nptext; + size_t nctext; + size_t ntag; + QCryptoCipher *cipher; + + nkey = unhex_string(data->key, &key); + niv = unhex_string(data->iv, &iv); + nptext = unhex_string(data->plaintext, &ptext); + nctext = unhex_string(data->ciphertext, &ctext); + ntag = unhex_string(data->tag, &tagexp); + if (data->aad) { + naad = unhex_string(data->aad, &aad); + } + + g_assert_cmpint(nptext, ==, nctext); + g_assert_cmpint(ntag, ==, sizeof(tag)); + out = g_new0(uint8_t, nptext); + + /* Encrypt: plaintext -> ciphertext, then read back the tag. */ + cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM, + key, nkey, &error_abort); + g_assert(cipher != NULL); + g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0); + if (naad) { + g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0); + } + g_assert(qcrypto_cipher_encrypt(cipher, ptext, out, nptext, + &error_abort) == 0); + g_assert_cmpmem(out, nptext, ctext, nctext); + g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag), + &error_abort) == 0); + g_assert_cmpmem(tag, sizeof(tag), tagexp, ntag); + qcrypto_cipher_free(cipher); + + /* Decrypt: ciphertext -> plaintext, recomputed tag must match. */ + memset(out, 0, nptext); + cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM, + key, nkey, &error_abort); + g_assert(cipher != NULL); + g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0); + if (naad) { + g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0); + } + g_assert(qcrypto_cipher_decrypt(cipher, ctext, out, nctext, + &error_abort) == 0); + g_assert_cmpmem(out, nctext, ptext, nptext); + g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag), + &error_abort) == 0); + g_assert_cmpmem(tag, sizeof(tag), tagexp, ntag); + qcrypto_cipher_free(cipher); +} + +/* + * Corrupt one ciphertext byte and confirm the recomputed GCM tag no longer + * matches: the authentication tag must detect tampering. + */ +static void test_cipher_gcm_tamper(const void *opaque) +{ + const QCryptoCipherGcmTestData *data = opaque; + g_autofree uint8_t *key = NULL; + g_autofree uint8_t *iv = NULL; + g_autofree uint8_t *aad = NULL; + g_autofree uint8_t *ctext = NULL; + g_autofree uint8_t *tagexp = NULL; + g_autofree uint8_t *out = NULL; + uint8_t tag[16]; + size_t nkey; + size_t niv; + size_t naad = 0; + size_t nctext; + size_t ntag; + QCryptoCipher *cipher; + + nkey = unhex_string(data->key, &key); + niv = unhex_string(data->iv, &iv); + nctext = unhex_string(data->ciphertext, &ctext); + ntag = unhex_string(data->tag, &tagexp); + if (data->aad) { + naad = unhex_string(data->aad, &aad); + } + out = g_new0(uint8_t, nctext); + + /* Flip one ciphertext bit before decrypting. */ + ctext[0] ^= 0x01; + + cipher = qcrypto_cipher_new(data->alg, QCRYPTO_CIPHER_MODE_GCM, + key, nkey, &error_abort); + g_assert(cipher != NULL); + g_assert(qcrypto_cipher_setiv(cipher, iv, niv, &error_abort) == 0); + if (naad) { + g_assert(qcrypto_cipher_setaad(cipher, aad, naad, &error_abort) == 0); + } + g_assert(qcrypto_cipher_decrypt(cipher, ctext, out, nctext, + &error_abort) == 0); + g_assert(qcrypto_cipher_gettag(cipher, tag, sizeof(tag), + &error_abort) == 0); + g_assert(memcmp(tag, tagexp, ntag) != 0); + qcrypto_cipher_free(cipher); +} + int main(int argc, char **argv) { size_t i; @@ -828,6 +1052,22 @@ int main(int argc, char **argv) } } + for (i = 0; i < G_N_ELEMENTS(gcm_test_data); i++) { + if (qcrypto_cipher_supports(gcm_test_data[i].alg, + QCRYPTO_CIPHER_MODE_GCM)) { + g_autofree char *tamper = g_strdup_printf("%s/tamper", + gcm_test_data[i].path); + + g_test_add_data_func(gcm_test_data[i].path, &gcm_test_data[i], + test_cipher_gcm); + g_test_add_data_func(tamper, &gcm_test_data[i], + test_cipher_gcm_tamper); + } else { + g_printerr("# skip unsupported %s:gcm\n", + QCryptoCipherAlgo_str(gcm_test_data[i].alg)); + } + } + if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_256, QCRYPTO_CIPHER_MODE_CBC)) { g_test_add_func("/crypto/cipher/null-iv", From c98058bb3d3464be0923ffd5f88937ecc57a0cac Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:34 +0000 Subject: [PATCH 152/627] hw/misc/aspeed_hace: Support 64-bit DMA for the crypto command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2700 crypto engine addresses DRAM with 64 bits, supplying the high half of the source, destination and context addresses through HACE80, HACE84 and HACE88. Add those registers and a crypt_get_addr() helper that combines the low and high halves when the SoC has 64-bit DMA, mirroring the hash engine. SoCs without 64-bit DMA (AST2500/AST2600/AST1030) ignore the high registers, so their behaviour is unchanged. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-14-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index d84f7f9cec..0a6e2fa829 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -57,6 +57,11 @@ #define CRYPT_CTX_KEY_OFFSET 0x10 #define CRYPT_CTX_SIZE 0x30 +/* AST2700 64-bit DMA high address registers for the crypto command */ +#define R_CRYPT_SRC_HI (0x80 / 4) +#define R_CRYPT_DEST_HI (0x84 / 4) +#define R_CRYPT_CONTEXT_HI (0x88 / 4) + #define R_STATUS (0x1c / 4) #define HASH_IRQ BIT(9) #define CRYPT_IRQ BIT(12) @@ -670,6 +675,19 @@ static void crypt_be_add(uint8_t *ctr, size_t len, uint64_t add) } } +static uint64_t crypt_get_addr(AspeedHACEState *s, int reg, int reg_hi) +{ + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); + uint64_t addr; + + addr = deposit64(0, 0, 32, s->regs[reg]); + if (ahc->has_dma64) { + addr = deposit64(addr, 32, 32, s->regs[reg_hi]); + } + + return addr; +} + /* * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are * either single contiguous buffers (direct access mode) or scatter-gather @@ -717,7 +735,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) } /* Fetch the IV and key from the context buffer in DRAM. */ - ctx_addr = s->regs[R_CRYPT_CONTEXT]; + ctx_addr = crypt_get_addr(s, R_CRYPT_CONTEXT, R_CRYPT_CONTEXT_HI); if (address_space_read(&s->dram_as, ctx_addr, MEMTXATTRS_UNSPECIFIED, ctx, sizeof(ctx))) { qemu_log_mask(LOG_GUEST_ERROR, @@ -758,7 +776,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) dst_buf = g_malloc0(buf_len); /* Gather the source into the bounce buffer, per the selected mode. */ - src_addr = s->regs[R_CRYPT_SRC]; + src_addr = crypt_get_addr(s, R_CRYPT_SRC, R_CRYPT_SRC_HI); if (sg_mode) { status = crypt_prepare_sg(s, src_addr, src_buf, len, false); } else { @@ -794,7 +812,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) } /* Scatter the result back out, per the selected mode. */ - dst_addr = s->regs[R_CRYPT_DEST]; + dst_addr = crypt_get_addr(s, R_CRYPT_DEST, R_CRYPT_DEST_HI); if (sg_mode) { status = crypt_prepare_sg(s, dst_addr, dst_buf, len, true); } else { @@ -958,6 +976,15 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, case R_HASH_KEY_BUFF_HI: data &= ahc->key_hi_mask; break; + case R_CRYPT_SRC_HI: + data &= ahc->src_hi_mask; + break; + case R_CRYPT_DEST_HI: + data &= ahc->dest_hi_mask; + break; + case R_CRYPT_CONTEXT_HI: + data &= ahc->key_hi_mask; + break; default: break; } From 7a1a61b7ace9a4f7dad5cc3d4d69459029360961 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:35 +0000 Subject: [PATCH 153/627] hw/misc/aspeed_hace: Support the AES-GCM mode for the crypto command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the AES-GCM mode (HACE10[6:4] = 0b101) used by the AST2700 crypto engine: decode the GCM selection, read the 96-bit IV from the context buffer, operate on the exact data length (GCM handles a partial final block itself), and write the 128-bit authentication tag to the tag buffer (HACE18/HACE8C). The hardware GCM path is only used without associated data (the driver falls back to software otherwise), so AAD is not modelled and a non-zero HACE14 is reported as unimplemented. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-15-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 70 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 0a6e2fa829..23dacc9be8 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -31,6 +31,9 @@ /* HACE0C[27:0] holds the crypto data length */ #define CRYPT_DATA_LEN_MASK 0x0FFFFFFF #define R_CRYPT_CMD (0x10 / 4) +/* AES-GCM associated data length (HACE14) and tag write buffer (HACE18) */ +#define R_CRYPT_GCM_ADD_LEN (0x14 / 4) +#define R_CRYPT_GCM_TAG (0x18 / 4) /* Crypto engine command register (HACE10) bits */ #define CRYPT_CMD_ENCRYPT BIT(7) #define CRYPT_CMD_ISR_EN BIT(12) @@ -42,6 +45,7 @@ #define CRYPT_CMD_ECB (0x0 << 4) #define CRYPT_CMD_CBC (0x1 << 4) #define CRYPT_CMD_CTR (0x4 << 4) +#define CRYPT_CMD_GCM (0x5 << 4) /* AES key length HACE10[3:2] */ #define CRYPT_CMD_AES_KEY_LEN_MASK (0x3 << 2) #define CRYPT_CMD_AES256 (0x2 << 2) @@ -57,10 +61,15 @@ #define CRYPT_CTX_KEY_OFFSET 0x10 #define CRYPT_CTX_SIZE 0x30 +/* AES-GCM uses a 96-bit IV and a 128-bit authentication tag */ +#define CRYPT_GCM_IV_LEN 12 +#define CRYPT_GCM_TAG_LEN 16 + /* AST2700 64-bit DMA high address registers for the crypto command */ #define R_CRYPT_SRC_HI (0x80 / 4) #define R_CRYPT_DEST_HI (0x84 / 4) #define R_CRYPT_CONTEXT_HI (0x88 / 4) +#define R_CRYPT_GCM_TAG_HI (0x8c / 4) #define R_STATUS (0x1c / 4) #define HASH_IRQ BIT(9) @@ -596,6 +605,9 @@ static bool crypt_decode_cmd(uint32_t cmd, QCryptoCipherAlgo *alg, case CRYPT_CMD_CTR: *mode = QCRYPTO_CIPHER_MODE_CTR; break; + case CRYPT_CMD_GCM: + *mode = QCRYPTO_CIPHER_MODE_GCM; + break; default: return false; } @@ -689,11 +701,12 @@ static uint64_t crypt_get_addr(AspeedHACEState *s, int reg, int reg_hi) } /* - * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are - * either single contiguous buffers (direct access mode) or scatter-gather - * lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the IV/key come from - * the context buffer (HACE08). For CBC the resulting chaining IV is written - * back to the context buffer so the driver can continue the chain. + * Perform an AES/DES/3DES ECB/CBC/CTR or AES-GCM operation. The source and + * destination are either single contiguous buffers (direct access mode) or + * scatter-gather lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the + * IV/key come from the context buffer (HACE08). For CBC and CTR the resulting + * chaining state is written back to the context buffer so the driver can + * continue; for GCM the authentication tag is written to the tag buffer. */ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) { @@ -703,6 +716,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) g_autoptr(QCryptoCipher) cipher = NULL; g_autofree uint8_t *src_buf = NULL; g_autofree uint8_t *dst_buf = NULL; + uint8_t tag[CRYPT_GCM_TAG_LEN]; uint8_t ctx[CRYPT_CTX_SIZE]; Error *local_err = NULL; QCryptoCipherMode mode; @@ -711,10 +725,13 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) uint64_t ctx_addr; uint64_t src_addr; uint64_t dst_addr; + uint64_t tag_addr; + uint32_t aad_len; size_t iv_offset; size_t blocklen; size_t buf_len; size_t keylen; + size_t ivlen; bool status; if (len == 0) { @@ -734,6 +751,20 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) return; } + /* GCM uses a 96-bit IV; the block modes use a full-block IV. */ + ivlen = (mode == QCRYPTO_CIPHER_MODE_GCM) ? CRYPT_GCM_IV_LEN : blocklen; + + /* + * The hardware GCM path is only exercised without associated data (the + * driver falls back to software when there is any), so AAD is not modelled. + */ + aad_len = s->regs[R_CRYPT_GCM_ADD_LEN]; + if (mode == QCRYPTO_CIPHER_MODE_GCM && aad_len != 0) { + qemu_log_mask(LOG_UNIMP, + "%s: GCM associated data is not implemented\n", __func__); + return; + } + /* Fetch the IV and key from the context buffer in DRAM. */ ctx_addr = crypt_get_addr(s, R_CRYPT_CONTEXT, R_CRYPT_CONTEXT_HI); if (address_space_read(&s->dram_as, ctx_addr, MEMTXATTRS_UNSPECIFIED, @@ -758,7 +789,7 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) } if (mode != QCRYPTO_CIPHER_MODE_ECB && - qcrypto_cipher_setiv(cipher, ctx + iv_offset, blocklen, + qcrypto_cipher_setiv(cipher, ctx + iv_offset, ivlen, &local_err) < 0) { qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher setiv failed: %s\n", __func__, error_get_pretty(local_err)); @@ -769,9 +800,11 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) /* * Round the working buffers up to a whole block. Block modes are already * block-aligned; the stream-like CTR mode may leave a partial final block - * that the engine still processes a full block at a time. + * that the engine still processes a full block at a time. GCM handles a + * partial final block itself, so it operates on the exact length. */ - buf_len = QEMU_ALIGN_UP(len, blocklen); + buf_len = (mode == QCRYPTO_CIPHER_MODE_GCM) ? + len : QEMU_ALIGN_UP(len, blocklen); src_buf = g_malloc0(buf_len); dst_buf = g_malloc0(buf_len); @@ -855,6 +888,24 @@ static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd) "%s: Failed to write IV, addr=0x%" HWADDR_PRIx "\n", __func__, ctx_addr + iv_offset); } + } else if (mode == QCRYPTO_CIPHER_MODE_GCM) { + /* + * GCM authenticates the message and writes the resulting tag to the + * dedicated tag buffer (HACE18/HACE8C). + */ + if (qcrypto_cipher_gettag(cipher, tag, sizeof(tag), &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto cipher gettag failed: " + "%s\n", __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + tag_addr = crypt_get_addr(s, R_CRYPT_GCM_TAG, R_CRYPT_GCM_TAG_HI); + if (address_space_write(&s->dram_as, tag_addr, MEMTXATTRS_UNSPECIFIED, + tag, sizeof(tag))) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to write tag, addr=0x%" HWADDR_PRIx "\n", + __func__, tag_addr); + } } } @@ -899,9 +950,11 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, case R_CRYPT_SRC: case R_CRYPT_DEST: case R_CRYPT_CONTEXT: + case R_CRYPT_GCM_TAG: data &= ahc->src_mask; break; case R_CRYPT_DATA_LEN: + case R_CRYPT_GCM_ADD_LEN: data &= CRYPT_DATA_LEN_MASK; break; case R_HASH_SRC: @@ -980,6 +1033,7 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, data &= ahc->src_hi_mask; break; case R_CRYPT_DEST_HI: + case R_CRYPT_GCM_TAG_HI: data &= ahc->dest_hi_mask; break; case R_CRYPT_CONTEXT_HI: From baf15a2cf21c75ec9c3f068991cf28844887bf74 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:36 +0000 Subject: [PATCH 154/627] hw/misc/aspeed_hace: Enable the crypto command on the AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With direct/scatter-gather access, 64-bit DMA and AES-GCM all in place, the AST2700 crypto engine is now fully modelled. Drop its temporary interrupt-only workaround so the crypto command runs for real, like the other HACE variants. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-16-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 15 +-------------- include/hw/misc/aspeed_hace.h | 1 - 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 23dacc9be8..8de05a9d98 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -1005,14 +1005,7 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, break; } case R_CRYPT_CMD: - /* - * The AST2700 crypto engine needs 64-bit DMA and AES-GCM, which are - * added later; until then it keeps the temporary workaround of only - * raising the completion interrupt without running the command. - */ - if (!ahc->raise_crypt_interrupt_workaround) { - do_crypt_operation(s, data); - } + do_crypt_operation(s, data); /* Hardware raises the crypt interrupt once the command finishes. */ s->regs[R_STATUS] |= CRYPT_IRQ; @@ -1214,12 +1207,6 @@ static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data) ahc->dest_hi_mask = 0x00000003; ahc->key_hi_mask = 0x00000003; - /* - * Currently, it does not support the CRYPT command. Instead, it only - * sends an interrupt to notify the firmware that the crypt command - * has completed. It is a temporary workaround. - */ - ahc->raise_crypt_interrupt_workaround = true; ahc->has_dma64 = true; } diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index b5416b0cb5..9b0e7683fa 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -49,7 +49,6 @@ struct AspeedHACEClass { uint32_t key_mask; uint32_t hash_mask; uint64_t nr_regs; - bool raise_crypt_interrupt_workaround; uint32_t src_hi_mask; uint32_t dest_hi_mask; uint32_t key_hi_mask; From 0375f6498eee6188089924bb766c653492ff8857 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 11 Aug 2026 06:01:37 +0000 Subject: [PATCH 155/627] tests/qtest/aspeed-hace: Test the crypto command on the AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cover the AST2700 crypto engine, which drives 64-bit scatter-gather DMA and adds AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600. Add AES-128 and AES-256 GCM known-answer vectors (GCM specification / NIST SP 800-38D, no associated data) and a dedicated GCM runner that programs the tag buffer and reads the tag back, checking it after both encryption and decryption. Register the AST2700 with all four modes. Signed-off-by: Jamin Lin Reviewed-by: Kane Chen Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-17-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 163 +++++++++++++++++++++++++++++++- tests/qtest/aspeed-hace-utils.h | 1 + tests/qtest/ast2700-hace-test.c | 9 ++ 3 files changed, 172 insertions(+), 1 deletion(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index f582c88ef5..260eec043c 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -654,6 +654,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, #define HACE_CRYPTO_CONTEXT 0x08 #define HACE_CRYPTO_DATA_LEN 0x0c #define HACE_CRYPTO_CMD 0x10 +#define HACE_CRYPTO_GCM_ADD_LEN 0x14 +#define HACE_CRYPTO_GCM_TAG 0x18 /* Crypto command bits */ #define HACE_CMD_ENCRYPT BIT(7) @@ -666,7 +668,9 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, #define HACE_CMD_ECB (0x0 << 4) #define HACE_CMD_CBC (0x1 << 4) #define HACE_CMD_CTR (0x4 << 4) +#define HACE_CMD_GCM (0x5 << 4) #define HACE_CMD_AES128 (0x0 << 2) +#define HACE_CMD_AES256 (0x2 << 2) /* Context buffer layout: IV (DES at +8), key at +0x10 */ #define HACE_CTX_KEY_OFFSET 0x10 @@ -794,6 +798,59 @@ static const uint8_t tdes_ctr_ctext[8] = { static const uint8_t tdes_ctr_ivout[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* + * aes_gcm_tv_template[2] (AES-128) and [9] (AES-256), from the McGrew & Viega + * GCM spec (also NIST SP 800-38D), no AAD. Both cases share this plaintext/IV. + */ +static const uint8_t aes_gcm_ptext[64] = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }; +static const uint8_t aes_gcm_iv[12] = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }; + +/* aes_gcm_tv_template[2] (AES-128) */ +static const uint8_t aes128_gcm_key[16] = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; +static const uint8_t aes128_gcm_ctext[64] = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }; +static const uint8_t aes128_gcm_tag[16] = { + 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }; + +/* aes_gcm_tv_template[9] (AES-256) */ +static const uint8_t aes256_gcm_key[32] = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }; +static const uint8_t aes256_gcm_ctext[64] = { + 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }; +static const uint8_t aes256_gcm_tag[16] = { + 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }; + typedef struct CryptTest { QCryptoCipherMode mode; QCryptoCipherAlgo alg; @@ -801,10 +858,13 @@ typedef struct CryptTest { const uint8_t *iv_out; const uint8_t *ptext; const uint8_t *ctext; + /* expected GCM authentication tag, or NULL for non-AEAD modes */ + const uint8_t *tag; const uint8_t *key; const uint8_t *iv; const char *name; size_t keylen; + size_t taglen; /* algorithm | mode | key size selection */ uint32_t cmd; size_t ivlen; @@ -927,6 +987,36 @@ static const CryptTest crypt_tests[] = { .iv_out = tdes_ctr_ivout, .len = sizeof(tdes_ctr_ptext), }, + { + .name = "aes128-gcm", + .cmd = HACE_CMD_AES128 | HACE_CMD_GCM, + .alg = QCRYPTO_CIPHER_ALGO_AES_128, + .mode = QCRYPTO_CIPHER_MODE_GCM, + .key = aes128_gcm_key, + .keylen = sizeof(aes128_gcm_key), + .iv = aes_gcm_iv, + .ivlen = sizeof(aes_gcm_iv), + .ptext = aes_gcm_ptext, + .ctext = aes128_gcm_ctext, + .tag = aes128_gcm_tag, + .taglen = sizeof(aes128_gcm_tag), + .len = sizeof(aes_gcm_ptext), + }, + { + .name = "aes256-gcm", + .cmd = HACE_CMD_AES256 | HACE_CMD_GCM, + .alg = QCRYPTO_CIPHER_ALGO_AES_256, + .mode = QCRYPTO_CIPHER_MODE_GCM, + .key = aes256_gcm_key, + .keylen = sizeof(aes256_gcm_key), + .iv = aes_gcm_iv, + .ivlen = sizeof(aes_gcm_iv), + .ptext = aes_gcm_ptext, + .ctext = aes256_gcm_ctext, + .tag = aes256_gcm_tag, + .taglen = sizeof(aes256_gcm_tag), + .len = sizeof(aes_gcm_ptext), + }, }; /* DRAM offsets for the crypto test source, destination and context buffers. */ @@ -944,6 +1034,8 @@ static const CryptTest crypt_tests[] = { */ #define CRYPT_SG_FRAGS 3 #define CRYPT_SG_FRAG_STRIDE 0x1000 +/* DRAM offset for the AES-GCM authentication tag write buffer. */ +#define CRYPT_OFF_TAG 0x60000 /* Describes one registered crypto test (qtest_add_data_func() data pointer). */ typedef struct AspeedCryptoTest { @@ -964,6 +1056,8 @@ static uint32_t crypt_mode_flag(uint32_t cmd) return CRYPT_MODE_CBC; case HACE_CMD_CTR: return CRYPT_MODE_CTR; + case HACE_CMD_GCM: + return CRYPT_MODE_GCM; default: return 0; } @@ -1109,6 +1203,47 @@ static void crypt_run_sg(QTestState *s, uint32_t base, uint64_t dram, crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len); } +/* + * Run one AES-GCM operation in scatter-gather mode: like crypt_run_sg() but + * also program the tag write buffer (HACE18) with no associated data, and read + * the authentication tag back into @out_tag. + */ +static void crypt_run_gcm(QTestState *s, uint32_t base, uint64_t dram, + const CryptTest *t, bool encrypt, uint8_t *out, + uint8_t *out_tag) +{ + const uint8_t *in = encrypt ? t->ptext : t->ctext; + uint64_t src_sg = dram + CRYPT_OFF_SRC_SG; + uint64_t dst_sg = dram + CRYPT_OFF_DST_SG; + uint64_t ctx = dram + CRYPT_OFF_CTX; + uint32_t cmd = t->cmd | HACE_CMD_ISR_EN | HACE_CMD_SRC_SG_CTRL | + HACE_CMD_DST_SG_CTRL; + + if (encrypt) { + cmd |= HACE_CMD_ENCRYPT; + } + + crypt_write_ctx(s, ctx, t); + crypt_make_sg(s, dram, CRYPT_OFF_SRC, src_sg, in, t->len); + crypt_make_sg(s, dram, CRYPT_OFF_DST, dst_sg, NULL, t->len); + + qtest_writel(s, base + HACE_CRYPTO_SRC, (uint32_t)src_sg); + qtest_writel(s, base + HACE_CRYPTO_DEST, (uint32_t)dst_sg); + qtest_writel(s, base + HACE_CRYPTO_CONTEXT, (uint32_t)ctx); + qtest_writel(s, base + HACE_CRYPTO_DATA_LEN, t->len); + qtest_writel(s, base + HACE_CRYPTO_GCM_ADD_LEN, 0); + qtest_writel(s, base + HACE_CRYPTO_GCM_TAG, + (uint32_t)(dram + CRYPT_OFF_TAG)); + qtest_writel(s, base + HACE_CRYPTO_CMD, cmd); + + g_assert_cmphex(qtest_readl(s, base + HACE_STS) & HACE_CRYPTO_ISR, ==, + HACE_CRYPTO_ISR); + qtest_writel(s, base + HACE_STS, HACE_CRYPTO_ISR); + + crypt_gather_sg(s, dram, CRYPT_OFF_DST, out, t->len); + qtest_memread(s, dram + CRYPT_OFF_TAG, out_tag, t->taglen); +} + static void aspeed_test_crypto(const void *data) { const AspeedCryptoTest *c = data; @@ -1145,6 +1280,29 @@ static void aspeed_test_crypto(const void *data) qtest_quit(s); } +static void aspeed_test_crypto_gcm(const void *data) +{ + const AspeedCryptoTest *c = data; + const CryptTest *t = &crypt_tests[c->index]; + QTestState *s = qtest_init(c->machine); + uint8_t out[64]; + uint8_t tag[16]; + + g_assert_cmpuint(t->len, <=, sizeof(out)); + + /* Encrypt: ptext -> ctext, then check the authentication tag. */ + crypt_run_gcm(s, c->base, c->dram, t, true, out, tag); + g_assert_cmpmem(out, t->len, t->ctext, t->len); + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen); + + /* Decrypt: ctext -> ptext, the recomputed tag must match. */ + crypt_run_gcm(s, c->base, c->dram, t, false, out, tag); + g_assert_cmpmem(out, t->len, t->ptext, t->len); + g_assert_cmpmem(tag, t->taglen, t->tag, t->taglen); + + qtest_quit(s); +} + void aspeed_add_crypto_tests(const char *prefix, const char *machine, uint32_t base, uint64_t dram, uint32_t modes, bool sg) @@ -1152,6 +1310,7 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine, int i; for (i = 0; i < ARRAY_SIZE(crypt_tests); i++) { + bool is_gcm = crypt_tests[i].mode == QCRYPTO_CIPHER_MODE_GCM; g_autofree char *path = NULL; AspeedCryptoTest *t; @@ -1173,7 +1332,9 @@ void aspeed_add_crypto_tests(const char *prefix, const char *machine, t->dram = dram; t->index = i; t->sg = sg; - qtest_add_data_func_full(path, t, aspeed_test_crypto, g_free); + qtest_add_data_func_full(path, t, + is_gcm ? aspeed_test_crypto_gcm : + aspeed_test_crypto, g_free); } } diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index 82b0b3f93d..a5601a3d65 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -86,6 +86,7 @@ enum { CRYPT_MODE_ECB = 1 << 0, CRYPT_MODE_CBC = 1 << 1, CRYPT_MODE_CTR = 1 << 2, + CRYPT_MODE_GCM = 1 << 3, }; /* diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c index 508a34dd6c..3f0217d635 100644 --- a/tests/qtest/ast2700-hace-test.c +++ b/tests/qtest/ast2700-hace-test.c @@ -94,5 +94,14 @@ int main(int argc, char **argv) qtest_add_func("ast2700/hace/sha384_accum", test_sha384_accum_ast2700); qtest_add_func("ast2700/hace/sha256_accum", test_sha256_accum_ast2700); + /* + * The AST2700 crypto engine uses scatter-gather with 64-bit DMA and adds + * AES-GCM on top of the ECB/CBC/CTR modes shared with the AST2600. + */ + aspeed_add_crypto_tests("ast2700", "-machine ast2700-evb", 0x12070000, + 0x400000000, + CRYPT_MODE_ECB | CRYPT_MODE_CBC | CRYPT_MODE_CTR | + CRYPT_MODE_GCM, true); + return g_test_run(); } From 8b6405a493a2106eaa3893237595afb4759ca498 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 21 Jul 2026 10:14:57 -0300 Subject: [PATCH 156/627] docs: Add security considerations for migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the security considerations that are unique to migration and that do not already fall into one of the other categories. Some aspects are better framed as security architecture considerations, so extend that section to mention TLS and clarify that disk images and guest network also need to be isolated from other processes, not just other guests. Reviewed-by: Peter Xu Reviewed-by: Daniel P. Berrangé Signed-off-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260721131457.3062767-1-farosas@suse.de Signed-off-by: Peter Xu --- docs/system/security.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/system/security.rst b/docs/system/security.rst index 52bbf0cc7a..af626a4230 100644 --- a/docs/system/security.rst +++ b/docs/system/security.rst @@ -133,6 +133,16 @@ an issue as a normal bug. that affect the level 0 QEMU process. While these bugs should be fixed, they will not be triaged as security flaws at this time. +* **migration/snapshots**. Migration failures and snapshot load + failures are considered part of normal operation as long as the + source virtual machine and savevm file, respectively, are still + functional. Aborting the QEMU process at the migration/snapshot + destination is similarly not considered a security issue. The + migration stream is assumed to be secure as long as the design + principles described in the Architecture section are held, in + which case plain manipulation of the stream is not considered as + an attack vector. + * **low severity impact**. As a catch all rule, issues which are judged to have a "low" severity impact on the system will usually not justify handling as security bugs, nor assignment @@ -159,10 +169,11 @@ could allow malicious guests to gain code execution in QEMU. At this point the guest has escaped the virtual machine and is able to act in the context of the QEMU process on the host. -Guests often interact with other guests and share resources with them. A -malicious guest must not gain control of other guests or access their data. -Disk image files and network traffic must be protected from other guests unless -explicitly shared between them by the user. +Guests often interact with other guests and share resources with them. +A malicious guest must not gain control of other guests or access +their data. Disk image files and network traffic must be protected +from other guests, users and processes unless explicitly shared with +them by the user. Principle of Least Privilege '''''''''''''''''''''''''''' @@ -223,6 +234,9 @@ Some Linux distros already ship with UNIX groups for these devices by default. system calls that are not needed by QEMU, thereby reducing the host kernel attack surface. +- Transport Layer Security (TLS) protocol can be used to ensure authenticity and + encryption of the live migration connection where the network is untrusted. + Sensitive configurations ------------------------ From 403ccbc55d7bfdef41998fbe26967b017663c3eb Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Tue, 28 Jul 2026 01:59:03 -0700 Subject: [PATCH 157/627] migration/cpr: Add HMP support for cpr-transfer Currently the cpr-transfer source QEMU instance cannot be driven entirely via HMP. The source must use QMP in order to specify both the main migration channel and the CPR channel. Extend the HMP migrate command with an optional CPR channel URI. When the migration mode is cpr-transfer, HMP uses this URI to build a CPR MigrationChannel in addition to the main migration channel. The new option is rejected unless the migration mode is cpr-transfer, so existing HMP migrate usage is unchanged. For example, source QEMU HMP commands can be something like below. The "-c unix:/tmp/cpr.sock" is for CPR URI. (qemu) migrate_set_parameter mode cpr-transfer (qemu) migrate -c unix:/tmp/cpr.sock tcp:0:50002 Signed-off-by: Dongli Zhang Reviewed-by: Dr. David Alan Gilbert Acked-by: Maciej S. Szmigiero Link: https://lore.kernel.org/r/20260728085903.173265-1-dongli.zhang@oracle.com Signed-off-by: Peter Xu --- hmp-commands.hx | 12 ++++++++---- migration/migration-hmp-cmds.c | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 7ae2468a3d..7f43cf537f 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -928,16 +928,17 @@ ERST { .name = "migrate", - .args_type = "detach:-d,resume:-r,uri:s", - .params = "[-d] [-r] uri", + .args_type = "detach:-d,resume:-r,uri-cpr:-cs,uri:s", + .params = "[-d] [-r] [-c uri-cpr] uri", .help = "migrate to URI (using -d to not wait for completion)" - "\n\t\t\t -r to resume a paused postcopy migration", + "\n\t\t\t -r to resume a paused postcopy migration" + "\n\t\t\t -c to specify a CPR URI for cpr-transfer mode", .cmd = hmp_migrate, }, SRST -``migrate [-d] [-r]`` *uri* +``migrate [-d] [-r] [-c uri-cpr]`` *uri* Migrate the VM to *uri*. ``-d`` @@ -945,6 +946,9 @@ SRST query an ongoing migration process, use "info migrate". ``-r`` Resume a paused postcopy migration. + ``-c`` *uri-cpr* + Specify the CPR URI for cpr-transfer mode. It must be a UNIX domain + socket. ERST { diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index b04fc4489f..b5eb27467c 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -837,9 +837,11 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) bool detach = qdict_get_try_bool(qdict, "detach", false); bool resume = qdict_get_try_bool(qdict, "resume", false); const char *uri = qdict_get_str(qdict, "uri"); + const char *uri_cpr = qdict_get_try_str(qdict, "uri-cpr"); Error *err = NULL; g_autoptr(MigrationChannelList) caps = NULL; g_autoptr(MigrationChannel) channel = NULL; + g_autoptr(MigrationChannel) channel_cpr = NULL; if (!migrate_uri_parse(uri, &channel, &err)) { hmp_handle_error(mon, err); @@ -847,6 +849,22 @@ void hmp_migrate(Monitor *mon, const QDict *qdict) } QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel)); + if (uri_cpr) { + if (migrate_mode() != MIG_MODE_CPR_TRANSFER) { + error_setg(&err, "-c can only be used in cpr-transfer mode"); + hmp_handle_error(mon, err); + return; + } + + if (!migrate_uri_parse(uri_cpr, &channel_cpr, &err)) { + hmp_handle_error(mon, err); + return; + } + + channel_cpr->channel_type = MIGRATION_CHANNEL_TYPE_CPR; + QAPI_LIST_PREPEND(caps, g_steal_pointer(&channel_cpr)); + } + qmp_migrate(NULL, true, caps, true, resume, &err); if (hmp_handle_error(mon, err)) { return; From d2d7e63da8e9a6ac4bb23e3ecc1de468530c9437 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 28 Jul 2026 13:17:29 +1000 Subject: [PATCH 158/627] system/memory: Use memmove() for directly accessible regions Similar to what's done in commit 4a73aee88140 ("softmmu: Use memmove in flatview_write_continue"), there are more sites where the overlapping source and destination buffer are allowed for the directly accessible regions. Use memmove() in those sites, listed as below. hw/remote/vfio-user-obj.c::vfu_object_mr_rw include/system/memory.h::address_space_read system/physmem.c::flatview_read_continue_step Signed-off-by: Gavin Shan Reviewed-by: Peter Maydell Reviewed-by: Peter Xu Link: https://lore.kernel.org/r/20260728031731.286666-2-gshan@redhat.com Signed-off-by: Peter Xu --- hw/remote/vfio-user-obj.c | 4 ++-- include/system/memory.h | 2 +- system/physmem.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index 87fa7b6572..ea50270628 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -375,9 +375,9 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset, ram_ptr = memory_region_get_ram_ptr(mr); if (is_write) { - memcpy((ram_ptr + offset), buf, size); + memmove((ram_ptr + offset), buf, size); } else { - memcpy(buf, (ram_ptr + offset), size); + memmove(buf, (ram_ptr + offset), size); } return 0; diff --git a/include/system/memory.h b/include/system/memory.h index 2192fc9bdc..336d4e84a6 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2741,7 +2741,7 @@ MemTxResult address_space_read(const AddressSpace *as, hwaddr addr, mr = flatview_translate(fv, addr, &addr1, &l, false, attrs); if (len == l && memory_access_is_direct(mr, false, attrs)) { ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - memcpy(buf, ptr, len); + memmove(buf, ptr, len); } else { result = flatview_read_continue(fv, addr, attrs, buf, len, addr1, l, mr); diff --git a/system/physmem.c b/system/physmem.c index c21ea92915..2c42e365cb 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3363,7 +3363,7 @@ static MemTxResult flatview_read_continue_step(MemTxAttrs attrs, uint8_t *buf, uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l, false, false); - memcpy(buf, ram_ptr, *l); + memmove(buf, ram_ptr, *l); return MEMTX_OK; } From bec5e7c71cc9770a900dac6930d076fe7ee9e57b Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 28 Jul 2026 13:17:30 +1000 Subject: [PATCH 159/627] system/memory: Use qemu_ram_move() for directly accessible regions All ram device regions were turned to be indirectly accessible by commit 4a2e242bbb ("memory: Don't use memcpy for ram_device regions"). This leads to guest hang on attempt to build 'cuda-samples' as reported by Julia. The guest is started by the following command lines, with GH100 GPU card passed from the host. host$ lspci | grep GH100 0009:01:00.0 3D controller: NVIDIA Corporation GH100 [GH200 120GB / 480GB] (rev a1) host$ /home/sandbox/gavin/qemu.main/build/qemu-system-aarch64 \ -machine virt,gic-version=host,ras=on,highmem-mmio-size=4T \ -accel kvm -cpu host -smp cpus=48 -m size=8G \ -drive file=/home/gavin/sandbox/images/disk.qcow2,if=none,id=d0 \ -device virtio-blk-pci,id=vb0,bus=pcie.0,drive=d0,num-queues=4 \ -device vfio-pci-nohotplug,host=0009:01:00.0,bus=pcie.1.0 : guest$ cd cuda-samples/build guest$ make -j 20 clean guest$ make -j 20 : [ 54%] Linking CUDA executable graphMemoryNodes [ 54%] Built target graphMemoryNodes guest$ qemu-system-aarch64: virtio: bogus descriptor or out of resources [ 555.814025] virtio_blk virtio0: [vda] new size: 268435456 512-byte logical blocks (137 GB/128 GiB) When the GPU's driver (NVidia open driver) is loaded on guest bootup, the memory blocks residing in the PCI BAR#4 of the GH100 GPU card can be presented to the guest through memory hot-add. The page cache can then be allocated from the hot added memory blocks when cuda-samples is being built. Afterwards, the page cache is sent to QEMU's virtio-blk device as part of the DMA request, the bounce buffer has to be used to accomodate the request as the corresponding memory region (MemoryRegion) is an indirectly accessible ram device region in qemu. However, the max bounce bufer size is only 4096 bytes by default and that is exhausted quickly, leading to a reset on the virtio-blk device and frozen guest eventually. QEMU ==== virtio_blk_handle_output virtio_blk_handle_vq virtio_blk_get_request virtqueue_pop virtqueue_split_pop virtqueue_map_desc address_space_map memory_access_is_direct # Return false memory_region_supports_direct_access (qemu) info mtree memory-region: pci_bridge_pci 0000000000000000-ffffffffffffffff (prio 0, container): pci_bridge_pci 0000042000000000-0000043fffffffff (prio 1, i/o): 0009:01:00.0 base BAR 4 0000042000000000-0000043fffffffff (prio 0, i/o): 0009:01:00.0 BAR 4 0000042000000000-000004379fffffff (prio 0, ramd): 0009:01:00.0 BAR 4 mmaps[0] This adds qemu_ram_move() where the aligned and small-sized accesses are handled by qatomics, and fall back to memmove() otherwise. The memove() for the directly accessible regions is replaced by qemu_ram_move() so that the issue covered by commit 4a2e242bbb (MMIO access instructions were optimized to SSE instructions) is fixed. This makes 'ram_device_mem_ops' redundant, paving the way to revert that commit to make the ram device region directly accessible again in the next patch. Besides, this also fixes the issue of the unexpected frozen reception on e1000 NIC in the scenario of DPDK due to the wrong Rx queue full indication caused by the following memcpy(), which is turned to 3 consective 'strb' instructions to the same location by glibc-2.24+ for aarch64. With this applied, the syntax of one-byte store is strictly ensured by a one-byte qatomic set. QEMU ==== e1000_receive_iov pci_dma_write pci_dma_rw dma_memory_rw dma_memory_rw_relaxed address_space_rw address_space_write flatview_write flatview_write_continue flatview_write_continue_step memcpy # 3 consective 'strb' instructions Reported-by: Julia Graham Reported-by: Liu Gang Reported-by: Ding Hui Suggested-by: Michael S. Tsirkin Suggested-by: Peter Xu Suggested-by: Richard Henderson Suggested-by: Peter Maydell Signed-off-by: Gavin Shan Reviewed-by: Peter Maydell Link: https://lore.kernel.org/r/20260728031731.286666-3-gshan@redhat.com [peterx: remove src==dst check, fix doc, enhance comments, per PeterM, add R-b] Signed-off-by: Peter Xu --- hw/remote/vfio-user-obj.c | 4 ++-- include/system/memory.h | 35 +++++++++++++++++++++++++++- system/physmem.c | 48 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index ea50270628..a0498d218f 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -375,9 +375,9 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset, ram_ptr = memory_region_get_ram_ptr(mr); if (is_write) { - memmove((ram_ptr + offset), buf, size); + qemu_ram_move((ram_ptr + offset), buf, size); } else { - memmove(buf, (ram_ptr + offset), size); + qemu_ram_move(buf, (ram_ptr + offset), size); } return 0; diff --git a/include/system/memory.h b/include/system/memory.h index 336d4e84a6..4de5bf2577 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2668,6 +2668,39 @@ void address_space_register_map_client(AddressSpace *as, QEMUBH *bh); void address_space_unregister_map_client(AddressSpace *as, QEMUBH *bh); /* Internal functions, part of the implementation of address_space_read. */ + +/** + * qemu_ram_move: move data from or to ramblock + * + * @dst: destination where the data is moved to + * @src: source where the data is moved from + * @n: length of data to be moved + * + * Move @n bytes from @src to @dst, the memory areas may overlap. This + * provides the same semantics as memmove(), plus an additional stronger + * guarantee: if @n is 1, 2 or 4 or 8 bytes, and @src and @dst are both + * naturally aligned for that access size, then both the load and the store + * will be done as a single atomic access (with the semantics of + * qatomic_read() and qatomic_set()). + * + * This is the underlying function that we use to implement accesses by + * a guest vCPU or a device DMA operation to a ram block. The atomic + * guarantee is needed for two major cases: (A) When the ram block is + * backed by a PCI BAR passed through from a host device (and so it might + * be hardware registers that must be accessed exactly once at the right + * width); (B) When an emulated device updates a data structure shared in + * guest memory with guest software (e.g. a network device's set of tx and + * rx descriptor blocks), if a write to memory is accidentally performed + * multiple times then it can break the guest code when it busy polls the + * guest memory. + * + * We don't attempt to perform the exact access when it would be unaligned + * because this can't be done on all host architectures. Although this is + * strictly speaking not doing what would happen on real hardware, we don't + * think there are going to be situations where that matters in practice. + */ +void qemu_ram_move(void *dst, const void *src, size_t n); + MemTxResult address_space_read_full(const AddressSpace *as, hwaddr addr, MemTxAttrs attrs, void *buf, hwaddr len); MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr, @@ -2741,7 +2774,7 @@ MemTxResult address_space_read(const AddressSpace *as, hwaddr addr, mr = flatview_translate(fv, addr, &addr1, &l, false, attrs); if (len == l && memory_access_is_direct(mr, false, attrs)) { ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - memmove(buf, ptr, len); + qemu_ram_move(buf, ptr, len); } else { result = flatview_read_continue(fv, addr, attrs, buf, len, addr1, l, mr); diff --git a/system/physmem.c b/system/physmem.c index 2c42e365cb..2f37cbeb07 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -3158,6 +3158,50 @@ void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size) invalidate_and_set_dirty(mr, addr, size); } +void qemu_ram_move(void *dst, const void *src, size_t n) +{ + uintptr_t test, len; + + if (n == 0) { + return; + } + + /* + * Calculate "the lowest set bit" over @src, @dst and @n, result put + * into @len (which guarantees a power-of-two). With that and the + * later check (len!=n), it makes sure that we will only do the atomic + * ops when: + * + * (1) @n is a power-of-two + * (2) @src and @dst addresses are both aligned to @n + */ + test = (uintptr_t)src | (uintptr_t)dst | n; + len = test & -test; + + /* Overlapping buffers, unaligned or oversized access */ + if (n > 8 || len != n) { + memmove(dst, src, n); + return; + } + + switch (len) { + case 1: + qatomic_set((uint8_t *)dst, qatomic_read((uint8_t *)src)); + break; + case 2: + qatomic_set((uint16_t *)dst, qatomic_read((uint16_t *)src)); + break; + case 4: + qatomic_set((uint32_t *)dst, qatomic_read((uint32_t *)src)); + break; + case 8: + qatomic_set((uint64_t *)dst, qatomic_read((uint64_t *)src)); + break; + default: + g_assert_not_reached(); + } +} + int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) { unsigned access_size_max = mr->ops->valid.max_access_size; @@ -3270,7 +3314,7 @@ static MemTxResult flatview_write_continue_step(MemTxAttrs attrs, uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l, false, true); - memmove(ram_ptr, buf, *l); + qemu_ram_move(ram_ptr, buf, *l); invalidate_and_set_dirty(mr, mr_addr, *l); return MEMTX_OK; @@ -3363,7 +3407,7 @@ static MemTxResult flatview_read_continue_step(MemTxAttrs attrs, uint8_t *buf, uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l, false, false); - memmove(buf, ram_ptr, *l); + qemu_ram_move(buf, ram_ptr, *l); return MEMTX_OK; } From ff77a515113f052cc5fc571b6a328142fdfcf220 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 28 Jul 2026 13:17:31 +1000 Subject: [PATCH 160/627] system/memory: Make ram device region directly accessible This basically reverts 4a2e242bbb30 ("memory: Don't use memcpy for ram_device regions") to make ram device region directly accessible again. With this, the bounce buffer is bypassed in address_space_map() when a ram device region is involved, potentially avoid to overrun the (small) bounce buffer. Reported-by: Julia Graham Suggested-by: Michael S. Tsirkin Suggested-by: Peter Xu Suggested-by: Richard Henderson Suggested-by: Peter Maydell Signed-off-by: Gavin Shan Reviewed-by: Peter Maydell Link: https://lore.kernel.org/r/20260728031731.286666-4-gshan@redhat.com Signed-off-by: Peter Xu --- include/system/memory.h | 11 ++--------- system/memory.c | 41 +---------------------------------------- system/trace-events | 2 -- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/include/system/memory.h b/include/system/memory.h index 4de5bf2577..1dc761058f 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -2718,15 +2718,8 @@ static inline bool memory_region_supports_direct_access(const MemoryRegion *mr) if (memory_region_is_romd(mr)) { return true; } - if (!memory_region_is_ram(mr)) { - return false; - } - /* - * RAM DEVICE regions can be accessed directly using memcpy, but it might - * be MMIO and access using mempy can be wrong (e.g., using instructions not - * intended for MMIO access). So we treat this as IO. - */ - return !memory_region_is_ram_device(mr); + + return memory_region_is_ram(mr); } static inline bool memory_access_is_direct(const MemoryRegion *mr, diff --git a/system/memory.c b/system/memory.c index 5fc36708ec..da710bbade 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1364,43 +1364,6 @@ const MemoryRegionOps unassigned_mem_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static uint64_t memory_region_ram_device_read(void *opaque, - hwaddr addr, unsigned size) -{ - MemoryRegion *mr = opaque; - uint64_t data = ldn_he_p(mr->ram_block->host + addr, size); - - trace_memory_region_ram_device_read(get_cpu_index(), mr, addr, data, size); - - return data; -} - -static void memory_region_ram_device_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - MemoryRegion *mr = opaque; - - trace_memory_region_ram_device_write(get_cpu_index(), mr, addr, data, size); - - stn_he_p(mr->ram_block->host + addr, size, data); -} - -static const MemoryRegionOps ram_device_mem_ops = { - .read = memory_region_ram_device_read, - .write = memory_region_ram_device_write, - .endianness = HOST_BIG_ENDIAN ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = true, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = true, - }, -}; - bool memory_region_access_valid(MemoryRegion *mr, hwaddr addr, unsigned size, @@ -1692,10 +1655,8 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner, const char *name, uint64_t size, void *ptr) { - memory_region_init_io(mr, owner, &ram_device_mem_ops, mr, name, size); - mr->ram = true; + memory_region_init_ram_ptr(mr, owner, name, size, ptr); mr->ram_device = true; - memory_region_set_ram_ptr(mr, size, ptr); } void memory_region_init_alias(MemoryRegion *mr, Object *owner, diff --git a/system/trace-events b/system/trace-events index 51b4a4679a..d483b31419 100644 --- a/system/trace-events +++ b/system/trace-events @@ -20,8 +20,6 @@ memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, u memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size, const char *name) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u name '%s'" memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u" -memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" -memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_sync_dirty(const char *mr, const char *listener, int global) "mr '%s' listener '%s' synced (global=%d)" flatview_new(void *view, void *root) "%p (root %p)" flatview_destroy(void *view, void *root) "%p (root %p)" From bdfe26faca7b7c8daa7895783d55ec6d05164880 Mon Sep 17 00:00:00 2001 From: Sam Heney Date: Thu, 30 Jul 2026 23:59:44 +0100 Subject: [PATCH 161/627] tests/qtest/migration: Only build tls_no_hostname test with TASN1 The test_precopy_tcp_tls_no_hostname test and its start hook use TestMigrateTLSX509 and migrate_hook_start_tls_x509_common(), which are only defined when CONFIG_TASN1 is set. This means building with gnutls enabled but libtasn1 unavailable fails: ../tests/qtest/migration/tls-tests.c: In function 'migrate_hook_start_tls_x509_no_host': ../tests/qtest/migration/tls-tests.c:510:5: error: unknown type name 'TestMigrateTLSX509' Guard the test with CONFIG_TASN1 like the other x509 tests. Fixes: df9c38b19af8 ("tests/qtest/migration: Add a NULL parameters test for TLS") Signed-off-by: Sam Heney Link: https://lore.kernel.org/r/5f24de0e-49af-45a7-927f-f79b203bb335@app.fastmail.com Signed-off-by: Peter Xu --- tests/qtest/migration/tls-tests.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index 827cc7bcf8..9bdb1165af 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -492,6 +492,7 @@ static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args) test_precopy_common(args); } +#ifdef CONFIG_TASN1 static void * migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to) { @@ -519,7 +520,6 @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args) test_precopy_common(args); } -#ifdef CONFIG_TASN1 static void test_precopy_tcp_tls_x509_default_host(char *name, MigrateCommon *args) { @@ -719,8 +719,10 @@ void migration_test_add_tls(MigrationTestEnv *env) migration_test_add("/migration/precopy/tcp/no-tls", test_precopy_tcp_no_tls); +#ifdef CONFIG_TASN1 migration_test_add("/migration/precopy/tcp/tls/no-hostname", test_precopy_tcp_tls_no_hostname); +#endif /* CONFIG_TASN1 */ migration_test_add("/migration/precopy/unix/tls/psk", test_precopy_unix_tls_psk); From e8d693e12af9cbb89d724baadfcc08559669e279 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 11 Aug 2026 14:31:44 -0400 Subject: [PATCH 162/627] tests/qtest: Do not use versioned pc-q35-5.2 machine anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of QEMU v11.1.0, the v5.2.0 machines are not usable anymore. Use the latest x86 q35 machine instead, otherwise we get: $ qemu-system-x86_64 -M pc-q35-5.2 qemu-system-x86_64: unsupported machine type: "pc-q35-5.2" Use -machine help to list supported machines See commit a35f8577a07 ("include/hw: add macros for deprecation & removal of versioned machines") and f59ee044067 ("include/hw/boards: cope with dev/rc versions in deprecation checks") for explanation on automatically removed versioned machines. This commit message is taken from commit 9eef3854d309 ("tests/qtest: Do not use versioned pc-q35-5.0 machine anymore") by Philippe Mathieu-Daudé . Cc: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Peter Maydell Message-ID: <20260811183144.190135-1-stefanha@redhat.com> Signed-off-by: Stefan Hajnoczi --- tests/qtest/fuzz-virtio-scsi-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/fuzz-virtio-scsi-test.c b/tests/qtest/fuzz-virtio-scsi-test.c index e37b48b2cc..102a5ccb67 100644 --- a/tests/qtest/fuzz-virtio-scsi-test.c +++ b/tests/qtest/fuzz-virtio-scsi-test.c @@ -19,7 +19,7 @@ static void test_mmio_oob_from_memory_region_cache(void) { QTestState *s; - s = qtest_init("-M pc-q35-5.2 -m 512M " + s = qtest_init("-M q35 -m 512M " "-device virtio-scsi,num_queues=8,addr=03.0 "); qtest_outl(s, 0xcf8, 0x80001811); From 197870349f2b6e5bb3ed89bf1a949ecaca09cd78 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:06 -0700 Subject: [PATCH 163/627] hw/hexagon: add hex-subsys The virt and DSP machine models build the same core subsystem, let's abstract out that part. Start with the DDR and config table ROM setup. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-2-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hex-subsys.c | 32 ++++++++++++++++++++++++++++++++ hw/hexagon/hexagon_dsp.c | 17 ++--------------- hw/hexagon/meson.build | 1 + hw/hexagon/virt.c | 14 ++------------ include/hw/hexagon/hex-subsys.h | 17 +++++++++++++++++ 5 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 hw/hexagon/hex-subsys.c create mode 100644 include/hw/hexagon/hex-subsys.h diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c new file mode 100644 index 0000000000..d146ee0c07 --- /dev/null +++ b/hw/hexagon/hex-subsys.c @@ -0,0 +1,32 @@ +/* + * Hexagon subsystem helpers shared between the machine models. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/hexagon/hex-subsys.h" +#include "hw/core/loader.h" +#include "system/address-spaces.h" + +void hex_subsys_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + MachineState *machine = MACHINE(hms); + MemoryRegion *sysmem = get_system_memory(); + + /* Main DDR at the reset vector. */ + memory_region_init_ram(&hms->ram, NULL, "ddr.ram", machine->ram_size, + &error_fatal); + memory_region_add_subregion(sysmem, 0x0, &hms->ram); + + /* Config-table ROM and the blob that backs it. */ + memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom", + sizeof(m_cfg->cfgtable), &error_fatal); + memory_region_add_subregion(sysmem, m_cfg->cfgbase, &hms->cfgtable_rom); + rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable, + sizeof(m_cfg->cfgtable), m_cfg->cfgbase, + &address_space_memory); +} diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index aa49399322..f94f7fd4e1 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -14,6 +14,7 @@ #include "hw/core/boards.h" #include "hw/core/qdev-properties.h" #include "hw/hexagon/hexagon.h" +#include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" @@ -108,7 +109,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, { HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(machine); HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(machine); - MemoryRegion *address_space; DeviceState *glob_regs_dev; DeviceState *tlb_dev; @@ -120,16 +120,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, machine->enable_graphics = 0; - address_space = get_system_memory(); - - memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom", - sizeof(m_cfg->cfgtable), &error_fatal); - memory_region_add_subregion(address_space, m_cfg->cfgbase, - &hms->cfgtable_rom); - - memory_region_init_ram(&hms->ram, NULL, "ddr.ram", - machine->ram_size, &error_fatal); - memory_region_add_subregion(address_space, 0x0, &hms->ram); + hex_subsys_create(hms, m_cfg); glob_regs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG); object_property_add_child(OBJECT(machine), "global-regs", @@ -162,10 +153,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, OBJECT(tlb_dev), &error_fatal); qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal); } - - rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable, - sizeof(m_cfg->cfgtable), m_cfg->cfgbase, - &address_space_memory); } static void init_mc(MachineClass *mc) diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build index bade3a3292..720a5d54dc 100644 --- a/hw/hexagon/meson.build +++ b/hw/hexagon/meson.build @@ -1,6 +1,7 @@ hexagon_ss = ss.source_set() hexagon_ss.add(files('hexagon_tlb.c')) hexagon_ss.add(files('hexagon_globalreg.c')) +hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c')) hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c')) hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c')) diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index b750472502..ad0bc4f132 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -13,6 +13,7 @@ #include "hw/core/clock.h" #include "hw/core/sysbus-fdt.h" #include "hw/hexagon/hexagon.h" +#include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" @@ -244,9 +245,7 @@ static void virt_init(MachineState *ms) vms->apb_clk = clock_new(OBJECT(ms), "apb-pclk"); clock_set_hz(vms->apb_clk, 24000000); - memory_region_init_ram(&vms->parent_obj.ram, NULL, "ddr.ram", - ms->ram_size, &error_fatal); - memory_region_add_subregion(vms->sys, 0x0, &vms->parent_obj.ram); + hex_subsys_create(&vms->parent_obj, m_cfg); if (m_cfg->l2tcm_size) { memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size, @@ -255,11 +254,6 @@ static void virt_init(MachineState *ms) &vms->tcm); } - memory_region_init_rom(&vms->parent_obj.cfgtable_rom, NULL, - "config_table.rom", sizeof(m_cfg->cfgtable), - &error_fatal); - memory_region_add_subregion(vms->sys, m_cfg->cfgbase, - &vms->parent_obj.cfgtable_rom); fdt_add_hvx(vms, m_cfg); gsregs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG); @@ -302,10 +296,6 @@ static void virt_init(MachineState *ms) clk_phandle = fdt_add_clocks(vms); fdt_add_uart(vms, VIRT_UART0, clk_phandle); - rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable, - sizeof(m_cfg->cfgtable), m_cfg->cfgbase, - &address_space_memory); - hexagon_load_fdt(vms); } diff --git a/include/hw/hexagon/hex-subsys.h b/include/hw/hexagon/hex-subsys.h new file mode 100644 index 0000000000..6bcde303f2 --- /dev/null +++ b/include/hw/hexagon/hex-subsys.h @@ -0,0 +1,17 @@ +/* + * Hexagon subsystem helpers shared between the machine models. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_HEXAGON_HEX_SUBSYS_H +#define HW_HEXAGON_HEX_SUBSYS_H + +#include "hw/hexagon/hexagon.h" + +/* Create the subsystem shared by every Hexagon machine. */ +void hex_subsys_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg); + +#endif /* HW_HEXAGON_HEX_SUBSYS_H */ From 024fff8b8160e20621731502213e1a077567b839 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:07 -0700 Subject: [PATCH 164/627] hw/hexagon: move VTCM to the common machine state The VTCM is described by the config table, so every machine can set it up the same way. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-3-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hex-subsys.c | 8 ++++++++ hw/hexagon/virt.c | 5 ----- include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/virt.h | 1 - 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index d146ee0c07..0c20cf02e7 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -29,4 +29,12 @@ void hex_subsys_create(HexagonCommonMachineState *hms, rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable, sizeof(m_cfg->cfgtable), m_cfg->cfgbase, &address_space_memory); + + if (m_cfg->cfgtable.vtcm_size_kb > 0) { + memory_region_init_ram(&hms->vtcm, NULL, "vtcm.ram", + m_cfg->cfgtable.vtcm_size_kb * 1024, + &error_fatal); + memory_region_add_subregion(sysmem, m_cfg->cfgtable.vtcm_base << 16, + &hms->vtcm); + } } diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index ad0bc4f132..53eaafaf85 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -75,11 +75,6 @@ static void fdt_add_hvx(HexagonVirtMachineState *vms, const MachineState *ms = MACHINE(vms); uint32_t vtcm_size_bytes = m_cfg->cfgtable.vtcm_size_kb * 1024; if (vtcm_size_bytes > 0) { - memory_region_init_ram(&vms->vtcm, NULL, "vtcm.ram", vtcm_size_bytes, - &error_fatal); - memory_region_add_subregion(vms->sys, m_cfg->cfgtable.vtcm_base << 16, - &vms->vtcm); - qemu_fdt_add_subnode(ms->fdt, "/soc/vtcm"); qemu_fdt_setprop_string(ms->fdt, "/soc/vtcm", "compatible", "qcom,hexagon_vtcm"); diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 1034b09c2a..9c73cadb16 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -156,6 +156,7 @@ struct HexagonCommonMachineState { MemoryRegion ram; MemoryRegion cfgtable_rom; + MemoryRegion vtcm; }; #endif diff --git a/include/hw/hexagon/virt.h b/include/hw/hexagon/virt.h index fcb4776219..cf0cd2f8f2 100644 --- a/include/hw/hexagon/virt.h +++ b/include/hw/hexagon/virt.h @@ -17,7 +17,6 @@ struct HexagonVirtMachineState { int fdt_size; MemoryRegion *sys; MemoryRegion tcm; - MemoryRegion vtcm; MemoryRegion bios; Clock *apb_clk; }; From 26088c1e7b39e05a724618518594383665b74069 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:08 -0700 Subject: [PATCH 165/627] hw/hexagon: move global registers to hex-subsys Both machines create the global register device the same way, so let hex-subsys own it and link it to each CPU as it is realized. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-4-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hex-subsys.c | 29 ++++++++++++++++++++++++++++- hw/hexagon/hexagon_dsp.c | 15 ++------------- hw/hexagon/virt.c | 23 +++++------------------ include/hw/hexagon/hex-subsys.h | 6 +++++- include/hw/hexagon/hexagon.h | 1 + 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 0c20cf02e7..6789b6bb23 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -8,11 +8,29 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hexagon/hex-subsys.h" +#include "hw/hexagon/hexagon_globalreg.h" #include "hw/core/loader.h" +#include "hw/core/qdev-properties.h" +#include "hw/core/qdev.h" +#include "hw/core/sysbus.h" #include "system/address-spaces.h" +static DeviceState *globalreg_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg, + Rev_t rev) +{ + DeviceState *glob_regs = qdev_new(TYPE_HEXAGON_GLOBALREG); + + object_property_add_child(OBJECT(hms), "global-regs", OBJECT(glob_regs)); + qdev_prop_set_uint64(glob_regs, "config-table-addr", m_cfg->cfgbase); + qdev_prop_set_uint32(glob_regs, "dsp-rev", rev); + sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal); + + return glob_regs; +} + void hex_subsys_create(HexagonCommonMachineState *hms, - const struct hexagon_machine_config *m_cfg) + const struct hexagon_machine_config *m_cfg, Rev_t rev) { MachineState *machine = MACHINE(hms); MemoryRegion *sysmem = get_system_memory(); @@ -37,4 +55,13 @@ void hex_subsys_create(HexagonCommonMachineState *hms, memory_region_add_subregion(sysmem, m_cfg->cfgtable.vtcm_base << 16, &hms->vtcm); } + + hms->glob_regs = globalreg_create(hms, m_cfg, rev); +} + +void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) +{ + object_property_set_link(OBJECT(cpu), "global-regs", + OBJECT(hms->glob_regs), &error_fatal); + qdev_realize_and_unref(cpu, NULL, &error_fatal); } diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index f94f7fd4e1..8599f5883b 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -15,7 +15,6 @@ #include "hw/core/qdev-properties.h" #include "hw/hexagon/hexagon.h" #include "hw/hexagon/hex-subsys.h" -#include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" #include "qapi/error.h" @@ -109,7 +108,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, { HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(machine); HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(machine); - DeviceState *glob_regs_dev; DeviceState *tlb_dev; memset(&hexagon_binfo, 0, sizeof(hexagon_binfo)); @@ -120,14 +118,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, machine->enable_graphics = 0; - hex_subsys_create(hms, m_cfg); - - glob_regs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG); - object_property_add_child(OBJECT(machine), "global-regs", - OBJECT(glob_regs_dev)); - qdev_prop_set_uint64(glob_regs_dev, "config-table-addr", m_cfg->cfgbase); - qdev_prop_set_uint32(glob_regs_dev, "dsp-rev", rev); - sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs_dev), &error_fatal); + hex_subsys_create(hms, m_cfg, rev); tlb_dev = qdev_new(TYPE_HEXAGON_TLB); object_property_add_child(OBJECT(machine), "tlb", OBJECT(tlb_dev)); @@ -147,11 +138,9 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, if (i == 0) { hexagon_init_bootstrap(dms, cpu); } - object_property_set_link(OBJECT(cpu), "global-regs", - OBJECT(glob_regs_dev), &error_fatal); object_property_set_link(OBJECT(cpu), "tlb", OBJECT(tlb_dev), &error_fatal); - qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal); + hex_subsys_realize_cpu(hms, DEVICE(cpu)); } } diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index 53eaafaf85..290783d511 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -14,7 +14,6 @@ #include "hw/core/sysbus-fdt.h" #include "hw/hexagon/hexagon.h" #include "hw/hexagon/hex-subsys.h" -#include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" @@ -226,9 +225,7 @@ static void virt_init(MachineState *ms) { HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms); const struct hexagon_machine_config *m_cfg = &v68n_1024; - DeviceState *gsregs_dev; DeviceState *tlb_dev; - DeviceState *cpu0; int32_t clk_phandle; create_fdt(vms); @@ -240,7 +237,7 @@ static void virt_init(MachineState *ms) vms->apb_clk = clock_new(OBJECT(ms), "apb-pclk"); clock_set_hz(vms->apb_clk, 24000000); - hex_subsys_create(&vms->parent_obj, m_cfg); + hex_subsys_create(&vms->parent_obj, m_cfg, v68_rev); if (m_cfg->l2tcm_size) { memory_region_init_ram(&vms->tcm, NULL, "tcm.ram", m_cfg->l2tcm_size, @@ -251,42 +248,32 @@ static void virt_init(MachineState *ms) fdt_add_hvx(vms, m_cfg); - gsregs_dev = qdev_new(TYPE_HEXAGON_GLOBALREG); - object_property_add_child(OBJECT(ms), "global-regs", OBJECT(gsregs_dev)); - qdev_prop_set_uint64(gsregs_dev, "config-table-addr", m_cfg->cfgbase); - qdev_prop_set_uint32(gsregs_dev, "dsp-rev", v68_rev); - sysbus_realize_and_unref(SYS_BUS_DEVICE(gsregs_dev), &error_fatal); - tlb_dev = qdev_new(TYPE_HEXAGON_TLB); object_property_add_child(OBJECT(ms), "tlb", OBJECT(tlb_dev)); qdev_prop_set_uint32(tlb_dev, "num-entries", m_cfg->cfgtable.jtlb_size_entries); sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb_dev), &error_fatal); - cpu0 = NULL; for (int i = 0; i < ms->smp.cpus; i++) { HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type)); qemu_register_reset(do_cpu_reset, cpu); if (i == 0) { - cpu0 = DEVICE(cpu); if (ms->kernel_filename) { uint64_t entry = load_kernel(vms); - qdev_prop_set_uint32(cpu0, "exec-start-addr", entry); + qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry); } else if (ms->firmware) { uint64_t entry = load_bios(vms); - qdev_prop_set_uint32(cpu0, "exec-start-addr", entry); + qdev_prop_set_uint32(DEVICE(cpu), "exec-start-addr", entry); } } qdev_prop_set_uint32(DEVICE(cpu), "htid", i); qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); - object_property_set_link(OBJECT(cpu), "global-regs", - OBJECT(gsregs_dev), &error_fatal); object_property_set_link(OBJECT(cpu), "tlb", OBJECT(tlb_dev), &error_fatal); - - qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal); + hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpu)); } + fdt_add_cpu_nodes(vms); clk_phandle = fdt_add_clocks(vms); fdt_add_uart(vms, VIRT_UART0, clk_phandle); diff --git a/include/hw/hexagon/hex-subsys.h b/include/hw/hexagon/hex-subsys.h index 6bcde303f2..087c105cfa 100644 --- a/include/hw/hexagon/hex-subsys.h +++ b/include/hw/hexagon/hex-subsys.h @@ -9,9 +9,13 @@ #define HW_HEXAGON_HEX_SUBSYS_H #include "hw/hexagon/hexagon.h" +#include "hw/core/qdev.h" /* Create the subsystem shared by every Hexagon machine. */ void hex_subsys_create(HexagonCommonMachineState *hms, - const struct hexagon_machine_config *m_cfg); + const struct hexagon_machine_config *m_cfg, Rev_t rev); + +/* Realize a CPU into the subsystem. */ +void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); #endif /* HW_HEXAGON_HEX_SUBSYS_H */ diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 9c73cadb16..ef5700082c 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -157,6 +157,7 @@ struct HexagonCommonMachineState { MemoryRegion ram; MemoryRegion cfgtable_rom; MemoryRegion vtcm; + DeviceState *glob_regs; }; #endif From d24f9c80f62f95cb8f6c2b8666d3efd1e021fb99 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:09 -0700 Subject: [PATCH 166/627] hw/hexagon: move the TLB to hex-subsys The TLB device is sized from the config table, so both machines create it identically. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-5-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hex-subsys.c | 16 ++++++++++++++++ hw/hexagon/hexagon_dsp.c | 10 ---------- hw/hexagon/virt.c | 10 ---------- include/hw/hexagon/hexagon.h | 1 + 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 6789b6bb23..ac7e29604e 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -9,6 +9,7 @@ #include "qapi/error.h" #include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" +#include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev.h" @@ -29,6 +30,18 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms, return glob_regs; } +static DeviceState *tlb_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + DeviceState *tlb = qdev_new(TYPE_HEXAGON_TLB); + + object_property_add_child(OBJECT(hms), "tlb", OBJECT(tlb)); + qdev_prop_set_uint32(tlb, "num-entries", m_cfg->cfgtable.jtlb_size_entries); + sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb), &error_fatal); + + return tlb; +} + void hex_subsys_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev) { @@ -57,11 +70,14 @@ void hex_subsys_create(HexagonCommonMachineState *hms, } hms->glob_regs = globalreg_create(hms, m_cfg, rev); + hms->tlb = tlb_create(hms, m_cfg); } void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) { object_property_set_link(OBJECT(cpu), "global-regs", OBJECT(hms->glob_regs), &error_fatal); + object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb), + &error_fatal); qdev_realize_and_unref(cpu, NULL, &error_fatal); } diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 8599f5883b..25e8550fba 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -15,7 +15,6 @@ #include "hw/core/qdev-properties.h" #include "hw/hexagon/hexagon.h" #include "hw/hexagon/hex-subsys.h" -#include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -108,7 +107,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, { HexagonCommonMachineState *hms = HEXAGON_COMMON_MACHINE(machine); HexagonDspMachineState *dms = HEXAGON_DSP_MACHINE(machine); - DeviceState *tlb_dev; memset(&hexagon_binfo, 0, sizeof(hexagon_binfo)); if (machine->kernel_filename) { @@ -120,12 +118,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, hex_subsys_create(hms, m_cfg, rev); - tlb_dev = qdev_new(TYPE_HEXAGON_TLB); - object_property_add_child(OBJECT(machine), "tlb", OBJECT(tlb_dev)); - qdev_prop_set_uint32(tlb_dev, "num-entries", - m_cfg->cfgtable.jtlb_size_entries); - sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb_dev), &error_fatal); - for (int i = 0; i < machine->smp.cpus; i++) { HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type)); qemu_register_reset(do_cpu_reset, cpu); @@ -138,8 +130,6 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, if (i == 0) { hexagon_init_bootstrap(dms, cpu); } - object_property_set_link(OBJECT(cpu), "tlb", - OBJECT(tlb_dev), &error_fatal); hex_subsys_realize_cpu(hms, DEVICE(cpu)); } } diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index 290783d511..b9e0bbb704 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -14,7 +14,6 @@ #include "hw/core/sysbus-fdt.h" #include "hw/hexagon/hexagon.h" #include "hw/hexagon/hex-subsys.h" -#include "hw/hexagon/hexagon_tlb.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev-clock.h" @@ -225,7 +224,6 @@ static void virt_init(MachineState *ms) { HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms); const struct hexagon_machine_config *m_cfg = &v68n_1024; - DeviceState *tlb_dev; int32_t clk_phandle; create_fdt(vms); @@ -248,12 +246,6 @@ static void virt_init(MachineState *ms) fdt_add_hvx(vms, m_cfg); - tlb_dev = qdev_new(TYPE_HEXAGON_TLB); - object_property_add_child(OBJECT(ms), "tlb", OBJECT(tlb_dev)); - qdev_prop_set_uint32(tlb_dev, "num-entries", - m_cfg->cfgtable.jtlb_size_entries); - sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb_dev), &error_fatal); - for (int i = 0; i < ms->smp.cpus; i++) { HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type)); qemu_register_reset(do_cpu_reset, cpu); @@ -269,8 +261,6 @@ static void virt_init(MachineState *ms) } qdev_prop_set_uint32(DEVICE(cpu), "htid", i); qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); - object_property_set_link(OBJECT(cpu), "tlb", - OBJECT(tlb_dev), &error_fatal); hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpu)); } diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index ef5700082c..6edd93f478 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -158,6 +158,7 @@ struct HexagonCommonMachineState { MemoryRegion cfgtable_rom; MemoryRegion vtcm; DeviceState *glob_regs; + DeviceState *tlb; }; #endif From d33ec047c30d28c883cac0eaa4a7c9168cd81a5f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:10 -0700 Subject: [PATCH 167/627] hw/hexagon: group the CPUs in a cluster The CPUs are now grouped in a TYPE_CPU_CLUSTER. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-6-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/Kconfig | 1 + hw/hexagon/hex-subsys.c | 30 +++++++++++++++++++++++++++++- hw/hexagon/hexagon_dsp.c | 11 ++++++++++- hw/hexagon/virt.c | 11 ++++++++++- include/hw/hexagon/hex-subsys.h | 12 +++++++++++- include/hw/hexagon/hexagon.h | 1 + 6 files changed, 62 insertions(+), 4 deletions(-) diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index 52065ab3b2..121c548bbb 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -2,6 +2,7 @@ config HEX_DSP bool default y depends on HEXAGON + select CPU_CLUSTER config HEX_VIRT bool diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index ac7e29604e..6fad6fe0a4 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -10,6 +10,7 @@ #include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" +#include "hw/cpu/cluster.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev.h" @@ -42,6 +43,16 @@ static DeviceState *tlb_create(HexagonCommonMachineState *hms, return tlb; } +static DeviceState *cluster_create(HexagonCommonMachineState *hms) +{ + DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER); + + object_property_add_child(OBJECT(hms), "cluster", OBJECT(cluster)); + qdev_prop_set_uint32(cluster, "cluster-id", 0); + + return cluster; +} + void hex_subsys_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev) { @@ -69,15 +80,32 @@ void hex_subsys_create(HexagonCommonMachineState *hms, &hms->vtcm); } + hms->cluster = cluster_create(hms); hms->glob_regs = globalreg_create(hms, m_cfg, rev); hms->tlb = tlb_create(hms, m_cfg); } -void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) +void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) { + object_property_add_child(OBJECT(hms->cluster), "cpu[*]", OBJECT(cpu)); object_property_set_link(OBJECT(cpu), "global-regs", OBJECT(hms->glob_regs), &error_fatal); object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb), &error_fatal); +} + +void hex_subsys_realize_cluster(HexagonCommonMachineState *hms) +{ + /* + * The cluster must be realized after its CPUs have been parented into it + * (see hex_subsys_add_cpu()) but before any CPU is itself realized, since + * qdev_realize_and_unref() on a CPU latches cluster_index into the TCG + * cflags at that point. + */ + qdev_realize_and_unref(hms->cluster, NULL, &error_fatal); +} + +void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) +{ qdev_realize_and_unref(cpu, NULL, &error_fatal); } diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 25e8550fba..1db5d68166 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -118,6 +118,8 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, hex_subsys_create(hms, m_cfg, rev); + g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, machine->smp.cpus); + for (int i = 0; i < machine->smp.cpus; i++) { HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type)); qemu_register_reset(do_cpu_reset, cpu); @@ -130,7 +132,14 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, if (i == 0) { hexagon_init_bootstrap(dms, cpu); } - hex_subsys_realize_cpu(hms, DEVICE(cpu)); + hex_subsys_add_cpu(hms, DEVICE(cpu)); + cpus[i] = cpu; + } + + hex_subsys_realize_cluster(hms); + + for (int i = 0; i < machine->smp.cpus; i++) { + hex_subsys_realize_cpu(hms, DEVICE(cpus[i])); } } diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index b9e0bbb704..dc1d5b6aa2 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -246,6 +246,8 @@ static void virt_init(MachineState *ms) fdt_add_hvx(vms, m_cfg); + g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus); + for (int i = 0; i < ms->smp.cpus; i++) { HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type)); qemu_register_reset(do_cpu_reset, cpu); @@ -261,7 +263,14 @@ static void virt_init(MachineState *ms) } qdev_prop_set_uint32(DEVICE(cpu), "htid", i); qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0)); - hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpu)); + hex_subsys_add_cpu(&vms->parent_obj, DEVICE(cpu)); + cpus[i] = cpu; + } + + hex_subsys_realize_cluster(&vms->parent_obj); + + for (int i = 0; i < ms->smp.cpus; i++) { + hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i])); } fdt_add_cpu_nodes(vms); diff --git a/include/hw/hexagon/hex-subsys.h b/include/hw/hexagon/hex-subsys.h index 087c105cfa..6d0d5e1da8 100644 --- a/include/hw/hexagon/hex-subsys.h +++ b/include/hw/hexagon/hex-subsys.h @@ -15,7 +15,17 @@ void hex_subsys_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev); -/* Realize a CPU into the subsystem. */ +/* + * Parent a CPU into the subsystem's cluster and wire its links. Call for + * every CPU before hex_subsys_realize_cluster(), then realize each CPU with + * hex_subsys_realize_cpu(). + */ +void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); + +/* Realize the CPU cluster, once all CPUs have been parented into it. */ +void hex_subsys_realize_cluster(HexagonCommonMachineState *hms); + +/* Realize a CPU previously parented via hex_subsys_add_cpu(). */ void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); #endif /* HW_HEXAGON_HEX_SUBSYS_H */ diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 6edd93f478..31669a829f 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -157,6 +157,7 @@ struct HexagonCommonMachineState { MemoryRegion ram; MemoryRegion cfgtable_rom; MemoryRegion vtcm; + DeviceState *cluster; DeviceState *glob_regs; DeviceState *tlb; }; From d922df10b27aa9f492638a22b62a43e873246c40 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:11 -0700 Subject: [PATCH 168/627] bitops.h: Add find_first_bit32() set_bit32()/test_bit32()/etc already let devices operate on guest-visible uint32_t register arrays without depending on the host's 'unsigned long' size. Add find_first_bit32() so callers need not cast a uint32_t array to 'unsigned long *'. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-7-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- include/qemu/bitops.h | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index c7b838a628..f7363a5479 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -43,10 +43,9 @@ * be some guest-visible register view of the bit array. * * We do not currently implement uint32_t versions of find_last_bit(), - * find_next_bit(), find_next_zero_bit(), find_first_bit() or - * find_first_zero_bit(), because we haven't yet needed them. If you - * need them you should implement them similarly to the 'unsigned long' - * versions. + * find_next_bit(), find_next_zero_bit() or find_first_zero_bit(), + * because we haven't yet needed them. If you need them you should + * implement them similarly to the 'unsigned long' versions. * * You can declare a bitmap to be used with these functions via the * DECLARE_BITMAP and DECLARE_BITMAP32 macros in bitmap.h. @@ -382,6 +381,29 @@ static inline int test_bit32(long nr, const uint32_t *addr) return 1U & (addr[BIT32_WORD(nr)] >> (nr & 31)); } +/** + * find_first_bit32 - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit number of the first set bit, + * or @size if there is no set bit in the bitmap. + */ +static inline uint32_t find_first_bit32(const uint32_t *addr, uint32_t size) +{ + uint32_t result; + + for (result = 0; result < size; result += 32) { + uint32_t tmp = *addr++; + if (tmp) { + result += ctz32(tmp); + return result < size ? result : size; + } + } + /* Not found */ + return size; +} + /** * DOC: Miscellaneous bit operations on single values * From 04f398b2a25d0b16339da4d0683ff505e2613ddf Mon Sep 17 00:00:00 2001 From: Sid Manning Date: Wed, 5 Aug 2026 21:27:12 -0700 Subject: [PATCH 169/627] hw/intc: Add l2vic interrupt controller The Hexagon DSP requires an L2VIC to route up to 1024 external interrupt sources through 4 VID output groups into the core's 8 interrupt inputs. Add a device model for it. Co-authored-by: Matheus Tavares Bernardino Co-authored-by: Damien Hedde Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-8-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- MAINTAINERS | 3 + docs/devel/hexagon-l2vic.rst | 55 ++++ docs/devel/index-internals.rst | 1 + hw/hexagon/Kconfig | 1 + hw/intc/Kconfig | 3 + hw/intc/hex-l2vic.c | 556 +++++++++++++++++++++++++++++++++ hw/intc/meson.build | 2 + hw/intc/trace-events | 4 + include/hw/intc/hex-l2vic.h | 61 ++++ target/hexagon/cpu.c | 2 + target/hexagon/cpu.h | 2 + target/hexagon/op_helper.c | 16 +- 12 files changed, 705 insertions(+), 1 deletion(-) create mode 100644 docs/devel/hexagon-l2vic.rst create mode 100644 hw/intc/hex-l2vic.c create mode 100644 include/hw/intc/hex-l2vic.h diff --git a/MAINTAINERS b/MAINTAINERS index 4628793dde..5a772818bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -250,6 +250,8 @@ M: Brian Cain R: Pierrick Bouvier S: Supported F: target/hexagon/ +F: hw/intc/hex-l2vic.c +F: include/hw/intc/hex-l2vic.h X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ @@ -262,6 +264,7 @@ F: gdbstub/gdb-xml/hexagon*.xml F: docs/system/target-hexagon.rst F: docs/system/hexagon/ F: docs/devel/hexagon-sys.rst +F: docs/devel/hexagon-l2vic.rst T: git https://github.com/qualcomm/qemu.git hex-next Hexagon idef-parser diff --git a/docs/devel/hexagon-l2vic.rst b/docs/devel/hexagon-l2vic.rst new file mode 100644 index 0000000000..9cb2a86871 --- /dev/null +++ b/docs/devel/hexagon-l2vic.rst @@ -0,0 +1,55 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Hexagon L2 Vectored Interrupt Controller +======================================== + + +.. code-block:: none + + +-------------+ +----------------------+ + | l2vic | | hexagon core | + | | | | + IRQ in ---->| | | | + IRQ in ---->| VID0 -|----------------->| irq2 | + ... ---->| | | | | + IRQ in ---->| | | v | + | ... | | | + | | | / | | \ | + IRQ in ---->| | | t0 t1 t2 t3 ...| + IRQ in ---->| VIDN -| | | + ... ---->| | | | + IRQ in ---->| | | Global SREG File | + | | | | + | State | | | + | [ ] <--|==================|==> [ VID ] | + | [ ] <--|==================|==> [ VID1 ] | + | | | | + +-------------+ +----------------------+ + +L2VIC/Core Integration +---------------------- + +* hexagon core supports 8 external interrupt sources +* l2vic supports 1024 input interrupts mapped among 4 output interrupts +* l2vic has four output signals: { VID0, VID1, VID2, VID3 } +* l2vic device has a bank of registers per-VID that can be used to query + the status or assert new interrupts. +* Interrupts are 'steered' to threads based on { thread priority, 'EX' state, + thread interrupt mask, thread interrupt enable, global interrupt enable, + etc. }. +* Any hardware thread could conceivably handle any input interrupt, dependent + on state. +* The system register transfer instruction can read the VID0-VID3 values from + the l2vic when reading from hexagon core system registers "VID" and "VID1". +* When l2vic VID0 has multiple active interrupts, it pulses the VID0 output + IRQ and stores the IRQ number for the VID0 register field. Only after this + interrupt is cleared can the l2vic pulse the VID0 output IRQ again and provide + the next interrupt number on the VID0 register. +* The ``ciad`` instruction clears the l2vic input interrupt and un-disables the + core interrupt. If some/an l2vic VID0 interrupt is pending when this occurs, + the next interrupt should fire and any subsequent reads of the VID register + should reflect the newly raised interrupt. +* In QEMU, on an external interrupt or an unmasked-pending interrupt, + all vCPUs are triggered (has_work==true) and each will grab the IO lock + while considering the steering logic to determine whether they're the thread + that must handle the interrupt. diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst index a8f5e310df..763cda1e76 100644 --- a/docs/devel/index-internals.rst +++ b/docs/devel/index-internals.rst @@ -15,6 +15,7 @@ Details about QEMU's various subsystems including how to add features to them. clocks ebpf_rss hexagon-sys + hexagon-l2vic migration/index multi-process reset diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index 121c548bbb..c75090c44a 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -3,6 +3,7 @@ config HEX_DSP default y depends on HEXAGON select CPU_CLUSTER + select HEX_L2VIC config HEX_VIRT bool diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 636d00b7e8..097de4efc5 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -8,6 +8,9 @@ config I8259 config PL190 bool +config HEX_L2VIC + bool + config IOAPIC bool select I8259 diff --git a/hw/intc/hex-l2vic.c b/hw/intc/hex-l2vic.c new file mode 100644 index 0000000000..f07ec850d4 --- /dev/null +++ b/hw/intc/hex-l2vic.c @@ -0,0 +1,556 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Arm PrimeCell PL190 Vector Interrupt Controller was used as a reference. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/irq.h" +#include "hw/core/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/bitmap.h" +#include "qemu/bitops.h" +#include "hw/intc/hex-l2vic.h" +#include "trace.h" + +#define L2VIC_VID_GRP_0 0x0 /* Read */ +#define L2VIC_VID_GRP_1 0x4 /* Read */ +#define L2VIC_VID_GRP_2 0x8 /* Read */ +#define L2VIC_VID_GRP_3 0xC /* Read */ +#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */ +#define L2VIC_INT_ENABLE_CLEARn 0x180 /* Write */ +#define L2VIC_INT_ENABLE_SETn 0x200 /* Write */ +#define L2VIC_INT_TYPEn 0x280 /* Read/Write */ +#define L2VIC_INT_STATUSn 0x380 /* Read */ +#define L2VIC_INT_CLEARn 0x400 /* Write */ +#define L2VIC_SOFT_INTn 0x480 /* Write */ +#define L2VIC_INT_PENDINGn 0x500 /* Read */ +#define L2VIC_INT_GRPn_0 0x600 /* Read/Write */ +#define L2VIC_INT_GRPn_1 0x680 /* Read/Write */ +#define L2VIC_INT_GRPn_2 0x700 /* Read/Write */ +#define L2VIC_INT_GRPn_3 0x780 /* Read/Write */ + +#define L2VIC_INTERRUPT_MAX 1024 +/* + * Note about l2vic groups: + * Each interrupt to L2VIC can be configured to associate with one of + * four groups. + * Group 0 interrupts go to IRQ2 via VID 0 (SSR: 0xC2, the default) + * Group 1 interrupts go to IRQ3 via VID 1 (SSR: 0xC3) + * Group 2 interrupts go to IRQ4 via VID 2 (SSR: 0xC4) + * Group 3 interrupts go to IRQ5 via VID 3 (SSR: 0xC5) + */ + +static void bitmap32_write_word(uint32_t *bitmap, int word_offset, uint32_t val) +{ + bitmap[word_offset] = val; +} + +static void bitmap32_clear_word(uint32_t *bitmap, int word_offset, + uint32_t mask) +{ + bitmap[word_offset] &= ~mask; +} + +static void bitmap32_set_word(uint32_t *bitmap, int word_offset, uint32_t mask) +{ + bitmap[word_offset] |= mask; +} + +static uint32_t bitmap32_read_word(uint32_t *bitmap, int word_offset) +{ + return bitmap[word_offset]; +} + +OBJECT_DECLARE_SIMPLE_TYPE(HexL2VICState, HEX_L2VIC) + +#define SLICE_MAX (L2VIC_INTERRUPT_MAX / 32) +#define L2VIC_REG_RANGE_SIZE 0x80 + +typedef struct HexL2VICState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegion fast_iomem; + /* + * vid_group[i] is readable at L2VIC_VID_GRP_i (offset i*4): the irq + * last delivered through VID group i, 0-1023 so only 10 bits are used. + */ + uint32_t vid_group[4]; + /* + * Last irq delivered on any VID group; not specific to group 0. + * Used by the ciad path to clear the most-recently-delivered + * interrupt from int_status. + */ + uint32_t vid; + DECLARE_BITMAP32(int_enable, L2VIC_INTERRUPT_MAX); + /* Asserted interrupts awaiting delivery once no VID is active */ + DECLARE_BITMAP32(int_pending, L2VIC_INTERRUPT_MAX); + /* Which enabled interrupt is active */ + DECLARE_BITMAP32(int_status, L2VIC_INTERRUPT_MAX); + /* Edge or Level interrupt */ + DECLARE_BITMAP32(int_type, L2VIC_INTERRUPT_MAX); + DECLARE_BITMAP32(int_group_n[4], L2VIC_INTERRUPT_MAX); + qemu_irq irq[8]; +} HexL2VICState; + +typedef enum { + L2VIC_OP_WRITE, + L2VIC_OP_CLEAR, + L2VIC_OP_SET, + L2VIC_OP_NONE, +} L2VicWriteOp; + +typedef struct { + hwaddr base; + size_t state_offset; + L2VicWriteOp write_op; + bool write_only; +} L2VicRegRange; + +static const L2VicRegRange l2vic_reg_ranges[] = { + { L2VIC_INT_ENABLEn, offsetof(HexL2VICState, int_enable), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_ENABLE_CLEARn, offsetof(HexL2VICState, int_enable), + L2VIC_OP_CLEAR, true }, + { L2VIC_INT_ENABLE_SETn, offsetof(HexL2VICState, int_enable), + L2VIC_OP_SET, true }, + { L2VIC_INT_TYPEn, offsetof(HexL2VICState, int_type), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_STATUSn, offsetof(HexL2VICState, int_status), + L2VIC_OP_NONE, false }, + { L2VIC_INT_CLEARn, offsetof(HexL2VICState, int_status), + L2VIC_OP_CLEAR, true }, + { L2VIC_SOFT_INTn, offsetof(HexL2VICState, int_pending), + L2VIC_OP_NONE, true }, + { L2VIC_INT_PENDINGn, offsetof(HexL2VICState, int_pending), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_GRPn_0, offsetof(HexL2VICState, int_group_n[0]), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_GRPn_1, offsetof(HexL2VICState, int_group_n[1]), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_GRPn_2, offsetof(HexL2VICState, int_group_n[2]), + L2VIC_OP_WRITE, false }, + { L2VIC_INT_GRPn_3, offsetof(HexL2VICState, int_group_n[3]), + L2VIC_OP_WRITE, false }, +}; + +static uint32_t *l2vic_state_bitmap(HexL2VICState *s, size_t state_offset) +{ + return (uint32_t *)((char *)s + state_offset); +} + +static bool l2vic_reg_read_range(HexL2VICState *s, hwaddr offset, + uint64_t *value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(l2vic_reg_ranges); i++) { + const L2VicRegRange *r = &l2vic_reg_ranges[i]; + + if (offset >= r->base && + offset < r->base + L2VIC_REG_RANGE_SIZE) { + if (r->write_only) { + *value = 0; + } else { + uint32_t *bitmap = l2vic_state_bitmap(s, r->state_offset); + *value = bitmap32_read_word(bitmap, + (offset - r->base) >> 2); + } + return true; + } + } + return false; +} + +static bool l2vic_reg_write_range(HexL2VICState *s, hwaddr offset, + uint32_t val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(l2vic_reg_ranges); i++) { + const L2VicRegRange *r = &l2vic_reg_ranges[i]; + + if (offset >= r->base && + offset < r->base + L2VIC_REG_RANGE_SIZE) { + uint32_t *bitmap = l2vic_state_bitmap(s, r->state_offset); + int word = (offset - r->base) >> 2; + + switch (r->write_op) { + case L2VIC_OP_WRITE: + bitmap32_write_word(bitmap, word, val); + break; + case L2VIC_OP_CLEAR: + bitmap32_clear_word(bitmap, word, val); + break; + case L2VIC_OP_SET: + bitmap32_set_word(bitmap, word, val); + break; + case L2VIC_OP_NONE: + /* Read-only or handled elsewhere; ignore the write. */ + break; + default: + g_assert_not_reached(); + } + return true; + } + } + return false; +} + +/* + * The four INT_GRPn_* register arrays are interleaved across irqs in + * blocks of 8: irq 0-7 live in group_n[0], irq 8-15 in group_n[1], irq + * 16-23 in group_n[2], irq 24-31 in group_n[3], irq 32-39 back in + * group_n[0], and so on. + */ +static uint32_t *get_int_group(HexL2VICState *s, int irq) +{ + return s->int_group_n[extract32(irq, 3, 2)]; +} + +static int find_slice(int irq) +{ + return irq / 32; +} + +static int get_vid(HexL2VICState *s, int irq) +{ + uint32_t *group = get_int_group(s, irq); + uint32_t slice = group[find_slice(irq)]; + uint32_t vid; + /* + * Each irq occupies a 4-bit field: bit 3 is the group-enable bit, + * bits 0-2 select the VID group. Shift down to this irq's field. + */ + uint32_t val = slice >> ((irq & 0x7) * 4); + + if (!(val & 0x8)) { + return 0; + } + vid = val & 0x7; + if (vid >= ARRAY_SIZE(s->vid_group)) { + qemu_log_mask(LOG_GUEST_ERROR, + "L2VIC: irq %d requests invalid vid group %u\n", + irq, vid); + return 0; + } + return vid; +} + +static inline bool vid_active(HexL2VICState *s) +{ + const uint32_t size = L2VIC_INTERRUPT_MAX; + const uint32_t active_irq = find_first_bit32(s->int_status, size); + return active_irq != size; +} + +static bool l2vic_update(HexL2VICState *s, int irq) +{ + bool pending; + bool enable; + + if (vid_active(s)) { + return true; + } + + pending = test_bit32(irq, s->int_pending); + enable = test_bit32(irq, s->int_enable); + if (pending && enable) { + int vid = get_vid(s, irq); + set_bit32(irq, s->int_status); + clear_bit32(irq, s->int_pending); + /* + * Only auto-disable for edge-triggered interrupts (type=1). + * Level-triggered interrupts (type=0, the default) keep their + * enable bit set across deliveries -- the firmware enables once + * and expects the interrupt to remain enabled. + */ + if (test_bit32(irq, s->int_type)) { + clear_bit32(irq, s->int_enable); + } + s->vid = irq; + s->vid_group[vid] = irq; + + qemu_irq_pulse(s->irq[vid + 2]); + trace_hex_l2vic_delivered(irq, vid); + return true; + } + return false; +} + +static void l2vic_update_all(HexL2VICState *s) +{ + for (int i = 0; i < L2VIC_INTERRUPT_MAX; i++) { + if (l2vic_update(s, i)) { + /* once vid is active, no-one else can set it until ciad */ + return; + } + } +} + +static void l2vic_set_irq(void *opaque, int irq, int level) +{ + HexL2VICState *s = (HexL2VICState *)opaque; + + if (level) { + set_bit32(irq, s->int_pending); + } + l2vic_update(s, irq); +} + +static void l2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + HexL2VICState *s = (HexL2VICState *)opaque; + + trace_hex_l2vic_reg_write((unsigned)offset, (uint32_t)val); + + if (!l2vic_reg_write_range(s, offset, val)) { + qemu_log_mask(LOG_UNIMP, + "%s: offset 0x%" HWADDR_PRIx " unimplemented\n", + __func__, offset); + } + + /* SOFT_INT also sets pending for edge-triggered interrupts */ + if (offset >= L2VIC_SOFT_INTn && + offset < L2VIC_SOFT_INTn + L2VIC_REG_RANGE_SIZE && val) { + int base_irq = ((offset - L2VIC_SOFT_INTn) >> 2) * 32; + uint32_t bits = val; + int bit; + + while ((bit = ctz32(bits)) < 32) { + int irq = base_irq + bit; + + if (test_bit32(irq, s->int_type)) { + set_bit32(irq, s->int_pending); + } + bits &= ~(1u << bit); + } + } + + l2vic_update_all(s); +} + +static uint64_t l2vic_read(void *opaque, hwaddr offset, unsigned size) +{ + uint64_t value; + HexL2VICState *s = (HexL2VICState *)opaque; + + if (offset <= L2VIC_VID_GRP_3) { + value = s->vid_group[offset >> 2]; + } else if (!l2vic_reg_read_range(s, offset, &value)) { + value = 0; + qemu_log_mask(LOG_GUEST_ERROR, + "L2VIC: %s: offset 0x%" HWADDR_PRIx "\n", __func__, + offset); + } + + trace_hex_l2vic_reg_read((unsigned)offset, (uint32_t)value); + return value; +} + +static const MemoryRegionOps l2vic_ops = { + .read = l2vic_read, + .write = l2vic_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .valid.unaligned = false, +}; + +#define FASTL2VIC_ENABLE 0x0 +#define FASTL2VIC_DISABLE 0x1 +#define FASTL2VIC_INT 0x2 + +static void fastl2vic_write(void *opaque, hwaddr offset, uint64_t val, + unsigned size) +{ + if (offset == 0) { + uint32_t cmd = (val >> 16) & 0x3; + uint32_t irq = val & 0x3ff; + uint32_t slice = (irq / 32) * 4; + val = 1 << (irq % 32); + + if (cmd == FASTL2VIC_ENABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_SETn + slice, val, size); + } else if (cmd == FASTL2VIC_DISABLE) { + l2vic_write(opaque, L2VIC_INT_ENABLE_CLEARn + slice, val, size); + } else if (cmd == FASTL2VIC_INT) { + l2vic_write(opaque, L2VIC_SOFT_INTn + slice, val, size); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write cmd %" PRId32 "\n", + __func__, cmd); + } + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid write offset 0x%08" HWADDR_PRIx + "\n", __func__, offset); +} + +static uint64_t fastl2vic_read(void *opaque, hwaddr offset, unsigned size) +{ + return 0; +} + +static const MemoryRegionOps fastl2vic_ops = { + .read = fastl2vic_read, + .write = fastl2vic_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .valid.unaligned = false, +}; + +static uint32_t l2vic_interface_read_vid_impl(HexL2VicInterface *iface, + uint32_t group) +{ + HexL2VICState *s = HEX_L2VIC(iface); + uint32_t result = 0; + + if (group == 0) { + /* VID register combines vid_group[0] (VID0) and vid_group[1] (VID1) */ + result = deposit32(result, 0, 16, s->vid_group[0]); + result = deposit32(result, 16, 16, s->vid_group[1]); + } else if (group == 1) { + /* VID1 register combines vid_group[2] (VID2) and vid_group[3] (VID3) */ + result = deposit32(result, 0, 16, s->vid_group[2]); + result = deposit32(result, 16, 16, s->vid_group[3]); + } + return result; +} + +static void l2vic_interface_update_vid_impl(HexL2VicInterface *iface, + uint32_t group, uint32_t value) +{ + HexL2VICState *s = HEX_L2VIC(iface); + + if (group == 0) { + s->vid_group[0] = extract32(value, 0, 16); + s->vid_group[1] = extract32(value, 16, 16); + } else if (group == 1) { + s->vid_group[2] = extract32(value, 0, 16); + s->vid_group[3] = extract32(value, 16, 16); + } + + l2vic_update_all(s); +} + +static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface) +{ + HexL2VICState *s = HEX_L2VIC(iface); + + if (s->vid < L2VIC_INTERRUPT_MAX) { + clear_bit32(s->vid, s->int_status); + } + l2vic_update_all(s); +} + +static void l2vic_reset_hold(Object *obj, ResetType type G_GNUC_UNUSED) +{ + HexL2VICState *s = HEX_L2VIC(obj); + + memset(s->int_enable, 0, sizeof(s->int_enable)); + memset(s->int_pending, 0, sizeof(s->int_pending)); + memset(s->int_status, 0, sizeof(s->int_status)); + memset(s->int_type, 0, sizeof(s->int_type)); + memset(s->int_group_n, 0, sizeof(s->int_group_n)); + memset(s->vid_group, 0, sizeof(s->vid_group)); + s->vid = 0; + + l2vic_update_all(s); +} + +static void reset_irq_handler(void *opaque, int irq, int level) +{ + Object *obj = OBJECT(opaque); + + if (level) { + l2vic_reset_hold(obj, RESET_TYPE_COLD); + } +} + +static void l2vic_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + HexL2VICState *s = HEX_L2VIC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + memory_region_init_io(&s->iomem, obj, &l2vic_ops, s, "l2vic", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + memory_region_init_io(&s->fast_iomem, obj, &fastl2vic_ops, s, "fast", + 0x10000); + sysbus_init_mmio(sbd, &s->fast_iomem); + + qdev_init_gpio_in(dev, l2vic_set_irq, L2VIC_INTERRUPT_MAX); + qdev_init_gpio_in_named(dev, reset_irq_handler, "reset", 1); + for (i = 0; i < 8; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } +} + +static const VMStateDescription vmstate_l2vic = { + .name = "l2vic", + .version_id = 1, + .minimum_version_id = 1, + .fields = + (VMStateField[]){ + VMSTATE_UINT32_ARRAY(vid_group, HexL2VICState, 4), + VMSTATE_UINT32(vid, HexL2VICState), + VMSTATE_UINT32_ARRAY(int_enable, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_type, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_status, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_ARRAY(int_pending, HexL2VICState, SLICE_MAX), + VMSTATE_UINT32_2DARRAY(int_group_n, HexL2VICState, 4, SLICE_MAX), + VMSTATE_END_OF_LIST() } +}; + +static void l2vic_interface_class_init(ObjectClass *klass, const void *data) +{ + HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_CLASS(klass); + + k->read_vid = l2vic_interface_read_vid_impl; + k->update_vid = l2vic_interface_update_vid_impl; + k->clear_interrupt = l2vic_interface_clear_interrupt_impl; +} + +static void l2vic_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->vmsd = &vmstate_l2vic; + rc->phases.hold = l2vic_reset_hold; +} + +static const TypeInfo l2vic_interface_info = { + .name = TYPE_HEX_L2VIC_INTERFACE, + .parent = TYPE_INTERFACE, + .class_size = sizeof(HexL2VicInterfaceClass), + .class_init = l2vic_interface_class_init, +}; + +static const TypeInfo l2vic_info = { + .name = TYPE_HEX_L2VIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(HexL2VICState), + .instance_init = l2vic_init, + .class_init = l2vic_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HEX_L2VIC_INTERFACE }, + { } + }, +}; + +static const TypeInfo l2vic_types[] = { + l2vic_interface_info, + l2vic_info, +}; + +DEFINE_TYPES(l2vic_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 377de78bb4..a1401cb521 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -74,6 +74,8 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('xics_spapr.c', 'spapr_xi specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) + +specific_ss.add(when: 'CONFIG_HEX_L2VIC', if_true: files('hex-l2vic.c')) specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index e7d6c30448..7512c6e600 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -337,6 +337,10 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u - sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx" sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx" sh_intc_set(int id, int enable) "setting interrupt group %d to %d" +# hex-l2vic.c +hex_l2vic_reg_write(unsigned int addr, uint32_t value) "addr: 0x%03x value: 0x%08"PRIx32 +hex_l2vic_reg_read(unsigned int addr, uint32_t value) "addr: 0x%03x value: 0x%08"PRIx32 +hex_l2vic_delivered(int irq, int vid) "l2vic: delivered %d (vid %d)" # loongson_ipi.c loongson_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64 diff --git a/include/hw/intc/hex-l2vic.h b/include/hw/intc/hex-l2vic.h new file mode 100644 index 0000000000..edc278266c --- /dev/null +++ b/include/hw/intc/hex-l2vic.h @@ -0,0 +1,61 @@ +/* + * QEMU L2VIC Interrupt Controller + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_INTC_HEX_L2VIC_H +#define HW_INTC_HEX_L2VIC_H + +#include "qom/object.h" + +#define TYPE_HEX_L2VIC "hex-l2vic" +/* + * L2VIC Interface for CPU/GlobalReg interaction + */ +#define TYPE_HEX_L2VIC_INTERFACE "hex-l2vic-if" + +typedef struct HexL2VicInterface HexL2VicInterface; + +typedef struct HexL2VicInterfaceClass { + InterfaceClass parent_class; + + uint32_t (*read_vid)(HexL2VicInterface *l2vic, uint32_t group); + + /* + * Write the VID: unpack the fields into per-group VIDs. This does + * not deliver or clear any interrupt; a pending interrupt stays + * gated until ciad. + */ + void (*update_vid)(HexL2VicInterface *l2vic, uint32_t group, + uint32_t value); + + /* Clear interrupt using CIAD instruction */ + void (*clear_interrupt)(HexL2VicInterface *l2vic); +} HexL2VicInterfaceClass; + +DECLARE_OBJ_CHECKERS(HexL2VicInterface, HexL2VicInterfaceClass, + HEX_L2VIC_INTERFACE, TYPE_HEX_L2VIC_INTERFACE); + +static inline uint32_t l2vic_read_vid(HexL2VicInterface *l2vic, + uint32_t group) +{ + HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + return k->read_vid(l2vic, group); +} + +static inline void l2vic_update_vid(HexL2VicInterface *l2vic, uint32_t group, + uint32_t value) +{ + HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + k->update_vid(l2vic, group, value); +} + +static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic) +{ + HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_GET_CLASS(l2vic); + k->clear_interrupt(l2vic); +} + +#endif /* HW_INTC_HEX_L2VIC_H */ diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 12d27ce138..75cae45029 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -65,6 +65,8 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_LINK("tlb", HexagonCPU, tlb, TYPE_HEXAGON_TLB, HexagonTLBState *), DEFINE_PROP_UINT32("exec-start-addr", HexagonCPU, boot_addr, 0xffffffff), + DEFINE_PROP_LINK("l2vic", HexagonCPU, l2vic, + TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *), DEFINE_PROP_LINK("global-regs", HexagonCPU, globalregs, TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *), DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0), diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 7694fd91fa..f6c3c63932 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -39,6 +39,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegState; #include "qemu/bitmap.h" #include "target/hexagon/reg_fields.h" +#include "hw/intc/hex-l2vic.h" #define NUM_PREGS 4 #define TOTAL_PER_THREAD_REGS 64 @@ -198,6 +199,7 @@ struct ArchCPU { uint32_t boot_addr; HexagonGlobalRegState *globalregs; uint32_t htid; + HexL2VicInterface *l2vic; #endif }; diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 3ce223caba..8fb3d43c33 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -40,6 +40,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hex_mmu.h" #include "hw/hexagon/hexagon_tlb.h" +#include "hw/intc/hex-l2vic.h" #include "hex_interrupts.h" #include "hexswi.h" #endif @@ -1564,7 +1565,20 @@ void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot, void HELPER(ciad)(CPUHexagonState *env, uint32_t mask) { - g_assert_not_reached(); + uint32_t ipendad; + uint32_t iad; + HexagonCPU *cpu; + + BQL_LOCK_GUARD(); + cpu = env_archcpu(env); + ipendad = hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD, + env->threadId); + iad = fGET_FIELD(ipendad, IPENDAD_IAD); + fSET_FIELD(ipendad, IPENDAD_IAD, iad & ~(mask)); + hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD, + ipendad, env->threadId); + l2vic_clear_interrupt(cpu->l2vic); + hex_interrupt_update(env); } void HELPER(siad)(CPUHexagonState *env, uint32_t mask) From df9c6d6396d08204674da2a81dfdc03b28bfda19 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:13 -0700 Subject: [PATCH 170/627] hw/hexagon: extract get_reg_value/set_reg_value stubs in globalreg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route the globalreg read/write accessors through new get_reg_value()/set_reg_value() helpers instead of touching s->regs[reg] directly. This will be exploited by a subsequent patch that redirects VID/VID1 accesses to the L2VIC. Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-9-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hexagon_globalreg.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c index b5e5913507..105475219a 100644 --- a/hw/hexagon/hexagon_globalreg.c +++ b/hw/hexagon/hexagon_globalreg.c @@ -135,6 +135,17 @@ static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val, return new_val; } +static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg) +{ + return s->regs[reg]; +} + +static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg, + uint32_t value) +{ + s->regs[reg] = value; +} + uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg, uint32_t htid) { @@ -146,7 +157,7 @@ uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg, g_assert(reg < NUM_SREGS); g_assert(reg >= HEX_SREG_GLB_START); - value = s->regs[reg]; + value = get_reg_value(s, reg); trace_hexagon_globalreg_read(htid, get_sreg_name(reg), value); return value; @@ -160,7 +171,7 @@ void hexagon_globalreg_write(HexagonGlobalRegState *s, uint32_t reg, } g_assert(reg < NUM_SREGS); g_assert(reg >= HEX_SREG_GLB_START); - s->regs[reg] = value; + set_reg_value(s, reg, value); trace_hexagon_globalreg_write(htid, get_sreg_name(reg), value); } @@ -168,6 +179,7 @@ uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg, uint32_t value) { uint32_t reg_mask; + uint32_t cur_val; if (!s) { return value; @@ -175,9 +187,10 @@ uint32_t hexagon_globalreg_masked_value(HexagonGlobalRegState *s, uint32_t reg, g_assert(reg < NUM_SREGS); g_assert(reg >= HEX_SREG_GLB_START); reg_mask = global_sreg_immut_masks[reg]; + cur_val = get_reg_value(s, reg); return reg_mask == IMMUTABLE ? - s->regs[reg] : - apply_write_mask(value, s->regs[reg], reg_mask); + cur_val : + apply_write_mask(value, cur_val, reg_mask); } void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg, @@ -186,7 +199,7 @@ void hexagon_globalreg_write_masked(HexagonGlobalRegState *s, uint32_t reg, if (!s) { return; } - s->regs[reg] = hexagon_globalreg_masked_value(s, reg, value); + set_reg_value(s, reg, hexagon_globalreg_masked_value(s, reg, value)); } uint64_t hexagon_globalreg_get_pcycle_base(HexagonGlobalRegState *s) From 03f38eecc93b66520bd22b07d25c88e03db0ff41 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:14 -0700 Subject: [PATCH 171/627] hw/hexagon: connect l2vic device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the l2vic to the shared hex-subsys so both machine models pick it up. Map its register banks, wire the interrupt lines to CPU[0] and link each vCPU, globalregs. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-10-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/hex-subsys.c | 38 +++++++++++++++++++++++++- hw/hexagon/hexagon_dsp.c | 2 +- hw/hexagon/hexagon_globalreg.c | 25 +++++++++++++++++ hw/hexagon/virt.c | 2 +- include/hw/hexagon/hex-subsys.h | 5 ++-- include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/hexagon_globalreg.h | 4 +++ 7 files changed, 72 insertions(+), 5 deletions(-) diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 6fad6fe0a4..25c028f657 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -10,6 +10,7 @@ #include "hw/hexagon/hex-subsys.h" #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" +#include "hw/intc/hex-l2vic.h" #include "hw/cpu/cluster.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" @@ -17,6 +18,31 @@ #include "hw/core/sysbus.h" #include "system/address-spaces.h" +#define HEX_L2VIC_CPU_IRQS 8 + +static DeviceState *l2vic_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + DeviceState *l2vic = qdev_new(TYPE_HEX_L2VIC); + + object_property_add_child(OBJECT(hms), "l2vic", OBJECT(l2vic)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(l2vic), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 0, m_cfg->l2vic_base); + sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 1, + m_cfg->cfgtable.fastl2vic_base << 16); + + return l2vic; +} + +static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu) +{ + int i; + + for (i = 0; i < HEX_L2VIC_CPU_IRQS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(l2vic), i, qdev_get_gpio_in(cpu, i)); + } +} + static DeviceState *globalreg_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev) @@ -26,6 +52,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms, object_property_add_child(OBJECT(hms), "global-regs", OBJECT(glob_regs)); qdev_prop_set_uint64(glob_regs, "config-table-addr", m_cfg->cfgbase); qdev_prop_set_uint32(glob_regs, "dsp-rev", rev); + object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic), + &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal); return glob_regs; @@ -81,6 +109,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms, } hms->cluster = cluster_create(hms); + hms->l2vic = l2vic_create(hms, m_cfg); hms->glob_regs = globalreg_create(hms, m_cfg, rev); hms->tlb = tlb_create(hms, m_cfg); } @@ -92,6 +121,8 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) OBJECT(hms->glob_regs), &error_fatal); object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb), &error_fatal); + object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic), + &error_fatal); } void hex_subsys_realize_cluster(HexagonCommonMachineState *hms) @@ -105,7 +136,12 @@ void hex_subsys_realize_cluster(HexagonCommonMachineState *hms) qdev_realize_and_unref(hms->cluster, NULL, &error_fatal); } -void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu) +void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu, + bool boot_cpu) { qdev_realize_and_unref(cpu, NULL, &error_fatal); + + if (boot_cpu) { + l2vic_connect_cpu(hms->l2vic, cpu); + } } diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 1db5d68166..20306c28e7 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -139,7 +139,7 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev, hex_subsys_realize_cluster(hms); for (int i = 0; i < machine->smp.cpus; i++) { - hex_subsys_realize_cpu(hms, DEVICE(cpus[i])); + hex_subsys_realize_cpu(hms, DEVICE(cpus[i]), (i == 0)); } } diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c index 105475219a..285cb48c44 100644 --- a/hw/hexagon/hexagon_globalreg.c +++ b/hw/hexagon/hexagon_globalreg.c @@ -11,6 +11,7 @@ #include "hw/core/qdev-properties.h" #include "hw/core/sysbus.h" #include "hw/core/resettable.h" +#include "hw/intc/hex-l2vic.h" #include "migration/vmstate.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -135,8 +136,16 @@ static inline uint32_t apply_write_mask(uint32_t new_val, uint32_t cur_val, return new_val; } +static inline bool is_vid_reg(uint32_t reg) +{ + return reg == HEX_SREG_VID || reg == HEX_SREG_VID1; +} + static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg) { + if (is_vid_reg(reg)) { + return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1); + } return s->regs[reg]; } @@ -144,6 +153,9 @@ static void set_reg_value(HexagonGlobalRegState *s, uint32_t reg, uint32_t value) { s->regs[reg] = value; + if (is_vid_reg(reg)) { + l2vic_update_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1, value); + } } uint32_t hexagon_globalreg_read(HexagonGlobalRegState *s, uint32_t reg, @@ -269,6 +281,16 @@ static void hexagon_globalreg_reset_hold(Object *obj, ResetType type) do_hexagon_globalreg_reset(s); } +static void hexagon_globalreg_realize(DeviceState *dev, Error **errp) +{ + HexagonGlobalRegState *s = HEXAGON_GLOBALREG(dev); + + if (!s->l2vic) { + error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set"); + return; + } +} + static const VMStateDescription vmstate_hexagon_globalreg = { .name = "hexagon_globalreg", .version_id = 1, @@ -288,6 +310,8 @@ static const VMStateDescription vmstate_hexagon_globalreg = { }; static const Property hexagon_globalreg_properties[] = { + DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic, + TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *), DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0), DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState, config_table_addr, 0xffffffffULL), @@ -308,6 +332,7 @@ static void hexagon_globalreg_class_init(ObjectClass *klass, const void *data) ResettableClass *rc = RESETTABLE_CLASS(klass); rc->phases.hold = hexagon_globalreg_reset_hold; + dc->realize = hexagon_globalreg_realize; dc->vmsd = &vmstate_hexagon_globalreg; dc->user_creatable = false; device_class_set_props(dc, hexagon_globalreg_properties); diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index dc1d5b6aa2..9a680852c3 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -270,7 +270,7 @@ static void virt_init(MachineState *ms) hex_subsys_realize_cluster(&vms->parent_obj); for (int i = 0; i < ms->smp.cpus; i++) { - hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i])); + hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]), (i == 0)); } fdt_add_cpu_nodes(vms); diff --git a/include/hw/hexagon/hex-subsys.h b/include/hw/hexagon/hex-subsys.h index 6d0d5e1da8..5792f7b5af 100644 --- a/include/hw/hexagon/hex-subsys.h +++ b/include/hw/hexagon/hex-subsys.h @@ -18,7 +18,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms, /* * Parent a CPU into the subsystem's cluster and wire its links. Call for * every CPU before hex_subsys_realize_cluster(), then realize each CPU with - * hex_subsys_realize_cpu(). + * hex_subsys_realize_cpu(). CPU[0] receives the L2VIC outputs. */ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); @@ -26,6 +26,7 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); void hex_subsys_realize_cluster(HexagonCommonMachineState *hms); /* Realize a CPU previously parented via hex_subsys_add_cpu(). */ -void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu); +void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu, + bool boot_cpu); #endif /* HW_HEXAGON_HEX_SUBSYS_H */ diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 31669a829f..ec1578807d 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -158,6 +158,7 @@ struct HexagonCommonMachineState { MemoryRegion cfgtable_rom; MemoryRegion vtcm; DeviceState *cluster; + DeviceState *l2vic; DeviceState *glob_regs; DeviceState *tlb; }; diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h index 950099808f..397dc6854c 100644 --- a/include/hw/hexagon/hexagon_globalreg.h +++ b/include/hw/hexagon/hexagon_globalreg.h @@ -10,6 +10,7 @@ #include "hw/core/qdev.h" #include "hw/core/sysbus.h" +#include "hw/intc/hex-l2vic.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -22,6 +23,9 @@ struct HexagonGlobalRegState { /* Array of system registers */ uint32_t regs[NUM_SREGS]; + /* L2VIC interface used to back the VID/VID1 registers */ + HexL2VicInterface *l2vic; + /* Global performance cycle counter base */ uint64_t g_pcycle_base; From 76f40eb3f19311d2f83ba3bd2e1a778681359902 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:15 -0700 Subject: [PATCH 172/627] hw/hexagon/virt: instantiate virtio-mmio transports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a VIRT_MMIO region and virtio-mmio transports, wired into l2vic. Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-11-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/virt.c | 28 ++++++++++++++++++++++++++++ include/hw/hexagon/virt.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index 9a680852c3..ff0770cfc4 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -30,11 +30,19 @@ enum { VIRT_UART0, + VIRT_MMIO, VIRT_FDT, }; +/* + * Virtio IRQs run from VIRTIO_IRQ_BASE to + * VIRTIO_IRQ_BASE + VIRTIO_DEV_COUNT - 1 + */ +static const int VIRTIO_IRQ_BASE = 16; + static const MemMapEntry base_memmap[] = { [VIRT_UART0] = { 0x10000000, 0x00000200 }, + [VIRT_MMIO] = { 0x11000000, 0x00001000 }, [VIRT_FDT] = { 0x99800000, 0x00400000 }, }; @@ -167,7 +175,25 @@ static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms) } } +static void create_virtio_devices(HexagonVirtMachineState *vms) +{ + hwaddr size = base_memmap[VIRT_MMIO].size; + for (int i = 0; i < VIRTIO_DEV_COUNT; i++) { + int irq = VIRTIO_IRQ_BASE + i; + hwaddr base = base_memmap[VIRT_MMIO].base + i * size; + DeviceState *dev = qdev_new("virtio-mmio"); + SysBusDevice *s = SYS_BUS_DEVICE(dev); + + object_property_add_child(OBJECT(MACHINE(vms)), "virtio-mmio[*]", + OBJECT(dev)); + sysbus_realize_and_unref(s, &error_fatal); + sysbus_mmio_map(s, 0, base); + sysbus_connect_irq(s, 0, + qdev_get_gpio_in(vms->parent_obj.l2vic, irq)); + vms->virtio_mmio[i] = dev; + } +} void hexagon_load_fdt(const HexagonVirtMachineState *vms) { @@ -246,6 +272,8 @@ static void virt_init(MachineState *ms) fdt_add_hvx(vms, m_cfg); + create_virtio_devices(vms); + g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus); for (int i = 0; i < ms->smp.cpus; i++) { diff --git a/include/hw/hexagon/virt.h b/include/hw/hexagon/virt.h index cf0cd2f8f2..4ca2f1ef85 100644 --- a/include/hw/hexagon/virt.h +++ b/include/hw/hexagon/virt.h @@ -11,6 +11,8 @@ #include "hw/hexagon/hexagon.h" #include "target/hexagon/cpu.h" +#define VIRTIO_DEV_COUNT 8 + struct HexagonVirtMachineState { HexagonCommonMachineState parent_obj; @@ -19,6 +21,7 @@ struct HexagonVirtMachineState { MemoryRegion tcm; MemoryRegion bios; Clock *apb_clk; + DeviceState *virtio_mmio[VIRTIO_DEV_COUNT]; }; void hexagon_load_fdt(const struct HexagonVirtMachineState *vms); From abd9e918e79bc3ed860745890c35355b4ed85cc6 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:16 -0700 Subject: [PATCH 173/627] hw/hexagon/virt: add l2vic interrupt-controller and virtio-mmio FDT nodes Expose l2vic as a device-tree interrupt-controller node and reference it via interrupt-parent, so guest kernels can discover the virtio-mmio transports. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-12-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/virt.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index ff0770cfc4..ea20ea3c50 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -75,6 +75,30 @@ static void create_fdt(HexagonVirtMachineState *vms) qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); } +static int32_t fdt_add_l2vic(HexagonVirtMachineState *vms, + const struct hexagon_machine_config *m_cfg) +{ + MachineState *ms = MACHINE(vms); + int32_t l2vic_phandle = qemu_fdt_alloc_phandle(ms->fdt); + char *nodename = g_strdup_printf("/soc/interrupt-controller@%x", + m_cfg->l2vic_base); + const char compat[] = "qcom,h2-pic\0hvm-pic"; + + qemu_fdt_setprop_cell(ms->fdt, "/soc", "interrupt-parent", l2vic_phandle); + + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 0x1); + qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, + m_cfg->l2vic_base, m_cfg->l2vic_size); + qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", l2vic_phandle); + + g_free(nodename); + return l2vic_phandle; +} + static void fdt_add_hvx(HexagonVirtMachineState *vms, const struct hexagon_machine_config *m_cfg) { @@ -175,13 +199,16 @@ static void fdt_add_cpu_nodes(const HexagonVirtMachineState *vms) } } -static void create_virtio_devices(HexagonVirtMachineState *vms) +static void create_virtio_devices(HexagonVirtMachineState *vms, + int32_t l2vic_phandle) { + MachineState *ms = MACHINE(vms); hwaddr size = base_memmap[VIRT_MMIO].size; for (int i = 0; i < VIRTIO_DEV_COUNT; i++) { int irq = VIRTIO_IRQ_BASE + i; hwaddr base = base_memmap[VIRT_MMIO].base + i * size; + char *nodename = g_strdup_printf("/soc/virtio_mmio@%" PRIx64, base); DeviceState *dev = qdev_new("virtio-mmio"); SysBusDevice *s = SYS_BUS_DEVICE(dev); @@ -192,6 +219,16 @@ static void create_virtio_devices(HexagonVirtMachineState *vms) sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->parent_obj.l2vic, irq)); vms->virtio_mmio[i] = dev; + + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", + "virtio,mmio"); + qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", irq); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", + l2vic_phandle); + + g_free(nodename); } } @@ -251,6 +288,7 @@ static void virt_init(MachineState *ms) HexagonVirtMachineState *vms = HEXAGON_VIRT_MACHINE(ms); const struct hexagon_machine_config *m_cfg = &v68n_1024; int32_t clk_phandle; + int32_t l2vic_phandle; create_fdt(vms); qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline); @@ -272,7 +310,8 @@ static void virt_init(MachineState *ms) fdt_add_hvx(vms, m_cfg); - create_virtio_devices(vms); + l2vic_phandle = fdt_add_l2vic(vms, m_cfg); + create_virtio_devices(vms, l2vic_phandle); g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus); From 5f8e903c02404a8c880b4bfcfbe1589d0a36e911 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:17 -0700 Subject: [PATCH 174/627] hw/hexagon/virt: connect pl011 UART interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire pl011's sysbus IRQ into l2vic at IRQ 15. Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-13-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/virt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index ea20ea3c50..64d8366d27 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -39,6 +39,7 @@ enum { * VIRTIO_IRQ_BASE + VIRTIO_DEV_COUNT - 1 */ static const int VIRTIO_IRQ_BASE = 16; +static const int VIRT_UART0_IRQ = 15; static const MemMapEntry base_memmap[] = { [VIRT_UART0] = { 0x10000000, 0x00000200 }, @@ -143,7 +144,7 @@ static int32_t fdt_add_clocks(const HexagonVirtMachineState *vms) } static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart, - int32_t clk_phandle) + int32_t clk_phandle, int32_t l2vic_phandle) { char *nodename; hwaddr base = base_memmap[uart].base; @@ -161,6 +162,8 @@ static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart, qdev_connect_clock_in(dev, "clk", vms->apb_clk); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); + sysbus_connect_irq(s, 0, + qdev_get_gpio_in(vms->parent_obj.l2vic, VIRT_UART0_IRQ)); nodename = g_strdup_printf("/pl011@%" PRIx64, base); qemu_fdt_add_subnode(ms->fdt, nodename); @@ -168,6 +171,9 @@ static void fdt_add_uart(const HexagonVirtMachineState *vms, int uart, /* Note that we can't use setprop_string because of the embedded NUL */ qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat)); qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", VIRT_UART0_IRQ); + qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", + l2vic_phandle); qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks", clk_phandle, clk_phandle); qemu_fdt_setprop(ms->fdt, nodename, "clock-names", clocknames, @@ -342,7 +348,7 @@ static void virt_init(MachineState *ms) fdt_add_cpu_nodes(vms); clk_phandle = fdt_add_clocks(vms); - fdt_add_uart(vms, VIRT_UART0, clk_phandle); + fdt_add_uart(vms, VIRT_UART0, clk_phandle, l2vic_phandle); hexagon_load_fdt(vms); } From 8ff5b8d403483f76e36ffb30087aacaf1a41fe07 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:18 -0700 Subject: [PATCH 175/627] tests/qtest: add L2VIC qtest Add a qtest exercising L2VIC register access and interrupt enable/disable. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-14-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- MAINTAINERS | 1 + tests/qtest/l2vic-test.c | 249 +++++++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 3 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/l2vic-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 5a772818bb..85fc30503d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -252,6 +252,7 @@ S: Supported F: target/hexagon/ F: hw/intc/hex-l2vic.c F: include/hw/intc/hex-l2vic.h +F: tests/qtest/l2vic-test.c X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/tests/qtest/l2vic-test.c b/tests/qtest/l2vic-test.c new file mode 100644 index 0000000000..adb4dc7281 --- /dev/null +++ b/tests/qtest/l2vic-test.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QTest testcase for the L2VIC Interrupt Controller + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" +#include "hw/hexagon/hexagon.h" + +#include "hw/hexagon/machine_cfg_v66g_1024.h.inc" +#include "hw/hexagon/machine_cfg_v68n_1024.h.inc" + +/* L2VIC register offsets exercised by this test */ +#define L2VIC_INT_ENABLEn 0x100 /* Read/Write */ +#define L2VIC_INT_ENABLE_CLEARn 0x180 /* Write */ +#define L2VIC_INT_ENABLE_SETn 0x200 /* Write */ +#define L2VIC_INT_TYPEn 0x280 /* Read/Write */ +#define L2VIC_INT_STATUSn 0x380 /* Read */ +#define L2VIC_INT_CLEARn 0x400 /* Write */ +#define L2VIC_SOFT_INTn 0x480 /* Write */ +#define L2VIC_INT_PENDINGn 0x500 /* Read */ +#define L2VIC_INT_GRPn_0 0x600 /* Read/Write */ +#define L2VIC_INT_GRPn_1 0x680 /* Read/Write */ +#define L2VIC_INT_GRPn_2 0x700 /* Read/Write */ +#define L2VIC_INT_GRPn_3 0x780 /* Read/Write */ + +/* + * VID group readback: records which irq last fired through each VID + * group. Outputs themselves are momentary pulses (see l2vic_update()), + * so these registers -- not the qtest IRQ level snapshot -- are how the + * test observes VID steering. + */ +#define L2VIC_VID_GRP_0 0x0 +#define L2VIC_VID_GRP_1 0x4 +#define L2VIC_VID_GRP_2 0x8 +#define L2VIC_VID_GRP_3 0xC + +typedef struct { + const char *machine; + const struct hexagon_machine_config *cfg; +} L2VICMachineCfg; + +static const L2VICMachineCfg l2vic_machines[] = { + { "virt", &v68n_1024 }, + { "V66G_1024", &v66g_1024 }, +}; + +static uint32_t l2vic_read32(uint64_t base, uint32_t offset) +{ + return readl(base + offset); +} + +static void l2vic_write32(uint64_t base, uint32_t offset, uint32_t value) +{ + writel(base + offset, value); +} + +static void test_l2vic_register_access(uint64_t base) +{ + uint32_t val; + + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x1); + val = l2vic_read32(base, L2VIC_INT_ENABLEn); + g_assert_cmpuint(val & 0x1, ==, 0x1); + + l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0x1); + val = l2vic_read32(base, L2VIC_INT_ENABLEn); + g_assert_cmpuint(val & 0x1, ==, 0x0); +} + +static void test_l2vic_interrupt_enable(uint64_t base) +{ + uint32_t val; + + val = l2vic_read32(base, L2VIC_INT_ENABLEn); + g_assert_cmpuint(val, ==, 0); + + /* Enable IRQ 0 and 2 */ + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x5); + val = l2vic_read32(base, L2VIC_INT_ENABLEn); + g_assert_cmpuint(val & 0x5, ==, 0x5); + + /* Disable IRQ 0, leaving IRQ 2 enabled */ + l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0x1); + val = l2vic_read32(base, L2VIC_INT_ENABLEn); + g_assert_cmpuint(val & 0x1, ==, 0x0); + g_assert_cmpuint(val & 0x4, ==, 0x4); +} + +static void test_l2vic_basic_functionality(uint64_t base) +{ + l2vic_read32(base, L2VIC_INT_ENABLEn); + l2vic_read32(base, L2VIC_INT_PENDINGn); + l2vic_read32(base, L2VIC_INT_STATUSn); + l2vic_read32(base, L2VIC_INT_TYPEn); + + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0); + l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0); +} + +/* + * IRQs 0-7 pack their group-enable/VID-select nibbles into + * L2VIC_INT_GRPn_0 (int_group_n[0]), 4 bits per irq: bit 3 enables + * VID steering, bits 0-2 select the VID group (0-3), which pulses + * output line vid+2. + */ +static void l2vic_set_vid_group(uint64_t base, int irq, int vid) +{ + uint32_t val = l2vic_read32(base, L2VIC_INT_GRPn_0); + uint32_t nibble = 0x8 | (vid & 0x7); + + val &= ~(0xFu << (irq * 4)); + val |= nibble << (irq * 4); + l2vic_write32(base, L2VIC_INT_GRPn_0, val); +} + +static void test_l2vic_irq_outputs(uint64_t base) +{ + uint32_t val; + + l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0xFFFFFFFF); + l2vic_write32(base, L2VIC_INT_CLEARn, 0xFFFFFFFF); + l2vic_write32(base, L2VIC_INT_TYPEn, 0); + l2vic_write32(base, L2VIC_INT_GRPn_0, 0); + + /* Group 0 / IRQ2: soft interrupts require edge-triggered config */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x1); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x1); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x1); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x1, ==, 0x1); + /* Default VID group (0) records the delivering irq, output line 2 */ + g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_0), ==, 0); + + l2vic_write32(base, L2VIC_INT_CLEARn, 0x1); + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x1, ==, 0x0); + + /* IRQ1 steered to VID group 1 -> output line 3 */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x2); + l2vic_set_vid_group(base, 1, 1); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x2); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x2); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x2, ==, 0x2); + g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_1), ==, 1); + + l2vic_write32(base, L2VIC_INT_CLEARn, 0x2); + + /* IRQ4 steered to VID group 2 -> output line 4 */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x10); + l2vic_set_vid_group(base, 4, 2); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x10); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x10); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x10, ==, 0x10); + g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_2), ==, 4); + + l2vic_write32(base, L2VIC_INT_CLEARn, 0x10); + + /* IRQ5 steered to VID group 3 -> output line 5 */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x20); + l2vic_set_vid_group(base, 5, 3); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x20); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x20); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x20, ==, 0x20); + g_assert_cmpuint(l2vic_read32(base, L2VIC_VID_GRP_3), ==, 5); + + l2vic_write32(base, L2VIC_INT_CLEARn, 0x20); + + /* Restore defaults; the block below reuses IRQ 3-5 without VID steering */ + l2vic_write32(base, L2VIC_INT_GRPn_0, 0); + l2vic_write32(base, L2VIC_INT_TYPEn, 0); + + /* Multiple pending: at most one active at a time */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0xF); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0xF); + l2vic_write32(base, L2VIC_SOFT_INTn, 0xF); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0xF, !=, 0x0); + + /* + * Only one irq becomes active per delivery; each clear unblocks the + * next pending one, so drain until all four have been delivered. + */ + while ((val = l2vic_read32(base, L2VIC_INT_STATUSn)) & 0xF) { + l2vic_write32(base, L2VIC_INT_CLEARn, val & 0xF); + } + + /* Level-triggered sources ignore soft interrupts */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x0); + l2vic_write32(base, L2VIC_INT_ENABLE_SETn, 0x20); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x20); + + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x20, ==, 0x0); + + /* Same source, now edge-triggered, does fire */ + l2vic_write32(base, L2VIC_INT_TYPEn, 0x20); + l2vic_write32(base, L2VIC_SOFT_INTn, 0x20); + val = l2vic_read32(base, L2VIC_INT_STATUSn); + g_assert_cmpuint(val & 0x20, ==, 0x20); + + l2vic_write32(base, L2VIC_INT_ENABLE_CLEARn, 0xFFFFFFFF); + l2vic_write32(base, L2VIC_INT_CLEARn, 0xFFFFFFFF); + l2vic_write32(base, L2VIC_INT_GRPn_0, 0); + l2vic_write32(base, L2VIC_INT_GRPn_1, 0); + l2vic_write32(base, L2VIC_INT_GRPn_2, 0); + l2vic_write32(base, L2VIC_INT_GRPn_3, 0); +} + +static void test_l2vic_on_machine(gconstpointer data) +{ + const L2VICMachineCfg *mc = data; + g_autofree char *args = g_strdup_printf("-machine %s", mc->machine); + uint64_t base = mc->cfg->l2vic_base; + + qtest_start(args); + + test_l2vic_register_access(base); + test_l2vic_interrupt_enable(base); + test_l2vic_basic_functionality(base); + test_l2vic_irq_outputs(base); + + qtest_end(); +} + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < ARRAY_SIZE(l2vic_machines); i++) { + g_autofree char *path = g_strdup_printf("/l2vic/%s/all-tests", + l2vic_machines[i].machine); + qtest_add_data_func(path, &l2vic_machines[i], test_l2vic_on_machine); + } + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 56ff860e21..a76863c7dd 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -299,7 +299,7 @@ qtests_riscv64 = ['riscv-csr-test'] + \ ['iommu-riscv-test'] : []) + \ (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) -qtests_hexagon = ['boot-serial-test'] +qtests_hexagon = ['boot-serial-test', 'l2vic-test'] qos_test_ss = ss.source_set() qos_test_ss.add( From 240f3620af7048fea14e0e7daf4ffeab8f6bc820 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:19 -0700 Subject: [PATCH 176/627] tests/functional/hexagon: add arch_tests functional test Add the test_int_steering case from hexagon-arch-tests. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-15-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/functional/hexagon/test_arch_tests.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/functional/hexagon/test_arch_tests.py b/tests/functional/hexagon/test_arch_tests.py index 54a1412c59..2bb34f9b8d 100755 --- a/tests/functional/hexagon/test_arch_tests.py +++ b/tests/functional/hexagon/test_arch_tests.py @@ -52,6 +52,12 @@ class ArchTestsUart(QemuSystemTest): """ self.run_uart_test("test_guest_mode") + def test_int_steering(self) -> None: + """Tests interrupt steering via priority-based routing to + specific threads using STID priority and iassignw. + """ + self.run_uart_test("test_int_steering") + if __name__ == "__main__": QemuSystemTest.main() From 954f0cec387e78fcbb6847f42bdd0c6794a5ed6e Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:20 -0700 Subject: [PATCH 177/627] hw/timer: Add QCT QTimer device model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the QCT QTimer generic timer device used by Hexagon DSP systems. Co-authored-by: Damien Hedde Co-authored-by: Tobias Röhmel Co-authored-by: Sid Manning Co-authored-by: Thomas Marceron Co-authored-by: Mahmoud Kamel Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-16-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- MAINTAINERS | 2 + hw/timer/Kconfig | 3 + hw/timer/meson.build | 2 + hw/timer/qct-qtimer.c | 667 ++++++++++++++++++++++++++++++++++ hw/timer/trace-events | 5 + include/hw/timer/qct-qtimer.h | 43 +++ 6 files changed, 722 insertions(+) create mode 100644 hw/timer/qct-qtimer.c create mode 100644 include/hw/timer/qct-qtimer.h diff --git a/MAINTAINERS b/MAINTAINERS index 85fc30503d..b252d2e5de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -253,6 +253,8 @@ F: target/hexagon/ F: hw/intc/hex-l2vic.c F: include/hw/intc/hex-l2vic.h F: tests/qtest/l2vic-test.c +F: hw/timer/qct-qtimer.c +F: include/hw/timer/qct-qtimer.h X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index b3d823ce2c..e1b751a54a 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -65,3 +65,6 @@ config STELLARIS_GPTM config AVR_TIMER16 bool + +config HEX_QTIMER + bool diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 201b5d8316..8323efaf46 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -34,3 +34,5 @@ specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_timer.c')) system_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) system_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c')) + +system_ss.add(when: 'CONFIG_HEX_QTIMER', if_true: files('qct-qtimer.c')) diff --git a/hw/timer/qct-qtimer.c b/hw/timer/qct-qtimer.c new file mode 100644 index 0000000000..f628e8d263 --- /dev/null +++ b/hw/timer/qct-qtimer.c @@ -0,0 +1,667 @@ +/* + * Qualcomm QCT QTimer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/irq.h" +#include "hw/core/qdev-properties.h" +#include "hw/core/sysbus.h" +#include "hw/timer/qct-qtimer.h" +#include "migration/vmstate.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "trace.h" + +#define QTIMER_MEM_SIZE_BYTES 0x1000 +#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL + +#define QCT_QTIMER_TIMER_FRAME_ELTS (16) +#define QCT_QTIMER_TIMER_VIEW_ELTS (2) + +#define QCT_QTIMER_AC_CNTFRQ (0x000) +#define QCT_QTIMER_AC_CNTSR (0x004) +#define QCT_QTIMER_AC_CNTTID_0 (0x08) +#define QCT_QTIMER_AC_CNTACR_START (0x40) +#define QCT_QTIMER_AC_CNTACR_END (0x5c) +#define QCT_QTIMER_AC_CNTTID_1 (0x108) +#define QCT_QTIMER_AC_CNTACR_RWPT (1 << 5) /* R/W of CNTP_* regs */ +#define QCT_QTIMER_AC_CNTACR_RWVT (1 << 4) /* R/W of CNTV_* regs */ +#define QCT_QTIMER_AC_CNTACR_RVOFF (1 << 3) /* R/W of CNTVOFF register */ +#define QCT_QTIMER_AC_CNTACR_RFRQ (1 << 2) /* R/W of CNTFRQ register */ +#define QCT_QTIMER_AC_CNTACR_RPVCT (1 << 1) /* R/W of CNTVCT register */ +#define QCT_QTIMER_AC_CNTACR_RPCT (1 << 0) /* R/W of CNTPCT register */ +#define QCT_QTIMER_VERSION (0x0fd0) + +#define QCT_QTIMER_CNTPCT_LO (0x000) +#define QCT_QTIMER_CNTPCT_HI (0x004) +#define QCT_QTIMER_CNT_FREQ (0x010) +#define QCT_QTIMER_CNTPL0ACR (0x014) +#define QCT_QTIMER_CNTPL0ACR_PL0CTEN (1 << 9) +#define QCT_QTIMER_CNTPL0ACR_PL0TVEN (1 << 8) +#define QCT_QTIMER_CNTPL0ACR_PL0VCTEN (1 << 1) +#define QCT_QTIMER_CNTPL0ACR_PL0PCTEN (1 << 0) +#define QCT_QTIMER_CNTP_CVAL_LO (0x020) +#define QCT_QTIMER_CNTP_CVAL_HI (0x024) +#define QCT_QTIMER_CNT_MASK 0x00ffffffffffffffULL +#define QCT_QTIMER_CNT_HI_BITS 24 +#define QCT_QTIMER_CNTP_TVAL (0x028) +#define QCT_QTIMER_CNTP_CTL (0x02c) +#define QCT_QTIMER_CNTP_CTL_ENABLE (1 << 0) +#define QCT_QTIMER_CNTP_CTL_INTEN (1 << 1) +#define QCT_QTIMER_CNTP_CTL_ISTAT (1 << 2) + +OBJECT_DECLARE_SIMPLE_TYPE(QCTQtimerState, QCT_QTIMER) + +typedef struct QCTHextimerState { + QCTQtimerState *qtimer; + QEMUTimer *timer; /* one-shot deadline timer */ + int64_t offset_ns; /* QEMU_CLOCK_VIRTUAL ns at which cntpct == 0 */ + uint64_t cntval; /* 64-bit physical timer compare value */ + uint32_t control; + uint32_t cnt_ctrl; + uint32_t cntpl0acr; + uint32_t int_level; + qemu_irq irq; +} QCTHextimerState; + +struct QCTQtimerState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegion view_iomem; + uint32_t secure; + QCTHextimerState timer[QCT_QTIMER_TIMER_FRAME_ELTS]; + uint32_t freq_hz; + uint32_t nr_frames; + uint32_t nr_views; + uint32_t frame_stride; + uint32_t freq_scale; +}; + +/* + * QTimer version register: + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Major | Minor | Step | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define QCT_QTIMER_VERSION_VALUE 0x20020000 + +static uint32_t qct_qtimer_cnttid(QCTQtimerState *s, unsigned int half) +{ + uint32_t nibble = 0x1 | (s->nr_views > 1 ? 0x4 : 0x0); + uint32_t base = half * 8; + uint32_t cnttid = 0; + unsigned int i; + + for (i = 0; i < 8; i++) { + if (base + i < s->nr_frames) { + cnttid |= nibble << (i * 4); + } + } + return cnttid; +} + +/* Counter value derived on-demand from QEMU_CLOCK_VIRTUAL. */ +static uint64_t hex_timer_now(QCTHextimerState *s) +{ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint32_t scale; + uint64_t scaled_elapsed; + + if (now <= s->offset_ns) { + return 0; + } + scale = MAX(s->qtimer->freq_scale, 1u); + scaled_elapsed = (uint64_t)(now - s->offset_ns) / scale; + return muldiv64(scaled_elapsed, s->qtimer->freq_hz, + NANOSECONDS_PER_SECOND) & + QCT_QTIMER_CNT_MASK; +} + +/* Arm (or disarm) the one-shot deadline timer. */ +static void hex_timer_rearm(QCTHextimerState *s) +{ + uint32_t scale; + uint64_t base_ns; + int64_t deadline_ns; + + if (!(s->control & QCT_QTIMER_CNTP_CTL_ENABLE)) { + timer_del(s->timer); + return; + } + + scale = MAX(s->qtimer->freq_scale, 1u); + /* + * Round the ticks-to-ns conversion up so that hex_timer_now(), which + * truncates when it divides elapsed ns by scale, is guaranteed to + * report >= cntval once this deadline fires. A truncating conversion + * here could re-arm at the same deadline forever when scale > 1. + */ + base_ns = muldiv64_round_up(s->cntval, NANOSECONDS_PER_SECOND, + s->qtimer->freq_hz); + if (base_ns > + ((uint64_t)INT64_MAX - (uint64_t)s->offset_ns) / scale) { + timer_del(s->timer); + return; + } + deadline_ns = s->offset_ns + (int64_t)(base_ns * scale); + timer_mod(s->timer, deadline_ns); +} + +static void hex_timer_update(QCTHextimerState *s) +{ + int level = s->int_level && + (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) && + !(s->control & QCT_QTIMER_CNTP_CTL_INTEN); + + trace_qtimer_interrupt(); + qemu_set_irq(s->irq, level); +} + +/* + * Access-control (AC) region: offsets below 0x1000, gates CNTFRQ/CNTSR/ + * CNTTID/CNTACR per frame plus the shared VERSION register. + */ +static uint64_t qct_qtimer_ac_read(void *opaque, hwaddr offset, unsigned size) +{ + QCTQtimerState *s = opaque; + uint32_t frame; + + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + return s->freq_hz; + case QCT_QTIMER_AC_CNTSR: + return s->secure; + case QCT_QTIMER_AC_CNTTID_0: + return qct_qtimer_cnttid(s, 0); + case QCT_QTIMER_AC_CNTTID_1: + return qct_qtimer_cnttid(s, 1); + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame = (offset - QCT_QTIMER_AC_CNTACR_START) / 4; + if (frame >= s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTACR offset 0x%x\n", + __func__, (int)offset); + return 0; + } + return s->timer[frame].cnt_ctrl; + case QCT_QTIMER_VERSION: + return QCT_QTIMER_VERSION_VALUE; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return 0; + } +} + +static void qct_qtimer_ac_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + QCTQtimerState *s = opaque; + uint32_t frame; + + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + if (value == 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTFRQ value 0\n", + __func__); + return; + } + s->freq_hz = value; + return; + case QCT_QTIMER_AC_CNTSR: + if (value > 0xff) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTSR value 0x%x\n", + __func__, (int)value); + return; + } + s->secure = value; + return; + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame = (offset - QCT_QTIMER_AC_CNTACR_START) / 4; + if (frame >= s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTACR offset 0x%x\n", + __func__, (int)offset); + return; + } + s->timer[frame].cnt_ctrl = value; + return; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return; + } +} + +static const MemoryRegionOps qct_qtimer_ac_ops = { + .read = qct_qtimer_ac_read, + .write = qct_qtimer_ac_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +/* + * View region: a flat array of (frame, view) slots, each frame_stride + * bytes wide, holding the per-frame CNTPCT/CNTP_CVAL/CNTP_TVAL/CNTP_CTL + * register set. + */ +static QCTHextimerState *qct_qtimer_demux(QCTQtimerState *s, hwaddr offset, + uint32_t *reg_offset, + uint32_t *view) +{ + uint32_t stride = s->frame_stride; + uint32_t stride_shift = ctz32(stride); + uint32_t slot_nr = offset >> stride_shift; + uint32_t frame = slot_nr / s->nr_views; + + *reg_offset = offset & (stride - 1); + *view = slot_nr % s->nr_views; + if (frame >= s->nr_frames) { + return NULL; + } + return &s->timer[frame]; +} + +/* Frames 8+ are described by CNTTID_1; each frame's 2nd view is a gated bit. */ +static bool qct_qtimer_view_visible(QCTQtimerState *s, uint32_t frame, + uint32_t view) +{ + uint32_t cnttid = qct_qtimer_cnttid(s, frame < 8 ? 0 : 1); + uint32_t frame_idx = frame < 8 ? frame : frame - 8; + + return !view || (cnttid & (0x4 << (frame_idx * 4))); +} + +static bool access_ok(QCTHextimerState *s, uint32_t reg_offset, uint32_t view) +{ + uint32_t acr; + uint32_t pl0acr; + + switch (reg_offset) { + case QCT_QTIMER_CNT_FREQ: + acr = QCT_QTIMER_AC_CNTACR_RFRQ; + pl0acr = QCT_QTIMER_CNTPL0ACR_PL0PCTEN | + QCT_QTIMER_CNTPL0ACR_PL0VCTEN; + break; + case QCT_QTIMER_CNTPCT_LO: + case QCT_QTIMER_CNTPCT_HI: + acr = QCT_QTIMER_AC_CNTACR_RPCT; + pl0acr = QCT_QTIMER_CNTPL0ACR_PL0PCTEN; + break; + case QCT_QTIMER_CNTP_CVAL_LO: + case QCT_QTIMER_CNTP_CVAL_HI: + case QCT_QTIMER_CNTP_TVAL: + case QCT_QTIMER_CNTP_CTL: + acr = QCT_QTIMER_AC_CNTACR_RWPT; + pl0acr = QCT_QTIMER_CNTPL0ACR_PL0CTEN; + break; + default: + /* CNTPL0ACR and VERSION are ungated. */ + return true; + } + + if (!(s->cnt_ctrl & acr)) { + return false; + } + return !view || (s->cntpl0acr & pl0acr); +} + +static MemTxResult hex_timer_read(void *opaque, hwaddr offset, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + QCTQtimerState *qs = opaque; + uint32_t reg_offset; + uint32_t view; + QCTHextimerState *s = qct_qtimer_demux(qs, offset, ®_offset, &view); + uint32_t frame; + + if (!s) { + *data = 0; + return MEMTX_ACCESS_ERROR; + } + frame = s - qs->timer; + + trace_qtimer_read(offset); + + if (!qct_qtimer_view_visible(qs, frame, view)) { + *data = 0; + return MEMTX_OK; + } + + if (!access_ok(s, reg_offset, view)) { + return MEMTX_ACCESS_ERROR; + } + + switch (reg_offset) { + case QCT_QTIMER_CNT_FREQ: + *data = s->qtimer->freq_hz; + return MEMTX_OK; + case QCT_QTIMER_CNTP_CVAL_LO: + *data = extract64(s->cntval, 0, 32); + return MEMTX_OK; + case QCT_QTIMER_CNTP_CVAL_HI: + /* HI half is 24-bit per TRM; bits [31:24] are reserved. */ + *data = extract64(s->cntval, 32, QCT_QTIMER_CNT_HI_BITS); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_LO: + *data = extract64(hex_timer_now(s), 0, 32); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_HI: + *data = extract64(hex_timer_now(s), 32, QCT_QTIMER_CNT_HI_BITS); + return MEMTX_OK; + case QCT_QTIMER_CNTP_TVAL: + *data = (uint32_t)(int32_t)(int64_t)(s->cntval - hex_timer_now(s)); + return MEMTX_OK; + case QCT_QTIMER_CNTP_CTL: + /* + * CNTP_CTL: bit 0 EN, bit 1 IMASK, bit 2 ISTAT (interrupt + * pending). ISTAT tracks int_level and is read-only. + */ + *data = s->control | ((s->int_level & 0x1) << 2); + return MEMTX_OK; + case QCT_QTIMER_CNTPL0ACR: + *data = view ? 0 : s->cntpl0acr; + return MEMTX_OK; + case QCT_QTIMER_VERSION: + *data = QCT_QTIMER_VERSION_VALUE; + return MEMTX_OK; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + *data = 0; + return MEMTX_ACCESS_ERROR; + } +} + +static MemTxResult hex_timer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + QCTQtimerState *qs = opaque; + uint32_t reg_offset; + uint32_t view; + QCTHextimerState *s = qct_qtimer_demux(qs, offset, ®_offset, &view); + uint32_t frame; + + if (!s) { + return MEMTX_ACCESS_ERROR; + } + frame = s - qs->timer; + + trace_qtimer_write(offset, value); + + if (!qct_qtimer_view_visible(qs, frame, view)) { + return MEMTX_OK; + } + + if (!access_ok(s, reg_offset, view)) { + return MEMTX_ACCESS_ERROR; + } + + switch (reg_offset) { + case QCT_QTIMER_CNTP_CVAL_LO: + s->int_level = 0; + s->cntval = deposit64(s->cntval, 0, 32, value); + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_CVAL_HI: + s->int_level = 0; + /* HI half is 24-bit per TRM; bits [31:24] are reserved. */ + s->cntval = deposit64(s->cntval, 32, QCT_QTIMER_CNT_HI_BITS, value) & + QCT_QTIMER_CNT_MASK; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_CTL: + /* ISTAT (bit 2) is read-only; keep SW writes from polluting it. */ + s->control = value & ~QCT_QTIMER_CNTP_CTL_ISTAT; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_TVAL: + /* TVAL write: CVAL = CNTPCT + TVAL (TVAL is signed 32-bit). */ + s->int_level = 0; + s->cntval = (hex_timer_now(s) + (int64_t)(int32_t)value) & + QCT_QTIMER_CNT_MASK; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTPL0ACR: + if (!view) { + s->cntpl0acr = value; + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return MEMTX_ACCESS_ERROR; + } + hex_timer_update(s); + return MEMTX_OK; +} + +static void hex_timer_tick(void *opaque) +{ + QCTHextimerState *s = opaque; + uint64_t now = hex_timer_now(s); + uint64_t diff56 = (now - s->cntval) & QCT_QTIMER_CNT_MASK; + int64_t signed_diff = (int64_t)(diff56 << 8) >> 8; + + if (signed_diff >= 0) { + s->int_level = 1; + hex_timer_update(s); + } else { + hex_timer_rearm(s); + } +} + +static const MemoryRegionOps hex_timer_ops = { + .read_with_attrs = hex_timer_read, + .write_with_attrs = hex_timer_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const VMStateDescription vmstate_qct_hextimer = { + .name = "qct-hextimer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(control, QCTHextimerState), + VMSTATE_UINT32(cnt_ctrl, QCTHextimerState), + VMSTATE_INT64(offset_ns, QCTHextimerState), + VMSTATE_UINT64(cntval, QCTHextimerState), + VMSTATE_UINT32(cntpl0acr, QCTHextimerState), + VMSTATE_UINT32(int_level, QCTHextimerState), + VMSTATE_TIMER_PTR(timer, QCTHextimerState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_qct_qtimer = { + .name = "qct-qtimer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(freq_hz, QCTQtimerState), + VMSTATE_UINT32(secure, QCTQtimerState), + VMSTATE_STRUCT_VARRAY_UINT32(timer, QCTQtimerState, nr_frames, + 1, vmstate_qct_hextimer, QCTHextimerState), + VMSTATE_END_OF_LIST() + } +}; + +static void qct_qtimer_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + QCTQtimerState *s = QCT_QTIMER(dev); + unsigned int i; + + if (s->nr_frames > QCT_QTIMER_TIMER_FRAME_ELTS) { + error_setg(errp, "nr_frames too high"); + return; + } + if (s->nr_views > QCT_QTIMER_TIMER_VIEW_ELTS) { + error_setg(errp, "nr_views too high"); + return; + } + if (s->freq_hz == 0) { + error_setg(errp, "freq-hz must be nonzero"); + return; + } + if (s->frame_stride == 0 || !is_power_of_2(s->frame_stride)) { + error_setg(errp, "frame_stride must be a nonzero power of two"); + return; + } + + memory_region_init_io(&s->iomem, OBJECT(s), &qct_qtimer_ac_ops, s, + "qct-qtimer-ac", QTIMER_MEM_SIZE_BYTES); + sysbus_init_mmio(sbd, &s->iomem); + + memory_region_init_io(&s->view_iomem, OBJECT(s), &hex_timer_ops, s, + "qct-qtimer-view", + (uint64_t)s->frame_stride * s->nr_frames * + s->nr_views); + sysbus_init_mmio(sbd, &s->view_iomem); + + for (i = 0; i < s->nr_frames; i++) { + QCTHextimerState *t = &s->timer[i]; + + t->qtimer = s; + s->secure |= (1 << i); + + sysbus_init_irq(sbd, &t->irq); + t->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hex_timer_tick, t); + } +} + +static void qct_qtimer_unrealize(DeviceState *dev) +{ + QCTQtimerState *s = QCT_QTIMER(dev); + unsigned int i; + + for (i = 0; i < s->nr_frames; i++) { + QCTHextimerState *t = &s->timer[i]; + + if (t->timer) { + timer_free(t->timer); + t->timer = NULL; + } + } +} + +static void qct_qtimer_reset_hold(Object *obj, ResetType type) +{ + QCTQtimerState *s = QCT_QTIMER(obj); + unsigned int i; + + for (i = 0; i < s->nr_frames; i++) { + QCTHextimerState *t = &s->timer[i]; + + /* + * Per TRM: CTL = 0 (EN=0, IMASK=0, ISTAT=0), CVAL = 0 so that + * TVAL (= CVAL - CNTPCT) also reads 0 at reset. The QEMUTimer is + * only armed when SW sets CTL.EN=1, so cntval=0 does not cause a + * spurious fire before SW programs the compare value. + */ + t->control = 0; + t->cnt_ctrl = QCT_QTIMER_AC_CNTACR_RWPT | QCT_QTIMER_AC_CNTACR_RWVT | + QCT_QTIMER_AC_CNTACR_RVOFF | QCT_QTIMER_AC_CNTACR_RFRQ | + QCT_QTIMER_AC_CNTACR_RPVCT | QCT_QTIMER_AC_CNTACR_RPCT; + t->cntval = 0; + t->cntpl0acr = 0; + t->int_level = 0; + t->offset_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + timer_del(t->timer); + qemu_set_irq(t->irq, 0); + } +} + +static const Property qct_qtimer_properties[] = { + DEFINE_PROP_UINT32("freq-hz", QCTQtimerState, freq_hz, + QTIMER_DEFAULT_FREQ_HZ), + DEFINE_PROP_UINT32("freq-scale", QCTQtimerState, freq_scale, 1), + DEFINE_PROP_UINT32("nr_frames", QCTQtimerState, nr_frames, 2), + DEFINE_PROP_UINT32("nr_views", QCTQtimerState, nr_views, 1), + DEFINE_PROP_UINT32("frame_stride", QCTQtimerState, frame_stride, 0x1000), +}; + +static void qct_qtimer_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + device_class_set_props(dc, qct_qtimer_properties); + dc->realize = qct_qtimer_realize; + dc->unrealize = qct_qtimer_unrealize; + dc->vmsd = &vmstate_qct_qtimer; + rc->phases.hold = qct_qtimer_reset_hold; +} + +/* QTimer interface implementation, backing HEX_SREG_TIMERLO/TIMERHI */ +static uint32_t qct_qtimer_get_timer_lo_impl(const QctQtimerInterface *obj) +{ + QCTQtimerState *s = QCT_QTIMER((QctQtimerInterface *)obj); + + return s->nr_frames > 0 ? extract64(hex_timer_now(&s->timer[0]), 0, 32) + : 0; +} + +static uint32_t qct_qtimer_get_timer_hi_impl(const QctQtimerInterface *obj) +{ + QCTQtimerState *s = QCT_QTIMER((QctQtimerInterface *)obj); + + return s->nr_frames > 0 ? extract64(hex_timer_now(&s->timer[0]), 32, 32) + : 0; +} + +static void qct_qtimer_interface_class_init(ObjectClass *klass, + const void *data) +{ + QctQtimerInterfaceClass *k = QCT_QTIMER_INTERFACE_CLASS(klass); + + k->get_timer_lo = qct_qtimer_get_timer_lo_impl; + k->get_timer_hi = qct_qtimer_get_timer_hi_impl; +} + +static const TypeInfo qct_qtimer_types[] = { + { + .name = TYPE_QCT_QTIMER_INTERFACE, + .parent = TYPE_INTERFACE, + .class_size = sizeof(QctQtimerInterfaceClass), + .class_init = qct_qtimer_interface_class_init, + }, + { + .name = TYPE_QCT_QTIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(QCTQtimerState), + .class_init = qct_qtimer_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_QCT_QTIMER_INTERFACE }, + { } + }, + }, +}; + +DEFINE_TYPES(qct_qtimer_types) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 634ba1da27..636310f8ca 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -128,3 +128,8 @@ imx_epit_get_freq(uint32_t freq) "ptimer frequency is %u" imx_epit_read(const char *name, uint32_t value) "(%s) = 0x%08x" imx_epit_write(const char *name, uint64_t value) "(%s, value = 0x%08" PRIx64 ")" imx_epit_cmp(uint32_t sr) "sr was %d" + +# qct-qtimer.c +qtimer_interrupt(void) "qtimer interrupt line updated" +qtimer_read(uint64_t offset) "offset 0x%" PRIx64 +qtimer_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 diff --git a/include/hw/timer/qct-qtimer.h b/include/hw/timer/qct-qtimer.h new file mode 100644 index 0000000000..53d8291472 --- /dev/null +++ b/include/hw/timer/qct-qtimer.h @@ -0,0 +1,43 @@ +/* + * Qualcomm QCT QTimer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_TIMER_QCT_QTIMER_H +#define HW_TIMER_QCT_QTIMER_H + +#include "qom/object.h" + +#define TYPE_QCT_QTIMER "qct-qtimer" + +/* QTimer interface for external access from hexagon_globalreg */ +#define TYPE_QCT_QTIMER_INTERFACE "qct-qtimer-if" + +typedef struct QctQtimerInterface QctQtimerInterface; + +typedef struct QctQtimerInterfaceClass { + InterfaceClass parent_class; + + /* Read the live physical counter, backing HEX_SREG_TIMERLO/TIMERHI */ + uint32_t (*get_timer_lo)(const QctQtimerInterface *qtimer); + uint32_t (*get_timer_hi)(const QctQtimerInterface *qtimer); +} QctQtimerInterfaceClass; + +DECLARE_OBJ_CHECKERS(QctQtimerInterface, QctQtimerInterfaceClass, + QCT_QTIMER_INTERFACE, TYPE_QCT_QTIMER_INTERFACE); + +static inline uint32_t qct_qtimer_get_timer_lo(const QctQtimerInterface *qtimer) +{ + QctQtimerInterfaceClass *k = QCT_QTIMER_INTERFACE_GET_CLASS(qtimer); + return k->get_timer_lo(qtimer); +} + +static inline uint32_t qct_qtimer_get_timer_hi(const QctQtimerInterface *qtimer) +{ + QctQtimerInterfaceClass *k = QCT_QTIMER_INTERFACE_GET_CLASS(qtimer); + return k->get_timer_hi(qtimer); +} + +#endif /* HW_TIMER_QCT_QTIMER_H */ From 57eaab1e8c8d7c1624591b1aeb668f14c3a8131d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:21 -0700 Subject: [PATCH 178/627] hw/hexagon: connect qtimer device Add the QTimer to the shared hex-subsys so both machine models pick it up. Map its view region, wire its interrupt lines into l2vic, and link it to the globalreg device backing HEX_SREG_TIMERLO/TIMERHI. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-17-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- hw/hexagon/Kconfig | 1 + hw/hexagon/hex-subsys.c | 28 ++++++++++++++++++++++++++ hw/hexagon/hexagon_globalreg.c | 17 ++++++++++++++++ include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/hexagon_globalreg.h | 4 ++++ 5 files changed, 51 insertions(+) diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index c75090c44a..83b2763d1e 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -4,6 +4,7 @@ config HEX_DSP depends on HEXAGON select CPU_CLUSTER select HEX_L2VIC + select HEX_QTIMER config HEX_VIRT bool diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c index 25c028f657..4e3a418340 100644 --- a/hw/hexagon/hex-subsys.c +++ b/hw/hexagon/hex-subsys.c @@ -11,6 +11,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "hw/cpu/cluster.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" @@ -20,6 +21,11 @@ #define HEX_L2VIC_CPU_IRQS 8 +/* Number of QTimer frames instantiated for every Hexagon machine. */ +#define HEX_QTIMER_NR_FRAMES 3 + +#define HEX_QTIMER_L2VIC_IRQ_BASE 2 + static DeviceState *l2vic_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg) { @@ -43,6 +49,25 @@ static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu) } } +static DeviceState *qtimer_create(HexagonCommonMachineState *hms, + const struct hexagon_machine_config *m_cfg) +{ + DeviceState *qtimer = qdev_new(TYPE_QCT_QTIMER); + + object_property_add_child(OBJECT(hms), "qtimer", OBJECT(qtimer)); + qdev_prop_set_uint32(qtimer, "nr_frames", HEX_QTIMER_NR_FRAMES); + sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 0, m_cfg->csr_base); + sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_region); + for (unsigned int i = 0; i < HEX_QTIMER_NR_FRAMES; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), i, + qdev_get_gpio_in(hms->l2vic, + HEX_QTIMER_L2VIC_IRQ_BASE + i)); + } + + return qtimer; +} + static DeviceState *globalreg_create(HexagonCommonMachineState *hms, const struct hexagon_machine_config *m_cfg, Rev_t rev) @@ -54,6 +79,8 @@ static DeviceState *globalreg_create(HexagonCommonMachineState *hms, qdev_prop_set_uint32(glob_regs, "dsp-rev", rev); object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic), &error_fatal); + object_property_set_link(OBJECT(glob_regs), "qtimer", OBJECT(hms->qtimer), + &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal); return glob_regs; @@ -110,6 +137,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms, hms->cluster = cluster_create(hms); hms->l2vic = l2vic_create(hms, m_cfg); + hms->qtimer = qtimer_create(hms, m_cfg); hms->glob_regs = globalreg_create(hms, m_cfg, rev); hms->tlb = tlb_create(hms, m_cfg); } diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c index 285cb48c44..61621cf2b8 100644 --- a/hw/hexagon/hexagon_globalreg.c +++ b/hw/hexagon/hexagon_globalreg.c @@ -12,6 +12,7 @@ #include "hw/core/sysbus.h" #include "hw/core/resettable.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "migration/vmstate.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -141,11 +142,21 @@ static inline bool is_vid_reg(uint32_t reg) return reg == HEX_SREG_VID || reg == HEX_SREG_VID1; } +static inline bool is_timer_reg(uint32_t reg) +{ + return reg == HEX_SREG_TIMERLO || reg == HEX_SREG_TIMERHI; +} + static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg) { if (is_vid_reg(reg)) { return l2vic_read_vid(s->l2vic, reg == HEX_SREG_VID ? 0 : 1); } + if (is_timer_reg(reg)) { + return reg == HEX_SREG_TIMERLO ? + qct_qtimer_get_timer_lo(s->qtimer) : + qct_qtimer_get_timer_hi(s->qtimer); + } return s->regs[reg]; } @@ -289,6 +300,10 @@ static void hexagon_globalreg_realize(DeviceState *dev, Error **errp) error_setg(errp, "hexagon_globalreg: 'l2vic' link property not set"); return; } + if (!s->qtimer) { + error_setg(errp, "hexagon_globalreg: 'qtimer' link property not set"); + return; + } } static const VMStateDescription vmstate_hexagon_globalreg = { @@ -312,6 +327,8 @@ static const VMStateDescription vmstate_hexagon_globalreg = { static const Property hexagon_globalreg_properties[] = { DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic, TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *), + DEFINE_PROP_LINK("qtimer", HexagonGlobalRegState, qtimer, + TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *), DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0), DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState, config_table_addr, 0xffffffffULL), diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index ec1578807d..3d7b3cb12d 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -159,6 +159,7 @@ struct HexagonCommonMachineState { MemoryRegion vtcm; DeviceState *cluster; DeviceState *l2vic; + DeviceState *qtimer; DeviceState *glob_regs; DeviceState *tlb; }; diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/hexagon_globalreg.h index 397dc6854c..07437dfabb 100644 --- a/include/hw/hexagon/hexagon_globalreg.h +++ b/include/hw/hexagon/hexagon_globalreg.h @@ -11,6 +11,7 @@ #include "hw/core/qdev.h" #include "hw/core/sysbus.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "qom/object.h" #include "target/hexagon/cpu.h" @@ -26,6 +27,9 @@ struct HexagonGlobalRegState { /* L2VIC interface used to back the VID/VID1 registers */ HexL2VicInterface *l2vic; + /* QTimer interface used to back the TIMERLO/TIMERHI registers */ + QctQtimerInterface *qtimer; + /* Global performance cycle counter base */ uint64_t g_pcycle_base; From 71d618d3aa64bd7a33d8fc14fff6f3051ad633c2 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:22 -0700 Subject: [PATCH 179/627] tests/qtest: add qct-qtimer qtest Add a qtest exercising the QCT QTimer's register access, view-region frame addressing, and one-shot timer firing behavior. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-18-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- MAINTAINERS | 1 + tests/qtest/meson.build | 2 +- tests/qtest/qct-qtimer-test.c | 385 ++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/qct-qtimer-test.c diff --git a/MAINTAINERS b/MAINTAINERS index b252d2e5de..8db47c48fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -255,6 +255,7 @@ F: include/hw/intc/hex-l2vic.h F: tests/qtest/l2vic-test.c F: hw/timer/qct-qtimer.c F: include/hw/timer/qct-qtimer.h +F: tests/qtest/qct-qtimer-test.c X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index a76863c7dd..651246b2eb 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -299,7 +299,7 @@ qtests_riscv64 = ['riscv-csr-test'] + \ ['iommu-riscv-test'] : []) + \ (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) -qtests_hexagon = ['boot-serial-test', 'l2vic-test'] +qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test'] qos_test_ss = ss.source_set() qos_test_ss.add( diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c new file mode 100644 index 0000000000..fd8bb0af77 --- /dev/null +++ b/tests/qtest/qct-qtimer-test.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QTest testcase for the QCT QTimer + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" +#include "hw/hexagon/hexagon.h" +#include "qemu/bitops.h" + +#include "hw/hexagon/machine_cfg_v68n_1024.h.inc" +#include "hw/hexagon/machine_cfg_v66g_1024.h.inc" + +#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL + +#define QCT_QTIMER_CNTPCT_LO (0x000) +#define QCT_QTIMER_CNTPCT_HI (0x004) +#define QCT_QTIMER_CNT_FREQ (0x010) +#define QCT_QTIMER_CNTP_CVAL_LO (0x020) +#define QCT_QTIMER_CNTP_TVAL (0x028) +#define QCT_QTIMER_CNTP_CTL (0x02c) +#define QCT_QTIMER_CNTP_CTL_ENABLE (1 << 0) + +#define QTIMER_FRAME_STRIDE 0x1000 +/* Frames instantiated by hex-subsys, and the L2VIC input frame 0 drives. */ +#define QTIMER_NR_FRAMES 3 +#define QTIMER_L2VIC_IRQ_BASE 2 + +#define QCT_QTIMER_AC_CNTFRQ (0x000) +#define QCT_QTIMER_AC_CNTSR (0x004) +#define QCT_QTIMER_AC_CNTTID_0 (0x08) +#define QCT_QTIMER_AC_CNTACR_START (0x40) +#define QCT_QTIMER_AC_CNTACR_ALL (0x3f) +#define QCT_QTIMER_AC_CNTACR_RWPT (1 << 5) /* R/W of CNTP_* regs */ +#define QCT_QTIMER_AC_CNTACR_RFRQ (1 << 2) /* R/W of CNTFRQ register */ +#define QCT_QTIMER_AC_CNTACR_RPCT (1 << 0) /* R/W of CNTPCT register */ + +static uint64_t qtimer_view_base; +static uint64_t qtimer_ac_base; + +#define TIMER_TEST_OFFSET 1000 +/* TIMER_TEST_OFFSET ticks expressed in nanoseconds of QEMU_CLOCK_VIRTUAL */ +#define TIMER_TEST_NS \ + ((TIMER_TEST_OFFSET * 1000000000ULL) / QTIMER_DEFAULT_FREQ_HZ) + +static uint32_t qtimer_read32(uint64_t base, uint32_t offset) +{ + return readl(base + offset); +} + +static void qtimer_write32(uint64_t base, uint32_t offset, uint32_t value) +{ + writel(base + offset, value); +} + +static uint64_t qtimer_read64(uint64_t base, uint32_t offset) +{ + uint32_t lo = qtimer_read32(base, offset); + uint32_t hi = qtimer_read32(base, offset + 4); + + return ((uint64_t)hi << 32) | lo; +} + +static void qtimer_write64(uint64_t base, uint32_t offset, uint64_t value) +{ + qtimer_write32(base, offset, extract64(value, 0, 32)); + qtimer_write32(base, offset + 4, extract64(value, 32, 32)); +} + +static void test_qtimer_basic_access(void) +{ + uint32_t val; + + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ); +} + +static void test_qtimer_multiple_frames(void) +{ + uint32_t val; + uint64_t frame0_base = qtimer_view_base; + uint64_t frame1_base = qtimer_view_base + 0x1000; + + val = qtimer_read32(frame0_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ); + + val = qtimer_read32(frame1_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ); +} + +static void test_qtimer_register_reads(void) +{ + qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ); + qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL); +} + +static void test_qtimer_control_registers(void) +{ + uint32_t ctl_val; + uint64_t cval_before, cval_after; + + cval_before = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL, 1000); + + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1); + ctl_val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(ctl_val & 1, ==, 1); + + /* CVAL should be greater than before since we set TVAL */ + cval_after = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(cval_after, >, cval_before); + + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 0); + ctl_val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(ctl_val & 1, ==, 0); +} + +static void test_qtimer_cval_access(void) +{ + uint64_t current_time, test_cval, read_cval; + + current_time = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + test_cval = current_time + 10000; + + qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, test_cval); + read_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(read_cval, ==, test_cval); +} + +static void test_qtimer_counter_progression(void) +{ + uint32_t freq; + uint64_t count1, count2; + + /* + * In qtest mode the virtual clock does not advance on its own, so + * reading the counter twice must give the same value. + */ + count1 = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + count2 = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(count2, ==, count1); + + freq = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ); +} + +static void test_qtimer_timer_behavior(void) +{ + uint64_t current_count, target_count, read_cval, new_count; + uint64_t ctl_val, count_after_disable; + + current_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + + target_count = current_count + TIMER_TEST_OFFSET; + qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, target_count); + + read_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(read_cval, ==, target_count); + + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1); + + ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + /* EN set, IMASK clear, ISTAT not yet pending */ + g_assert_cmpuint(ctl_val, ==, 0x1); + + /* Step forward but not past the target */ + qtest_clock_step(global_qtest, TIMER_TEST_NS / 2); + new_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(new_count, >=, current_count); + + /* Step past the target */ + qtest_clock_step(global_qtest, TIMER_TEST_NS); + new_count = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(new_count, >=, target_count); + + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 0); + + ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + /* EN cleared, ISTAT set since new_count >= target_count */ + g_assert_cmpuint(ctl_val, ==, 0x4); + + /* + * CNTPCT runs independently of CNTP_CTL.EN: only the compare/IRQ + * logic is gated by EN, so the counter must keep advancing. + */ + qtest_clock_step(global_qtest, TIMER_TEST_NS / 2); + count_after_disable = qtimer_read64(qtimer_view_base, + QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(count_after_disable, >, new_count); + + /* ISTAT remains set while CNTPCT >= CVAL, even with EN=0 */ + ctl_val = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(ctl_val, ==, 0x4); +} + +/* Test the access-control region: CNTFRQ, CNTSR, CNTTID_0, CNTACR frame 0 */ +static void test_qtimer_ac_region(void) +{ + uint32_t freq, sr, tid0, acr0; + + freq = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ); + g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ); + + /* A write of 0 to CNTFRQ must be ignored (freq-hz must stay nonzero). */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ, 0); + freq = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTFRQ); + g_assert_cmpuint(freq, ==, QTIMER_DEFAULT_FREQ_HZ); + + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTSR, 0x3); + sr = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTSR); + g_assert_cmpuint(sr, ==, 0x3); + + tid0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTTID_0); + g_assert_cmpuint(tid0, ==, 0x111); + + /* CNTACR for frame 0 defaults to full read/write permissions. */ + acr0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START); + g_assert_cmpuint(acr0, !=, 0); + + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, 0); + acr0 = qtimer_read32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START); + g_assert_cmpuint(acr0, ==, 0); + + /* Restore full permissions so later view-region tests keep working. */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, + QCT_QTIMER_AC_CNTACR_ALL); +} + +static void test_qtimer_access_denied(void) +{ + uint32_t acr_all = QCT_QTIMER_AC_CNTACR_ALL; + uint64_t cval, saved_cval; + uint32_t val; + + /* Park CVAL at a known nonzero value while access is still permitted. */ + saved_cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTPCT_LO) + 10000; + qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, saved_cval); + g_assert_cmpuint(qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO), + ==, saved_cval); + + /* Clearing RFRQ denies CNTFRQ reads. */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, + acr_all & ~QCT_QTIMER_AC_CNTACR_RFRQ); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, ==, 0); + + /* Clearing RPCT denies CNTPCT reads, both halves. */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, + acr_all & ~QCT_QTIMER_AC_CNTACR_RPCT); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(val, ==, 0); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTPCT_HI); + g_assert_cmpuint(val, ==, 0); + + /* + * Clearing RWPT denies the whole CNTP_* set: CVAL/TVAL/CTL reads all + * read back 0 even though CVAL holds saved_cval. + */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, + acr_all & ~QCT_QTIMER_AC_CNTACR_RWPT); + cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(cval, ==, 0); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL); + g_assert_cmpuint(val, ==, 0); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(val, ==, 0); + + /* Denied writes must be dropped rather than applied. */ + qtimer_write64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO, 0x1234); + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_TVAL, 0x5678); + qtimer_write32(qtimer_view_base, QCT_QTIMER_CNTP_CTL, 1); + + /* Restoring RWPT reveals that CVAL still holds the pre-denial value. */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, acr_all); + cval = qtimer_read64(qtimer_view_base, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(cval, ==, saved_cval); + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(val & 1, ==, 0); + + /* CNTFRQ and CNTPCT work again once permissions are back. */ + val = qtimer_read32(qtimer_view_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, ==, QTIMER_DEFAULT_FREQ_HZ); + + /* + * An unimplemented offset in the view region is also an access error, + * and reads back as 0. + */ + val = qtimer_read32(qtimer_view_base, 0x100); + g_assert_cmpuint(val, ==, 0); + + /* Leave the frame with full permissions for any later test. */ + qtimer_write32(qtimer_ac_base, QCT_QTIMER_AC_CNTACR_START, acr_all); +} + +static void test_qtimer_frame_irq_routing(void) +{ + unsigned int frame, other; + uint64_t frame_base; + + qtest_irq_intercept_in(global_qtest, "/machine/l2vic"); + + for (frame = 0; frame < QTIMER_NR_FRAMES; frame++) { + frame_base = qtimer_view_base + frame * QTIMER_FRAME_STRIDE; + + qtimer_write32(frame_base, QCT_QTIMER_CNTP_TVAL, TIMER_TEST_OFFSET); + qtimer_write32(frame_base, QCT_QTIMER_CNTP_CTL, + QCT_QTIMER_CNTP_CTL_ENABLE); + g_assert_false(qtest_get_irq(global_qtest, + QTIMER_L2VIC_IRQ_BASE + frame)); + + /* Step past the deadline so the frame raises its interrupt. */ + qtest_clock_step(global_qtest, TIMER_TEST_NS * 2); + g_assert_true(qtest_get_irq(global_qtest, + QTIMER_L2VIC_IRQ_BASE + frame)); + + /* No other frame's line may be disturbed. */ + for (other = 0; other < QTIMER_NR_FRAMES; other++) { + if (other != frame) { + g_assert_false(qtest_get_irq(global_qtest, + QTIMER_L2VIC_IRQ_BASE + other)); + } + } + + /* Clearing EN drops the interrupt, leaving a clean slate. */ + qtimer_write32(frame_base, QCT_QTIMER_CNTP_CTL, 0); + g_assert_false(qtest_get_irq(global_qtest, + QTIMER_L2VIC_IRQ_BASE + frame)); + } +} + +typedef struct { + const char *machine; + const struct hexagon_machine_config *cfg; +} QtimerMachineCfg; + +static const QtimerMachineCfg qtimer_machines[] = { + { "virt", &v68n_1024 }, + { "V66G_1024", &v66g_1024 }, +}; + +static void test_qtimer_on_machine(gconstpointer data) +{ + const QtimerMachineCfg *mc = data; + g_autofree char *args = g_strdup_printf( + "-machine %s -global qct-qtimer.freq-scale=1", mc->machine); + + qtimer_view_base = mc->cfg->qtmr_region; + qtimer_ac_base = mc->cfg->csr_base; + + qtest_start(args); + + test_qtimer_basic_access(); + test_qtimer_multiple_frames(); + test_qtimer_register_reads(); + test_qtimer_control_registers(); + test_qtimer_cval_access(); + test_qtimer_counter_progression(); + test_qtimer_timer_behavior(); + test_qtimer_ac_region(); + test_qtimer_access_denied(); + test_qtimer_frame_irq_routing(); + + qtest_end(); +} + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < ARRAY_SIZE(qtimer_machines); i++) { + g_autofree char *path = g_strdup_printf("/qct-qtimer/%s/all-tests", + qtimer_machines[i].machine); + qtest_add_data_func(path, &qtimer_machines[i], test_qtimer_on_machine); + } + + return g_test_run(); +} From 701eb2ac98ba543a3a458a7fcaf8cc0f5e469ed4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 5 Aug 2026 21:27:23 -0700 Subject: [PATCH 180/627] tests/functional/hexagon: enable more arch_tests cases Add more tests from hexagon-arch-tests, enabled by QTimer device. These exercise cache maintenance ops, l2vic, thread start/stop, tlb/mmu operations, and user-mode transitions. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260806042723.3785369-19-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/functional/hexagon/test_arch_tests.py | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/functional/hexagon/test_arch_tests.py b/tests/functional/hexagon/test_arch_tests.py index 2bb34f9b8d..0834398c3b 100755 --- a/tests/functional/hexagon/test_arch_tests.py +++ b/tests/functional/hexagon/test_arch_tests.py @@ -58,6 +58,38 @@ class ArchTestsUart(QemuSystemTest): """ self.run_uart_test("test_int_steering") + def test_cache(self) -> None: + """Tests cache operations: dckill/ickill, l2kill, dczeroa, + dccleaninva, cache disable/enable, barriers, and dcinva/dccleana. + """ + self.run_uart_test("test_cache") + + def test_l2vic(self) -> None: + """Tests the L2VIC interrupt controller: enable readback, + interrupt type readback, VID capture, and the fast interface. + """ + self.run_uart_test("test_l2vic") + + def test_threads(self) -> None: + """Tests hardware thread management: start/stop, MODECTL state, + per-thread HTID, shared memory, wait/resume, STID priority, and + SCHEDCFG/BESTWAIT readback. + """ + self.run_uart_test("test_threads") + + def test_tlb_mmu(self) -> None: + """Tests TLB/MMU operations: write/read/probe/invalidate, + global entries, multiple entries, overwrite, ASID matching, + and permission checks. + """ + self.run_uart_test("test_tlb_mmu") + + def test_user_mode(self) -> None: + """Tests user mode / privilege transitions: supervisor mode, + SSR UM/IE/XE/CE/PE bits, and the trap0 user-mode exit handler. + """ + self.run_uart_test("test_user_mode") + if __name__ == "__main__": QemuSystemTest.main() From 9e96b5953e2fb619a5ad6274ebba3baee0b933c4 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:35 -0700 Subject: [PATCH 181/627] host-utils: fix ssub32/64_saturate return type and clamp direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ssub32_saturate() and ssub64_saturate() were declared to return bool instead of int32_t/int64_t, and clamped to the wrong bound on overflow. Reviewed-by: Philippe Mathieu-Daudé Cc: qemu-stable@nongnu.org Fixes: 16495533131 ("host-utils: Introduce signed saturation primitives") Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-2-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- include/qemu/host-utils.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 2e8da7fb3d..1db9dbb138 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -607,10 +607,10 @@ static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret) } /** - * sadd32_saturate - addition with saturation + * sadd32_saturate - 32-bit signed addition with saturation * @x, @y: addends * - * Computes @x + @y, and saturates rathern than truncating the result. + * Computes @x + @y, and saturates rather than truncating the result. */ static inline int32_t sadd32_saturate(int32_t x, int32_t y) { @@ -622,10 +622,10 @@ static inline int32_t sadd32_saturate(int32_t x, int32_t y) } /** - * sadd64_saturate - addition with saturation + * sadd64_saturate - 64-bit signed addition with saturation * @x, @y: addends * - * Computes @x + @y, and saturates rathern than truncating the result. + * Computes @x + @y, and saturates rather than truncating the result. */ static inline int64_t sadd64_saturate(int64_t x, int64_t y) { @@ -637,31 +637,31 @@ static inline int64_t sadd64_saturate(int64_t x, int64_t y) } /** - * ssub32_saturate - subtraction with saturation + * ssub32_saturate - 32-bit signed subtraction with saturation * @x, @y: addends * - * Computes @x + @y, and saturates rathern than truncating the result. + * Computes @x - @y, and saturates rather than truncating the result. */ -static inline bool ssub32_saturate(int32_t x, int32_t y) +static inline int32_t ssub32_saturate(int32_t x, int32_t y) { int32_t ret; if (ssub32_overflow(x, y, &ret)) { - ret = x < 0 ? INT32_MAX : INT32_MIN; + ret = x < 0 ? INT32_MIN : INT32_MAX; } return ret; } /** - * ssub64_saturate - subtraction with saturation + * ssub64_saturate - 64-bit signed subtraction with saturation * @x, @y: addends * - * Computes @x + @y, and saturates rathern than truncating the result. + * Computes @x - @y, and saturates rather than truncating the result. */ -static inline bool ssub64_saturate(int64_t x, int64_t y) +static inline int64_t ssub64_saturate(int64_t x, int64_t y) { int64_t ret; if (ssub64_overflow(x, y, &ret)) { - ret = x < 0 ? INT64_MAX : INT64_MIN; + ret = x < 0 ? INT64_MIN : INT64_MAX; } return ret; } From 8c53023a26ec397fadaf3fd10404df1be57d2816 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:36 -0700 Subject: [PATCH 182/627] target/hexagon: add GVec overrides for HVX saturating add/sub Reviewed-by: Marco Liebel Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-3-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_hvx.h | 87 ++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index 0da64d467e..289ce89959 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -234,6 +234,93 @@ static inline void assert_vhist_tmp(DisasContext *ctx) tcg_gen_gvec_sub(MO_32, VddV_off, VuuV_off, VvvV_off, \ sizeof(MMVector) * 2, sizeof(MMVector) * 2) +#define fGEN_TCG_V6_vaddbsat(SHORTCODE) \ + tcg_gen_gvec_ssadd(MO_8, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vaddhsat(SHORTCODE) \ + tcg_gen_gvec_ssadd(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vaddwsat(SHORTCODE) \ + tcg_gen_gvec_ssadd(MO_32, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vaddubsat(SHORTCODE) \ + tcg_gen_gvec_usadd(MO_8, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vadduhsat(SHORTCODE) \ + tcg_gen_gvec_usadd(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vadduwsat(SHORTCODE) \ + tcg_gen_gvec_usadd(MO_32, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_PAIR_ADDSUB(OP, VECE, DST, SRC_A, SRC_B) \ + tcg_gen_gvec_##OP(VECE, DST, SRC_A, SRC_B, \ + 2 * VECTOR_SIZE_BYTE, 2 * VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vaddbsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ssadd, MO_8, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vaddhsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ssadd, MO_16, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vaddwsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ssadd, MO_32, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vaddubsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(usadd, MO_8, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vadduhsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(usadd, MO_16, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vadduwsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(usadd, MO_32, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsubbsat(SHORTCODE) \ + tcg_gen_gvec_sssub(MO_8, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsubhsat(SHORTCODE) \ + tcg_gen_gvec_sssub(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsubwsat(SHORTCODE) \ + tcg_gen_gvec_sssub(MO_32, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsububsat(SHORTCODE) \ + tcg_gen_gvec_ussub(MO_8, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsubuhsat(SHORTCODE) \ + tcg_gen_gvec_ussub(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsubuwsat(SHORTCODE) \ + tcg_gen_gvec_ussub(MO_32, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vsubbsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(sssub, MO_8, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsubhsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(sssub, MO_16, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsubwsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(sssub, MO_32, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsububsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ussub, MO_8, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsubuhsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ussub, MO_16, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vsubuwsat_dv(SHORTCODE) \ + fGEN_TCG_PAIR_ADDSUB(ussub, MO_32, VddV_off, VuuV_off, VvvV_off) /* Vector shift right - various forms */ #define fGEN_TCG_V6_vasrh(SHORTCODE) \ do { \ From d47d794ea2c7b3f5baa8d57fbe496c755119e0da Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:37 -0700 Subject: [PATCH 183/627] target/hexagon: add GVec override for HVX vmpyih multiply Reviewed-by: Marco Liebel Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-4-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_hvx.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index 289ce89959..7e5372a764 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -321,6 +321,11 @@ static inline void assert_vhist_tmp(DisasContext *ctx) #define fGEN_TCG_V6_vsubuwsat_dv(SHORTCODE) \ fGEN_TCG_PAIR_ADDSUB(ussub, MO_32, VddV_off, VuuV_off, VvvV_off) + +#define fGEN_TCG_V6_vmpyih(SHORTCODE) \ + tcg_gen_gvec_mul(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + /* Vector shift right - various forms */ #define fGEN_TCG_V6_vasrh(SHORTCODE) \ do { \ From 234d8cb6f2e95cc5078b232943e47bc4f56170c3 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:38 -0700 Subject: [PATCH 184/627] target/hexagon: add GVec overrides for HVX absolute difference Reviewed-by: Marco Liebel Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-5-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_hvx.h | 16 +++++++++ target/hexagon/genptr.c | 70 ++++++++++++++++++++++++++++++++++++ target/hexagon/genptr.h | 4 +++ target/hexagon/helper.h | 5 +++ target/hexagon/op_helper.c | 21 +++++++++++ 5 files changed, 116 insertions(+) diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index 7e5372a764..cbf84a8cae 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -326,6 +326,22 @@ static inline void assert_vhist_tmp(DisasContext *ctx) tcg_gen_gvec_mul(MO_16, VdV_off, VuV_off, VvV_off, \ VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) +#define fGEN_TCG_V6_vabsdiffub(SHORTCODE) \ + gen_gvec_uabsdiff(MO_8, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vabsdiffuh(SHORTCODE) \ + gen_gvec_uabsdiff(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vabsdiffh(SHORTCODE) \ + gen_gvec_sabsdiff(MO_16, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + +#define fGEN_TCG_V6_vabsdiffw(SHORTCODE) \ + gen_gvec_sabsdiff(MO_32, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) + /* Vector shift right - various forms */ #define fGEN_TCG_V6_vasrh(SHORTCODE) \ do { \ diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 12813f48bf..2a98b13b71 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -37,6 +37,76 @@ #include "genptr.h" +static void gen_sabsdiff_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_sub_i32(t, a, b); + tcg_gen_sub_i32(d, b, a); + tcg_gen_movcond_i32(TCG_COND_LT, d, a, b, d, t); +} + +static void gen_sabsdiff_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_smin_vec(vece, t, a, b); + tcg_gen_smax_vec(vece, d, a, b); + tcg_gen_sub_vec(vece, d, d, t); +} + +void gen_gvec_sabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0 + }; + static const GVecGen3 ops[4] = { + [MO_16] = { .fniv = gen_sabsdiff_vec, + .fno = gen_helper_gvec_sabsdiff_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + [MO_32] = { .fni4 = gen_sabsdiff_i32, + .fniv = gen_sabsdiff_vec, + .fno = gen_helper_gvec_sabsdiff_w, + .opt_opc = vecop_list, + .vece = MO_32 }, + }; + + tcg_debug_assert(vece == MO_16 || vece == MO_32); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &ops[vece]); +} + +static void gen_uabsdiff_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t = tcg_temp_new_vec_matching(d); + + tcg_gen_umin_vec(vece, t, a, b); + tcg_gen_umax_vec(vece, d, a, b); + tcg_gen_sub_vec(vece, d, d, t); +} + +void gen_gvec_uabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sub_vec, INDEX_op_umin_vec, INDEX_op_umax_vec, 0 + }; + static const GVecGen3 ops[4] = { + [MO_8] = { .fniv = gen_uabsdiff_vec, + .fno = gen_helper_gvec_uabsdiff_b, + .opt_opc = vecop_list, + .vece = MO_8 }, + [MO_16] = { .fniv = gen_uabsdiff_vec, + .fno = gen_helper_gvec_uabsdiff_h, + .opt_opc = vecop_list, + .vece = MO_16 }, + }; + + tcg_debug_assert(vece == MO_8 || vece == MO_16); + tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &ops[vece]); +} + TCGv gen_read_reg(TCGv result, int num) { tcg_gen_mov_tl(result, hex_gpr[num]); diff --git a/target/hexagon/genptr.h b/target/hexagon/genptr.h index 5d09677410..f498398367 100644 --- a/target/hexagon/genptr.h +++ b/target/hexagon/genptr.h @@ -59,6 +59,10 @@ TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign); void gen_set_half(int N, TCGv result, TCGv src); void gen_set_half_i64(int N, TCGv_i64 result, TCGv src); void probe_noshuf_load(TCGv va, int s, int mi); +void gen_gvec_sabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); +void gen_gvec_uabsdiff(unsigned vece, uint32_t dofs, uint32_t aofs, + uint32_t bofs, uint32_t oprsz, uint32_t maxsz); extern const target_ulong reg_immut_masks[TOTAL_PER_THREAD_REGS]; diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 033e5619d6..78dc28ca9e 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -108,6 +108,11 @@ DEF_HELPER_2(probe_pkt_scalar_store_s0, void, env, int) DEF_HELPER_2(probe_hvx_stores, void, env, int) DEF_HELPER_2(probe_pkt_scalar_hvx_stores, void, env, int) +DEF_HELPER_FLAGS_4(gvec_sabsdiff_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabsdiff_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabsdiff_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabsdiff_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + #if !defined(CONFIG_USER_ONLY) DEF_HELPER_3(raise_stack_overflow, void, env, i32, i32) DEF_HELPER_2(swi, void, env, i32) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 8fb3d43c33..23894ff3d2 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -35,6 +35,7 @@ #include "mmvec/macros.h" #include "op_helper.h" #include "cpu_helper.h" +#include "tcg/tcg-gvec-desc.h" #include "translate.h" #ifndef CONFIG_USER_ONLY #include "hw/hexagon/hexagon_globalreg.h" @@ -1961,3 +1962,23 @@ void HELPER(pending_interrupt)(CPUHexagonState *env) printf("ERROR: bogus helper: " #tag "\n") #include "helper_funcs_generated.c.inc" + +#define DO_ABSDIFF(NAME, TYPE, UTYPE) \ +void HELPER(NAME)(void *vd, void *vn, void *vm, uint32_t desc) \ +{ \ + intptr_t i, oprsz = simd_oprsz(desc); \ + UTYPE *d = vd; \ + TYPE *n = vn, *m = vm; \ + \ + for (i = 0; i < oprsz / sizeof(TYPE); i++) { \ + d[i] = n[i] < m[i] ? (UTYPE)m[i] - (UTYPE)n[i] \ + : (UTYPE)n[i] - (UTYPE)m[i]; \ + } \ +} + +DO_ABSDIFF(gvec_sabsdiff_h, int16_t, uint16_t) +DO_ABSDIFF(gvec_sabsdiff_w, int32_t, uint32_t) +DO_ABSDIFF(gvec_uabsdiff_b, uint8_t, uint8_t) +DO_ABSDIFF(gvec_uabsdiff_h, uint16_t, uint16_t) + +#undef DO_ABSDIFF From ffbb6bbca5d0b74fb24ece36356963267f8b34ab Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:39 -0700 Subject: [PATCH 185/627] target/hexagon: add GVec overrides for HVX vector average Reviewed-by: Marco Liebel Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-6-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/gen_tcg_hvx.h | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/target/hexagon/gen_tcg_hvx.h b/target/hexagon/gen_tcg_hvx.h index cbf84a8cae..2a342cdee6 100644 --- a/target/hexagon/gen_tcg_hvx.h +++ b/target/hexagon/gen_tcg_hvx.h @@ -342,6 +342,68 @@ static inline void assert_vhist_tmp(DisasContext *ctx) gen_gvec_sabsdiff(MO_32, VdV_off, VuV_off, VvV_off, \ VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE) +#define fGEN_TCG_VEC_AVG(VECE, SHIFT_FN) \ + do { \ + intptr_t tmpoff = offsetof(CPUHexagonState, vtmp); \ + tcg_gen_gvec_and(MO_64, tmpoff, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + tcg_gen_gvec_xor(MO_64, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + SHIFT_FN(VECE, VdV_off, VdV_off, 1, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + tcg_gen_gvec_add(VECE, VdV_off, tmpoff, VdV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + } while (0) + +#define fGEN_TCG_V6_vavgub(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_8, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavguh(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_16, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavguw(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_32, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavgb(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_8, tcg_gen_gvec_sari) + +#define fGEN_TCG_V6_vavgh(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_16, tcg_gen_gvec_sari) + +#define fGEN_TCG_V6_vavgw(SHORTCODE) \ + fGEN_TCG_VEC_AVG(MO_32, tcg_gen_gvec_sari) + +#define fGEN_TCG_VEC_AVGRND(VECE, SHIFT_FN) \ + do { \ + intptr_t tmpoff = offsetof(CPUHexagonState, vtmp); \ + tcg_gen_gvec_or(MO_64, tmpoff, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + tcg_gen_gvec_xor(MO_64, VdV_off, VuV_off, VvV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + SHIFT_FN(VECE, VdV_off, VdV_off, 1, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + tcg_gen_gvec_sub(VECE, VdV_off, tmpoff, VdV_off, \ + VECTOR_SIZE_BYTE, VECTOR_SIZE_BYTE); \ + } while (0) + +#define fGEN_TCG_V6_vavgubrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_8, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavguhrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_16, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavguwrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_32, tcg_gen_gvec_shri) + +#define fGEN_TCG_V6_vavgbrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_8, tcg_gen_gvec_sari) + +#define fGEN_TCG_V6_vavghrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_16, tcg_gen_gvec_sari) + +#define fGEN_TCG_V6_vavgwrnd(SHORTCODE) \ + fGEN_TCG_VEC_AVGRND(MO_32, tcg_gen_gvec_sari) + /* Vector shift right - various forms */ #define fGEN_TCG_V6_vasrh(SHORTCODE) \ do { \ From ead4d3a8d874f7f59fec909ea17a66b056b39ea5 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:40 -0700 Subject: [PATCH 186/627] tests/tcg/hexagon: add HVX test for V6_vsubwsat saturation Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-7-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/hvx_misc.c | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/tcg/hexagon/hvx_misc.c b/tests/tcg/hexagon/hvx_misc.c index 90c3733da0..641cff59ab 100644 --- a/tests/tcg/hexagon/hvx_misc.c +++ b/tests/tcg/hexagon/hvx_misc.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include int err; @@ -386,6 +388,47 @@ static void test_vsubuwsat_dv(void) check_output_w(__LINE__, 2); } +static void test_vsubwsat(void) +{ + const int32_t x0 = INT32_MIN; + const int32_t y0 = 1; + const int32_t x1 = INT32_MAX; + const int32_t y1 = -1; + HVX_Vector v0; + HVX_Vector v1; + HVX_Vector vres; + + /* INT32_MIN - 1 underflows and must saturate to INT32_MIN */ + memset(expect, 0x12, sizeof(MMVector)); + memset(output, 0x34, sizeof(MMVector)); + + v0 = Q6_V_vsplat_R(x0); + v1 = Q6_V_vsplat_R(y0); + vres = Q6_Vw_vsub_VwVw_sat(v0, v1); + memcpy(&output[0], &vres, sizeof(MMVector)); + + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { + expect[0].w[j] = INT32_MIN; + } + + check_output_w(__LINE__, 1); + + /* INT32_MAX - (-1) overflows and must saturate to INT32_MAX */ + memset(expect, 0x12, sizeof(MMVector)); + memset(output, 0x34, sizeof(MMVector)); + + v0 = Q6_V_vsplat_R(x1); + v1 = Q6_V_vsplat_R(y1); + vres = Q6_Vw_vsub_VwVw_sat(v0, v1); + memcpy(&output[0], &vres, sizeof(MMVector)); + + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { + expect[0].w[j] = INT32_MAX; + } + + check_output_w(__LINE__, 1); +} + static void test_load_tmp_predicated(void) { void *p0 = buffer0; @@ -530,6 +573,7 @@ int main() test_vadduwsat(); test_vsubuwsat_dv(); + test_vsubwsat(); test_load_tmp_predicated(); test_load_cur_predicated(); From dde6dc062adbae1c1a1928a87cc425c310339c2b Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Fri, 7 Aug 2026 08:22:41 -0700 Subject: [PATCH 187/627] tests/tcg/hexagon: add HVX tests for vabsdiff Cover the four vabsdiff variants. The expected value is computed in int64_t to avoid overflowing the source element type. Reviewed-by: Pierrick Bouvier Link: https://lore.kernel.org/qemu-devel/20260807152241.1576334-8-brian.cain@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/hvx_misc.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/tcg/hexagon/hvx_misc.c b/tests/tcg/hexagon/hvx_misc.c index 641cff59ab..32a3661a86 100644 --- a/tests/tcg/hexagon/hvx_misc.c +++ b/tests/tcg/hexagon/hvx_misc.c @@ -317,6 +317,34 @@ TEST_VEC_OP2(vand, vand, , d, 8, &) TEST_VEC_OP2(vor, vor, , d, 8, |) TEST_VEC_OP1(vnot, vnot, , d, 8, ~) +#define TEST_VEC_ABSDIFF(NAME, INTRINSIC, SRC_FIELD, DST_FIELD, \ + CHECK_FIELD, FIELDSZ) \ +static inline void test_##NAME(void) \ +{ \ + HVX_Vector v0; \ + HVX_Vector v1; \ + HVX_Vector vres; \ + for (int i = 0; i < BUFSIZE; i++) { \ + memcpy(&v0, &buffer0[i], sizeof(MMVector)); \ + memcpy(&v1, &buffer1[i], sizeof(MMVector)); \ + vres = INTRINSIC(v0, v1); \ + memcpy(&output[i], &vres, sizeof(MMVector)); \ + } \ + for (int i = 0; i < BUFSIZE; i++) { \ + for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \ + int64_t diff = (int64_t)buffer0[i].SRC_FIELD[j] - \ + (int64_t)buffer1[i].SRC_FIELD[j]; \ + expect[i].DST_FIELD[j] = diff < 0 ? -diff : diff; \ + } \ + } \ + check_output_##CHECK_FIELD(__LINE__, BUFSIZE); \ +} + +TEST_VEC_ABSDIFF(vabsdiffub, Q6_Vub_vabsdiff_VubVub, ub, ub, b, 1) +TEST_VEC_ABSDIFF(vabsdiffuh, Q6_Vuh_vabsdiff_VuhVuh, uh, uh, h, 2) +TEST_VEC_ABSDIFF(vabsdiffh, Q6_Vuh_vabsdiff_VhVh, h, uh, h, 2) +TEST_VEC_ABSDIFF(vabsdiffw, Q6_Vuw_vabsdiff_VwVw, w, uw, w, 4) + TEST_PRED_OP2(pred_or, or, |, "") TEST_PRED_OP2(pred_or_n, or, |, "!") TEST_PRED_OP2(pred_and, and, &, "") @@ -575,6 +603,11 @@ int main() test_vsubuwsat_dv(); test_vsubwsat(); + test_vabsdiffub(); + test_vabsdiffuh(); + test_vabsdiffh(); + test_vabsdiffw(); + test_load_tmp_predicated(); test_load_cur_predicated(); From 19148de4986f9e93392849a0e4fa75244e780e9f Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Mon, 10 Aug 2026 21:22:06 -0600 Subject: [PATCH 188/627] Hexagon (target/hexagon) Clean up disassembly of control and system regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change disassembly of control regs from C{num}/{name} to {name} Change disassembly of system regs from S{num}/r{num} to {name} Signed-off-by: Taylor Simpson Reviewed-by: Brian Cain Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20260811032206.58501-1-ltaylorsimpson@gmail.com Signed-off-by: Brian Cain --- target/hexagon/gen_printinsn.py | 14 +++-- target/hexagon/printinsn.c | 99 +++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/target/hexagon/gen_printinsn.py b/target/hexagon/gen_printinsn.py index d5f969960a..cf1a12adbc 100755 --- a/target/hexagon/gen_printinsn.py +++ b/target/hexagon/gen_printinsn.py @@ -28,13 +28,14 @@ import argparse ## Generate data for printing each instruction (format string + operands) ## def regprinter(m): - str = m.group(1) - str += ":".join(["%d"] * len(m.group(2))) - str += m.group(3) if ("S" in m.group(1)) and (len(m.group(2)) == 1): - str += "/%s" + str = "%s" elif ("C" in m.group(1)) and (len(m.group(2)) == 1): - str += "/%s" + str = "%s" + else: + str = m.group(1) + str += ":".join(["%d"] * len(m.group(2))) + str += m.group(3) return str @@ -142,11 +143,12 @@ def main(): else: regno = ri if len(b) == 1: - f.write(f", insn->regno[{regno}]") if "S" in a: f.write(f", sreg2str(insn->regno[{regno}])") elif "C" in a: f.write(f", creg2str(insn->regno[{regno}])") + else: + f.write(f", insn->regno[{regno}]") elif len(b) == 2: f.write(f", insn->regno[{regno}] + 1" f", insn->regno[{regno}]") else: diff --git a/target/hexagon/printinsn.c b/target/hexagon/printinsn.c index a7e46f4bcd..1673e95421 100644 --- a/target/hexagon/printinsn.c +++ b/target/hexagon/printinsn.c @@ -23,18 +23,105 @@ #include "internal.h" #include "decode.h" -static const char *sreg2str(unsigned int reg) +/* + * Used when there is some sort of error and we can't figure out the real + * system register name + */ +static const char *const generic_sreg_names[256] = { + "S000", "S001", "S002", "S003", "S004", "S005", "S006", "S007", + "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", + "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", + "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", + "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", + "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", + "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", + "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", + "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", + "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", + "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", + "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", + "S096", "S097", "S098", "S099", "S100", "S101", "S102", "S103", + "S104", "S105", "S106", "S107", "S108", "S109", "S110", "S111", + "S112", "S113", "S114", "S115", "S116", "S117", "S118", "S119", + "S120", "S121", "S122", "S123", "S124", "S125", "S126", "S127", + "S128", "S129", "S130", "S131", "S132", "S133", "S134", "S135", + "S136", "S137", "S138", "S139", "S140", "S141", "S142", "S143", + "S144", "S145", "S146", "S147", "S148", "S149", "S150", "S151", + "S152", "S153", "S154", "S155", "S156", "S157", "S158", "S159", + "S160", "S161", "S162", "S163", "S164", "S165", "S166", "S167", + "S168", "S169", "S170", "S171", "S172", "S173", "S174", "S175", + "S176", "S177", "S178", "S179", "S180", "S181", "S182", "S183", + "S184", "S185", "S186", "S187", "S188", "S189", "S190", "S191", + "S192", "S193", "S194", "S195", "S196", "S197", "S198", "S199", + "S200", "S201", "S202", "S203", "S204", "S205", "S206", "S207", + "S208", "S209", "S210", "S211", "S212", "S213", "S214", "S215", + "S216", "S217", "S218", "S219", "S220", "S221", "S222", "S223", + "S224", "S225", "S226", "S227", "S228", "S229", "S230", "S231", + "S232", "S233", "S234", "S235", "S236", "S237", "S238", "S239", + "S240", "S241", "S242", "S243", "S244", "S245", "S246", "S247", + "S248", "S249", "S250", "S251", "S252", "S253", "S254", "S255", +}; + +static const char *sreg2str(uint8_t reg) { - if (reg < TOTAL_PER_THREAD_REGS) { - return hexagon_regnames[reg]; +#ifndef CONFIG_USER_ONLY + if (reg < NUM_SREGS) { + return hexagon_sregnames[reg]; } else { - return "???"; + return generic_sreg_names[reg]; } +#else + return generic_sreg_names[reg]; +#endif } -static const char *creg2str(unsigned int reg) +/* + * Used when there is some sort of error and we can't figure out the real + * control register name + */ +static const char *const generic_creg_names[256] = { + "C000", "C001", "C002", "C003", "C004", "C005", "C006", "C007", + "C008", "C009", "C010", "C011", "C012", "C013", "C014", "C015", + "C016", "C017", "C018", "C019", "C020", "C021", "C022", "C023", + "C024", "C025", "C026", "C027", "C028", "C029", "C030", "C031", + "C032", "C033", "C034", "C035", "C036", "C037", "C038", "C039", + "C040", "C041", "C042", "C043", "C044", "C045", "C046", "C047", + "C048", "C049", "C050", "C051", "C052", "C053", "C054", "C055", + "C056", "C057", "C058", "C059", "C060", "C061", "C062", "C063", + "C064", "C065", "C066", "C067", "C068", "C069", "C070", "C071", + "C072", "C073", "C074", "C075", "C076", "C077", "C078", "C079", + "C080", "C081", "C082", "C083", "C084", "C085", "C086", "C087", + "C088", "C089", "C090", "C091", "C092", "C093", "C094", "C095", + "C096", "C097", "C098", "C099", "C100", "C101", "C102", "C103", + "C104", "C105", "C106", "C107", "C108", "C109", "C110", "C111", + "C112", "C113", "C114", "C115", "C116", "C117", "C118", "C119", + "C120", "C121", "C122", "C123", "C124", "C125", "C126", "C127", + "C128", "C129", "C130", "C131", "C132", "C133", "C134", "C135", + "C136", "C137", "C138", "C139", "C140", "C141", "C142", "C143", + "C144", "C145", "C146", "C147", "C148", "C149", "C150", "C151", + "C152", "C153", "C154", "C155", "C156", "C157", "C158", "C159", + "C160", "C161", "C162", "C163", "C164", "C165", "C166", "C167", + "C168", "C169", "C170", "C171", "C172", "C173", "C174", "C175", + "C176", "C177", "C178", "C179", "C180", "C181", "C182", "C183", + "C184", "C185", "C186", "C187", "C188", "C189", "C190", "C191", + "C192", "C193", "C194", "C195", "C196", "C197", "C198", "C199", + "C200", "C201", "C202", "C203", "C204", "C205", "C206", "C207", + "C208", "C209", "C210", "C211", "C212", "C213", "C214", "C215", + "C216", "C217", "C218", "C219", "C220", "C221", "C222", "C223", + "C224", "C225", "C226", "C227", "C228", "C229", "C230", "C231", + "C232", "C233", "C234", "C235", "C236", "C237", "C238", "C239", + "C240", "C241", "C242", "C243", "C244", "C245", "C246", "C247", + "C248", "C249", "C250", "C251", "C252", "C253", "C254", "C255", +}; + +static const char *creg2str(uint8_t reg) { - return sreg2str(reg + HEX_REG_SA0); + uint8_t gpr = reg + HEX_REG_SA0; + if (gpr < TOTAL_PER_THREAD_REGS) { + return hexagon_regnames[gpr]; + } else { + return generic_creg_names[reg]; + } } static void snprintinsn(GString *buf, Insn *insn) From 770e282e50e6f6bafe76c3e6b41f9cc8acef7ad9 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:51 -0700 Subject: [PATCH 189/627] target/hexagon: fix incorrect/too-permissive HVX encodings The following encodings have become stricter since v68: - V6_vunpackob, V6_vunpackoh: ---00 -> --000 - V6_vaddbq/hq/wq, V6_vaddbnq/hnq/wnq: ---01 -> --001 - V6_vsubbq/hq, V6_vsubwq/bnq/hnq/wnq: ---01/---10 -> --001/--010 - V6_vhist, V6_vwhist128/256, V6_vwhist128/256_sat: ---00 -> --000 - V6_vhistq, V6_vwhist128/256q, V6_vwhist128/256q_sat: ---10 -> --010 Pre v68 compilers, by default, already use "0" for the non-specified bit that changed in v68, so unless someone is manually writing the binary encoding, this should not cause any backwards incompatibility with pre-v68 binaries. Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/1fe4b8a0fcae6705a591b1b5131e28f6d8062eed.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/imported/mmvec/encode_ext.def | 48 ++++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 402438f566..6d70086b5f 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -647,36 +647,36 @@ DEF_ENC(V6_vsubububb_sat, ICLASS_CJ" 1 110 101 vvvvv PP 0 uuuuu 101 ddddd") DEF_ENC(V6_vmpyewuh_64, ICLASS_CJ" 1 110 101 vvvvv PP 0 uuuuu 110 ddddd") DEF_FIELDROW_DESC32( ICLASS_CJ" 1 110 --0 ----- PP 1 ----- ----- ---","Vx32=Vu32") -DEF_ENC(V6_vunpackob, ICLASS_CJ" 1 110 --0 ---00 PP 1 uuuuu 000 xxxxx") // -DEF_ENC(V6_vunpackoh, ICLASS_CJ" 1 110 --0 ---00 PP 1 uuuuu 001 xxxxx") // +DEF_ENC(V6_vunpackob, ICLASS_CJ" 1 110 --0 --000 PP 1 uuuuu 000 xxxxx") // +DEF_ENC(V6_vunpackoh, ICLASS_CJ" 1 110 --0 --000 PP 1 uuuuu 001 xxxxx") // //DEF_ENC(V6_vunpackow, ICLASS_CJ" 1 110 --0 ---00 PP 1 uuuuu 010 xxxxx") // -DEF_ENC(V6_vhist, ICLASS_CJ" 1 110 --0 ---00 PP 1 -000- 100 -----") -DEF_ENC(V6_vwhist256, ICLASS_CJ" 1 110 --0 ---00 PP 1 -0010 100 -----") -DEF_ENC(V6_vwhist256_sat, ICLASS_CJ" 1 110 --0 ---00 PP 1 -0011 100 -----") -DEF_ENC(V6_vwhist128, ICLASS_CJ" 1 110 --0 ---00 PP 1 -010- 100 -----") -DEF_ENC(V6_vwhist128m, ICLASS_CJ" 1 110 --0 ---00 PP 1 -011i 100 -----") +DEF_ENC(V6_vhist, ICLASS_CJ" 1 110 --0 --000 PP 1 -000- 100 -----") +DEF_ENC(V6_vwhist256, ICLASS_CJ" 1 110 --0 --000 PP 1 -0010 100 -----") +DEF_ENC(V6_vwhist256_sat, ICLASS_CJ" 1 110 --0 --000 PP 1 -0011 100 -----") +DEF_ENC(V6_vwhist128, ICLASS_CJ" 1 110 --0 --000 PP 1 -010- 100 -----") +DEF_ENC(V6_vwhist128m, ICLASS_CJ" 1 110 --0 --000 PP 1 -011i 100 -----") DEF_FIELDROW_DESC32( ICLASS_CJ" 1 110 --0 ----- PP 1 ----- ----- ---","if (Qv4) Vx32=Vu32") -DEF_ENC(V6_vaddbq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 000 xxxxx") // -DEF_ENC(V6_vaddhq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 001 xxxxx") // -DEF_ENC(V6_vaddwq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 010 xxxxx") // -DEF_ENC(V6_vaddbnq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 011 xxxxx") // -DEF_ENC(V6_vaddhnq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 100 xxxxx") // -DEF_ENC(V6_vaddwnq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 101 xxxxx") // -DEF_ENC(V6_vsubbq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 110 xxxxx") // -DEF_ENC(V6_vsubhq, ICLASS_CJ" 1 110 vv0 ---01 PP 1 uuuuu 111 xxxxx") // +DEF_ENC(V6_vaddbq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 000 xxxxx") // +DEF_ENC(V6_vaddhq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 001 xxxxx") // +DEF_ENC(V6_vaddwq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 010 xxxxx") // +DEF_ENC(V6_vaddbnq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 011 xxxxx") // +DEF_ENC(V6_vaddhnq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 100 xxxxx") // +DEF_ENC(V6_vaddwnq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 101 xxxxx") // +DEF_ENC(V6_vsubbq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 110 xxxxx") // +DEF_ENC(V6_vsubhq, ICLASS_CJ" 1 110 vv0 --001 PP 1 uuuuu 111 xxxxx") // -DEF_ENC(V6_vsubwq, ICLASS_CJ" 1 110 vv0 ---10 PP 1 uuuuu 000 xxxxx") // -DEF_ENC(V6_vsubbnq, ICLASS_CJ" 1 110 vv0 ---10 PP 1 uuuuu 001 xxxxx") // -DEF_ENC(V6_vsubhnq, ICLASS_CJ" 1 110 vv0 ---10 PP 1 uuuuu 010 xxxxx") // -DEF_ENC(V6_vsubwnq, ICLASS_CJ" 1 110 vv0 ---10 PP 1 uuuuu 011 xxxxx") // +DEF_ENC(V6_vsubwq, ICLASS_CJ" 1 110 vv0 --010 PP 1 uuuuu 000 xxxxx") // +DEF_ENC(V6_vsubbnq, ICLASS_CJ" 1 110 vv0 --010 PP 1 uuuuu 001 xxxxx") // +DEF_ENC(V6_vsubhnq, ICLASS_CJ" 1 110 vv0 --010 PP 1 uuuuu 010 xxxxx") // +DEF_ENC(V6_vsubwnq, ICLASS_CJ" 1 110 vv0 --010 PP 1 uuuuu 011 xxxxx") // -DEF_ENC(V6_vhistq, ICLASS_CJ" 1 110 vv0 ---10 PP 1 --00- 100 -----") -DEF_ENC(V6_vwhist256q, ICLASS_CJ" 1 110 vv0 ---10 PP 1 --010 100 -----") -DEF_ENC(V6_vwhist256q_sat, ICLASS_CJ" 1 110 vv0 ---10 PP 1 --011 100 -----") -DEF_ENC(V6_vwhist128q, ICLASS_CJ" 1 110 vv0 ---10 PP 1 --10- 100 -----") -DEF_ENC(V6_vwhist128qm, ICLASS_CJ" 1 110 vv0 ---10 PP 1 --11i 100 -----") +DEF_ENC(V6_vhistq, ICLASS_CJ" 1 110 vv0 --010 PP 1 --00- 100 -----") +DEF_ENC(V6_vwhist256q, ICLASS_CJ" 1 110 vv0 --010 PP 1 --010 100 -----") +DEF_ENC(V6_vwhist256q_sat, ICLASS_CJ" 1 110 vv0 --010 PP 1 --011 100 -----") +DEF_ENC(V6_vwhist128q, ICLASS_CJ" 1 110 vv0 --010 PP 1 --10- 100 -----") +DEF_ENC(V6_vwhist128qm, ICLASS_CJ" 1 110 vv0 --010 PP 1 --11i 100 -----") DEF_ENC(V6_vandvqv, ICLASS_CJ" 1 110 vv0 ---11 PP 1 uuuuu 000 ddddd") From e1245d0ea4552895429a10e6eb51f148cea4d4c0 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:52 -0700 Subject: [PATCH 190/627] target/hexagon/cpu: add HVX IEEE FP extension This flag will be used to control the HVX IEEE float instructions, which are only available at some Hexagon cores. When unavailable, the instruction effectively only set the destination registers to 0. Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/10fb5b86db60a465e51db2cf73185307a1ec0895.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/attribs_def.h.inc | 3 +++ target/hexagon/cpu.c | 1 + target/hexagon/cpu.h | 1 + target/hexagon/gen_tcg_funcs.py | 12 ++++++++++++ target/hexagon/hex_common.py | 25 +++++++++++++++++++++++++ target/hexagon/translate.c | 1 + target/hexagon/translate.h | 1 + 7 files changed, 44 insertions(+) diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index 6c55063a30..b1c155ea6d 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -196,5 +196,8 @@ DEF_ATTRIB(NOTE_SHIFT_RESOURCE, "Uses the HVX shift resource.", "", "") DEF_ATTRIB(RESTRICT_NOSLOT1_STORE, "Packet must not have slot 1 store", "", "") DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") +/* HVX IEEE FP extension attributes */ +DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "") + /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 75cae45029..f25878cd67 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -75,6 +75,7 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, qdev_prop_uint32, target_ulong), DEFINE_PROP_BOOL("short-circuit", HexagonCPU, short_circuit, true), + DEFINE_PROP_BOOL("ieee-fp", HexagonCPU, ieee_fp_extension, true), }; const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index f6c3c63932..502f27983b 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -194,6 +194,7 @@ struct ArchCPU { bool lldb_compat; target_ulong lldb_stack_adjust; bool short_circuit; + bool ieee_fp_extension; #ifndef CONFIG_USER_ONLY HexagonTLBState *tlb; uint32_t boot_addr; diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index 43e6807749..2592acf21e 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -23,6 +23,15 @@ import string import hex_common from textwrap import dedent +def gen_disabled_ieee_insn(f, tag, regs): + f.write(" if (!ctx->ieee_fp_extension) {\n") + for regtype, regid in regs: + reg = hex_common.get_register(tag, regtype, regid) + if reg.is_hvx_reg() and reg.is_written(): + reg.gen_zero(f) + f.write(" return;\n") + f.write(" }\n") + ## ## Generate the TCG code to call the helper ## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} @@ -74,6 +83,9 @@ def gen_tcg_func(f, tag, regs, imms): i = 1 if immlett.isupper() else 0 f.write(f" int {hex_common.imm_name(immlett)} = insn->immed[{i}];\n") + if "A_HVX_IEEE_FP" in hex_common.attribdict[tag]: + gen_disabled_ieee_insn(f, tag, regs) + if hex_common.is_idef_parser_enabled(tag): gpr_operands = [ hex_common.get_register(tag, regtype, regid) diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 09a025ba13..ce5e38bea4 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -784,6 +784,11 @@ class VRegDest(Register, Hvx, Dest): TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()}); """)) + def gen_zero(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, + sizeof(MMVector), sizeof(MMVector), 0); + """)) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -850,6 +855,11 @@ class VRegReadWrite(Register, Hvx, ReadWrite): TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()}); """)) + def gen_zero(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, + sizeof(MMVector), sizeof(MMVector), 0); + """)) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -882,6 +892,11 @@ class VRegTmp(Register, Hvx, ReadWrite): vreg_src_off(ctx, {self.reg_num}), sizeof(MMVector), sizeof(MMVector)); """)) + def gen_zero(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, + sizeof(MMVector), sizeof(MMVector), 0); + """)) def gen_write(self, f, tag): f.write(code_fmt(f"""\ gen_vreg_write(ctx, {self.hvx_off()}, {self.reg_num}, @@ -915,6 +930,11 @@ class VRegPairDest(Register, Hvx, Dest): TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()}); """)) + def gen_zero(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, + sizeof(MMVectorPair), sizeof(MMVectorPair), 0); + """)) def gen_write(self, f, tag): pass def helper_hvx_desc(self, f): @@ -974,6 +994,11 @@ class VRegPairReadWrite(Register, Hvx, ReadWrite): TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr(); tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()}); """)) + def gen_zero(self, f): + f.write(code_fmt(f"""\ + tcg_gen_gvec_dup_imm(MO_64, {self.hvx_off()}, + sizeof(MMVectorPair), sizeof(MMVectorPair), 0); + """)) def gen_write(self, f, tag): f.write(code_fmt(f"""\ gen_vreg_write_pair(ctx, {self.hvx_off()}, {self.reg_num}, diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 199b4f8c2e..58c84df66e 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -1211,6 +1211,7 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP); ctx->short_circuit = hex_cpu->short_circuit; ctx->hex_def = HEXAGON_CPU_GET_CLASS(hex_cpu)->hex_def; + ctx->ieee_fp_extension = hex_cpu->ieee_fp_extension; #ifndef CONFIG_USER_ONLY ctx->num_cycles = 0; ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED); diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 2fca157553..3c5773e2c7 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -81,6 +81,7 @@ typedef struct DisasContext { target_ulong branch_dest; bool is_tight_loop; bool short_circuit; + bool ieee_fp_extension; bool read_after_write; bool has_hvx_overlap; TCGv new_value[TOTAL_PER_THREAD_REGS]; From 5995de98c4699b3246f1dffa86b90f677b6e7684 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:53 -0700 Subject: [PATCH 191/627] hexagon: group cpu configurations in their own struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be used in a follow up commit. Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/8f9a2e2ccfd2eeda73a63d1a6abbfd6e5458b44c.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/cpu.c | 14 +++++++------- target/hexagon/cpu.h | 10 +++------- target/hexagon/cpu_bits.h | 7 +++++++ target/hexagon/translate.c | 6 +++--- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index f25878cd67..3bc2a2efa9 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -71,11 +71,11 @@ static const Property hexagon_cpu_properties[] = { TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *), DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0), #endif - DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), - DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, - qdev_prop_uint32, target_ulong), - DEFINE_PROP_BOOL("short-circuit", HexagonCPU, short_circuit, true), - DEFINE_PROP_BOOL("ieee-fp", HexagonCPU, ieee_fp_extension, true), + DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, cfg.lldb_compat, false), + DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, cfg.lldb_stack_adjust, + 0, qdev_prop_uint32, target_ulong), + DEFINE_PROP_BOOL("short-circuit", HexagonCPU, cfg.short_circuit, true), + DEFINE_PROP_BOOL("ieee-fp", HexagonCPU, cfg.ieee_fp_extension, true), }; const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { @@ -127,7 +127,7 @@ const char * const hexagon_gregnames[] = { static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr) { HexagonCPU *cpu = env_archcpu(env); - target_ulong stack_adjust = cpu->lldb_stack_adjust; + target_ulong stack_adjust = cpu->cfg.lldb_stack_adjust; target_ulong stack_start = env->stack_start; target_ulong stack_size = 0x10000; @@ -239,7 +239,7 @@ static void hexagon_dump(CPUHexagonState *env, FILE *f, int flags) { HexagonCPU *cpu = env_archcpu(env); - if (cpu->lldb_compat) { + if (cpu->cfg.lldb_compat) { /* * When comparing with LLDB, it doesn't step through single-cycle * hardware loops the same way. So, we just skip them here diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 502f27983b..b0d726bf02 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -186,15 +186,13 @@ typedef struct HexagonCPUClass { const HexagonCPUDef *hex_def; } HexagonCPUClass; +#include "cpu_bits.h" + struct ArchCPU { CPUState parent_obj; CPUHexagonState env; - - bool lldb_compat; - target_ulong lldb_stack_adjust; - bool short_circuit; - bool ieee_fp_extension; + HexagonCPUConfig cfg; #ifndef CONFIG_USER_ONLY HexagonTLBState *tlb; uint32_t boot_addr; @@ -204,8 +202,6 @@ struct ArchCPU { #endif }; -#include "cpu_bits.h" - FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) FIELD(TB_FLAGS, MMU_INDEX, 1, 3) FIELD(TB_FLAGS, PCYCLE_ENABLED, 4, 1) diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 164e74c782..797ecabca9 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -21,6 +21,13 @@ #include "qemu/bitops.h" #include "cpu-qom.h" +typedef struct HexagonCPUConfig { + bool lldb_compat; + uint32_t lldb_stack_adjust; + bool short_circuit; + bool ieee_fp_extension; +} HexagonCPUConfig; + #define PCALIGN 4 #define PCALIGN_MASK (PCALIGN - 1) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 58c84df66e..06a8159d28 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -1209,9 +1209,9 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, ctx->num_hvx_insns = 0; ctx->branch_cond = TCG_COND_NEVER; ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP); - ctx->short_circuit = hex_cpu->short_circuit; + ctx->short_circuit = hex_cpu->cfg.short_circuit; ctx->hex_def = HEXAGON_CPU_GET_CLASS(hex_cpu)->hex_def; - ctx->ieee_fp_extension = hex_cpu->ieee_fp_extension; + ctx->ieee_fp_extension = hex_cpu->cfg.ieee_fp_extension; #ifndef CONFIG_USER_ONLY ctx->num_cycles = 0; ctx->pcycle_enabled = FIELD_EX32(hex_flags, TB_FLAGS, PCYCLE_ENABLED); @@ -1268,7 +1268,7 @@ static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu) * so end the TLB after every packet. */ HexagonCPU *hex_cpu = env_archcpu(env); - if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) { + if (hex_cpu->cfg.lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) { ctx->base.is_jmp = DISAS_TOO_MANY; } } From 97a75a12d6875b0b86211ea5699d1f7a4825e131 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:54 -0700 Subject: [PATCH 192/627] hexagon: print info on "-d in_asm" for disabled IEEE FP instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When cpu->cfg.ieee_fp_extension is off, IEEE FP instructions don't get executed. Let's print that info on the "-d in_asm" output to help users. This will generate an output like the following: 0x00020e30: 0x1f82e1c0 { V0.sf = vadd(V1.sf,V2.sf) (disabled: no ieee_fp) } Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/1bdc772e4a795ecd9f5bf2b7e7143cc4b297318c.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- disas/hexagon.c | 4 ++-- target/hexagon/cpu.c | 5 ++++- target/hexagon/cpu_bits.h | 5 +++-- target/hexagon/decode.c | 4 ++-- target/hexagon/printinsn.c | 9 +++++++-- target/hexagon/printinsn.h | 2 +- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/disas/hexagon.c b/disas/hexagon.c index 36b8321c26..e2d3804606 100644 --- a/disas/hexagon.c +++ b/disas/hexagon.c @@ -31,7 +31,6 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info) { - const HexagonCPUDef *hex_def = (const HexagonCPUDef *)info->target_info; uint32_t words[PACKET_WORDS_MAX]; bool found_end = false; GString *buf; @@ -58,8 +57,9 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info) return PACKET_WORDS_MAX * sizeof(uint32_t); } + const HexagonCPUConfig *cfg = info->target_info; buf = g_string_sized_new(PACKET_BUFFER_LEN); - len = disassemble_hexagon(words, i, memaddr, buf, hex_def); + len = disassemble_hexagon(words, i, memaddr, buf, cfg); (*info->fprintf_func)(info->stream, "%s", buf->str); g_string_free(buf, true); diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 3bc2a2efa9..666b0cad53 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -444,12 +444,13 @@ static void hexagon_cpu_disas_set_info(const CPUState *cs, const HexagonCPU *cpu = HEXAGON_CPU(cs); info->print_insn = print_insn_hexagon; info->endian = BFD_ENDIAN_LITTLE; - info->target_info = HEXAGON_CPU_GET_CLASS(cpu)->hex_def; + info->target_info = &cpu->cfg; } static void hexagon_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + HexagonCPU *cpu = HEXAGON_CPU(dev); HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(dev); Error *local_err = NULL; @@ -459,6 +460,8 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) return; } + cpu->cfg.hex_def = mcc->hex_def; + gdb_register_coprocessor(cs, hexagon_hvx_gdb_read_register, hexagon_hvx_gdb_write_register, gdb_find_static_feature("hexagon-hvx.xml")); diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 797ecabca9..a8fba4aa18 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -26,6 +26,7 @@ typedef struct HexagonCPUConfig { uint32_t lldb_stack_adjust; bool short_circuit; bool ieee_fp_extension; + const HexagonCPUDef *hex_def; } HexagonCPUConfig; #define PCALIGN 4 @@ -130,7 +131,7 @@ static inline bool is_packet_end(uint32_t endocing) return ((bits == 0x3) || (bits == 0x0)); } -int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc, GString *buf, - const HexagonCPUDef *hex_def); +int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc, + GString *buf, const HexagonCPUConfig *cfg); #endif diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index e6bb7733be..b12e91fe6a 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -856,7 +856,7 @@ int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words, /* Used for "-d in_asm" logging */ int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc, - GString *buf, const HexagonCPUDef *hex_def) + GString *buf, const HexagonCPUConfig *cfg) { HexagonCPUDef any_def = { .hex_version = HEX_VER_ANY, /* Allow decode to accept anything */ @@ -867,7 +867,7 @@ int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc, ctx.hex_def = &any_def; if (decode_packet(&ctx, nwords, words, &ctx.pkt, true) > 0) { - snprint_a_pkt_disas(buf, &ctx.pkt, words, pc, hex_def); + snprint_a_pkt_disas(buf, &ctx.pkt, words, pc, cfg); return ctx.pkt.encod_pkt_size_in_bytes; } else { for (int i = 0; i < nwords; i++) { diff --git a/target/hexagon/printinsn.c b/target/hexagon/printinsn.c index 1673e95421..023ea12dba 100644 --- a/target/hexagon/printinsn.c +++ b/target/hexagon/printinsn.c @@ -139,7 +139,7 @@ static void snprintinsn(GString *buf, Insn *insn) } void snprint_a_pkt_disas(GString *buf, Packet *pkt, uint32_t *words, - target_ulong pc, const HexagonCPUDef *hex_def) + target_ulong pc, const HexagonCPUConfig *cfg) { bool has_endloop0 = false; bool has_endloop1 = false; @@ -171,12 +171,17 @@ void snprint_a_pkt_disas(GString *buf, Packet *pkt, uint32_t *words, } g_string_append(buf, "\t"); - if (opcode_supported(pkt->insn[i].opcode, hex_def)) { + if (opcode_supported(pkt->insn[i].opcode, cfg->hex_def)) { snprintinsn(buf, &(pkt->insn[i])); } else { g_string_append(buf, ""); } + if (!cfg->ieee_fp_extension && + GET_ATTRIB(pkt->insn[i].opcode, A_HVX_IEEE_FP)) { + g_string_append(buf, " (disabled: no ieee_fp)"); + } + if (i < pkt->num_insns - 1) { /* * Subinstructions are two instructions encoded diff --git a/target/hexagon/printinsn.h b/target/hexagon/printinsn.h index de962b5f2e..c8389408d3 100644 --- a/target/hexagon/printinsn.h +++ b/target/hexagon/printinsn.h @@ -22,6 +22,6 @@ #include "insn.h" void snprint_a_pkt_disas(GString *buf, Packet *pkt, uint32_t *words, - target_ulong pc, const HexagonCPUDef *hex_def); + target_ulong pc, const HexagonCPUConfig *cfg); #endif From 69e46b28228441c5d064fb3b84691cbb23e71296 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:55 -0700 Subject: [PATCH 193/627] target/hexagon: add v68 HVX IEEE float arithmetic insns Add HVX IEEE floating-point arithmetic instructions: - vmpy_sf_sf, vmpy_sf_hf, vmpy_hf_hf: multiply operations - vdmpy_sf_hf: dot-product multiply - vmpy_sf_hf_acc, vmpy_hf_hf_acc, vdmpy_sf_hf_acc: multiply-accumulate - vadd_sf_sf, vsub_sf_sf, vadd_sf_hf, vsub_sf_hf: add/sub with sf output - vadd_hf_hf, vsub_hf_hf: add/sub with hf output Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/8923b6c6bc4fe750c07a07bcd490761f8bab52fe.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/arch.c | 8 ++ target/hexagon/attribs_def.h.inc | 4 + target/hexagon/cpu.c | 3 + target/hexagon/cpu.h | 1 + target/hexagon/hex_common.py | 1 + target/hexagon/imported/mmvec/encode_ext.def | 18 ++++ target/hexagon/imported/mmvec/ext.idef | 101 +++++++++++++++++++ target/hexagon/meson.build | 1 + target/hexagon/mmvec/hvx_ieee_fp.c | 21 ++++ target/hexagon/mmvec/hvx_ieee_fp.h | 18 ++++ target/hexagon/mmvec/macros.h | 1 + target/hexagon/mmvec/mmvec.h | 2 + 12 files changed, 179 insertions(+) create mode 100644 target/hexagon/mmvec/hvx_ieee_fp.c create mode 100644 target/hexagon/mmvec/hvx_ieee_fp.h diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 0a400bf7a7..3c417358e0 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -199,6 +199,10 @@ void arch_fpop_start(CPUHexagonState *env) set_float_rounding_mode( softfloat_roundingmodes[fREAD_REG_FIELD(USR, USR_FPRND)], &env->fp_status); + /* + * No need to check env->hvx_fp_status, these instructions don't + * raise exceptions nor interact with usr fields. + */ } #ifdef CONFIG_USER_ONLY @@ -237,6 +241,10 @@ void arch_fpop_end(CPUHexagonState *env, bool pkt_need_commit) SOFTFLOAT_TEST_FLAG(float_flag_overflow, FPOVFF, FPOVFE); SOFTFLOAT_TEST_FLAG(float_flag_underflow, FPUNFF, FPUNFE); } + /* + * No need to check env->hvx_fp_status, these instructions don't + * raise exceptions nor interact with usr fields. + */ } int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust, diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index b1c155ea6d..ecd08d02df 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -198,6 +198,10 @@ DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") /* HVX IEEE FP extension attributes */ DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "") +DEF_ATTRIB(HVX_IEEE_FP_ACC, "HVX IEEE FP accumulate instruction", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_16, "HVX IEEE FP 16-bit output", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_32, "HVX IEEE FP 32-bit output", "", "") +DEF_ATTRIB(CVI_VX_NO_TMP_LD, "HVX multiply without tmp load", "", "") /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 666b0cad53..0ddd898e6e 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -420,6 +420,9 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); /* Default NaN value: sign bit set, all frac bits set */ set_float_default_nan_pattern(0b11111111, &env->fp_status); + + set_default_nan_mode(1, &env->hvx_fp_status); + set_float_default_nan_pattern(0b01111111, &env->hvx_fp_status); #ifndef CONFIG_USER_ONLY memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS); memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS); diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index b0d726bf02..c50fbb3f72 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -152,6 +152,7 @@ typedef struct CPUArchState { MemLog mem_log_stores[STORES_MAX]; float_status fp_status; + float_status hvx_fp_status; target_ulong llsc_addr; target_ulong llsc_val; diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index ce5e38bea4..602f49e1f5 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -253,6 +253,7 @@ def need_env(tag): "A_LOAD" in attribdict[tag] or "A_CVI_GATHER" in attribdict[tag] or "A_CVI_SCATTER" in attribdict[tag] or + "A_HVX_IEEE_FP" in attribdict[tag] or "A_IMPLICIT_WRITES_USR" in attribdict[tag] or "A_PRIV" in attribdict[tag] or "J2_trap" in tag) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 6d70086b5f..4ce87d09fd 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -804,5 +804,23 @@ DEF_ENC(V6_vmpyewuh, ICLASS_CJ" 1 111 111 vvvvv PP 0 uuuuu 101 ddddd") DEF_ENC(V6_vmpyowh, ICLASS_CJ" 1 111 111 vvvvv PP 0 uuuuu 111 ddddd") DEF_ENC(V6_vmpyuhvs,"00011111110vvvvvPP1uuuuu111ddddd") +/* IEEE FP multiply instructions */ +DEF_ENC(V6_vmpy_sf_sf,"00011111100vvvvvPP1uuuuu001ddddd") +DEF_ENC(V6_vmpy_sf_hf,"00011111100vvvvvPP1uuuuu010ddddd") +DEF_ENC(V6_vmpy_hf_hf,"00011111100vvvvvPP1uuuuu011ddddd") +DEF_ENC(V6_vdmpy_sf_hf,"00011111101vvvvvPP1uuuuu110ddddd") + +/* IEEE FP multiply-accumulate instructions */ +DEF_ENC(V6_vmpy_sf_hf_acc,"00011100010vvvvvPP1uuuuu001xxxxx") +DEF_ENC(V6_vmpy_hf_hf_acc,"00011100010vvvvvPP1uuuuu010xxxxx") +DEF_ENC(V6_vdmpy_sf_hf_acc,"00011100010vvvvvPP1uuuuu011xxxxx") + +/* IEEE FP add/sub instructions */ +DEF_ENC(V6_vadd_sf_sf,"00011111100vvvvvPP1uuuuu110ddddd") +DEF_ENC(V6_vsub_sf_sf,"00011111100vvvvvPP1uuuuu111ddddd") +DEF_ENC(V6_vadd_sf_hf,"00011111100vvvvvPP1uuuuu100ddddd") +DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd") +DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd") +DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd") #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 03d31f6181..14df8e4790 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -2895,9 +2895,110 @@ EXTINSN(V6_vprefixqw,"Vd32.w=prefixsum(Qv4)", ATTRIBS(A_EXTENSION,A_CVI,A_CVI_ } } ) +/* KVX - IEEE FP Instructions */ +/* Single pipe, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) +/* Single pipe, 16-bit output */ +#define ITERATOR_INSN_IEEE_FP_16(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) +/* Two pipes: P2 & P3, single output: P2, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_SINGLE_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* Two pipes: P2 & P3, two outputs, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* + * single pipe, accumulate instruction, produces 16-bit output, requires 16-bit + * accumulate input + */ +#define ITERATOR_INSN_IEEE_FP_ACC_16(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_ACC,A_HVX_IEEE_FP_OUT_16,A_CVI_VX_NO_TMP_LD), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* + * single pipe, accumulate instruction, produces 32-bit output, requires 32-bit + * accumulate input + */ +#define ITERATOR_INSN_IEEE_FP_ACC_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_ACC,A_HVX_IEEE_FP_OUT_32,A_CVI_VX_NO_TMP_LD), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* IEEE FP multiply instructions */ +ITERATOR_INSN_IEEE_FP_DOUBLE_SINGLE_32(32, vmpy_sf_sf, + "Vd32.sf=vmpy(Vu32.sf,Vv32.sf)", "Vector IEEE mul: sf", + VdV.sf[i] = float32_mul(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_hf, + "Vdd32.sf=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE mul: hf widen to sf", + VddV.v[0].sf[i] = fp_mult_sf_hf(VuV.hf[2*i], VvV.hf[2*i], &env->hvx_fp_status); + VddV.v[1].sf[i] = fp_mult_sf_hf(VuV.hf[2*i+1], VvV.hf[2*i+1], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vmpy_hf_hf, "Vd32.hf=vmpy(Vu32.hf,Vv32.hf)", + "Vector IEEE mul: hf", + VdV.hf[i] = float16_mul(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_32(32, vdmpy_sf_hf, "Vd32.sf=vdmpy(Vu32.hf,Vv32.hf)", + "Vector IEEE mul reduction: hf widen to sf", + VdV.sf[i] = fp_vdmpy(VuV.hf[2*i+1], VuV.hf[2*i], VvV.hf[2*i+1], + VvV.hf[2*i], &env->hvx_fp_status)) + +/* IEEE FP multiply-accumulate instructions */ +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_hf_acc, + "Vxx32.sf+=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma: hf widen to sf", + VxxV.v[0].sf[i] = float32_muladd(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), + VxxV.v[0].sf[i], 0, &env->hvx_fp_status); + VxxV.v[1].sf[i] = float32_muladd(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), + VxxV.v[1].sf[i], 0, &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_ACC_16(16, vmpy_hf_hf_acc, + "Vx32.hf+=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma: hf", + VxV.hf[i] = float16_muladd(VuV.hf[i], VvV.hf[i], VxV.hf[i], 0, &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_ACC_32(32, vdmpy_sf_hf_acc, + "Vx32.sf+=vdmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma reduce: hf widen to sf", + VxV.sf[i] = float32_add(fp_vdmpy(VuV.hf[2*i+1], VuV.hf[2*i], + VvV.hf[2*i+1], VvV.hf[2*i], + &env->hvx_fp_status), + VxV.sf[i], &env->hvx_fp_status)) + +/* IEEE FP add/sub instructions */ +ITERATOR_INSN_IEEE_FP_32(32, vadd_sf_sf, "Vd32.sf=vadd(Vu32.sf,Vv32.sf)", + "Vector IEEE add: sf", + VdV.sf[i] = float32_add(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_32(32, vsub_sf_sf, "Vd32.sf=vsub(Vu32.sf,Vv32.sf)", + "Vector IEEE sub: sf", + VdV.sf[i] = float32_sub(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vadd_hf_hf, "Vd32.hf=vadd(Vu32.hf,Vv32.hf)", + "Vector IEEE add: hf", + VdV.hf[i] = float16_add(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vsub_hf_hf, "Vd32.hf=vsub(Vu32.hf,Vv32.hf)", + "Vector IEEE sub: hf", + VdV.hf[i] = float16_sub(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vadd_sf_hf, + "Vdd32.sf=vadd(Vu32.hf,Vv32.hf)", "Vector IEEE add: hf widen to sf", + VddV.v[0].sf[i] = float32_add(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), &env->hvx_fp_status); + VddV.v[1].sf[i] = float32_add(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_hf, + "Vdd32.sf=vsub(Vu32.hf,Vv32.hf)", "Vector IEEE sub: hf widen to sf", + VddV.v[0].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), &env->hvx_fp_status); + VddV.v[1].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status)) /****************************************************************************** DEBUG Vector/Register Printing diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 59cb09c107..4c921eee73 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -252,6 +252,7 @@ hexagon_ss.add(files( 'fma_emu.c', 'mmvec/decode_ext_mmvec.c', 'mmvec/system_ext_mmvec.c', + 'mmvec/hvx_ieee_fp.c', )) hexagon_softmmu_ss.add(files( diff --git a/target/hexagon/mmvec/hvx_ieee_fp.c b/target/hexagon/mmvec/hvx_ieee_fp.c new file mode 100644 index 0000000000..3367226998 --- /dev/null +++ b/target/hexagon/mmvec/hvx_ieee_fp.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hvx_ieee_fp.h" + +float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status) +{ + return float32_mul(float16_to_float32(a1, true, fp_status), + float16_to_float32(a2, true, fp_status), fp_status); +} + +float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, + float_status *fp_status) +{ + return float32_add(fp_mult_sf_hf(a1, a3, fp_status), + fp_mult_sf_hf(a2, a4, fp_status), fp_status); +} diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h new file mode 100644 index 0000000000..75008deb3b --- /dev/null +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HEXAGON_HVX_IEEE_H +#define HEXAGON_HVX_IEEE_H + +#include "fpu/softfloat.h" + +#define f16_to_f32(A) float16_to_float32((A), true, &env->hvx_fp_status) + +float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status); +float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, + float_status *fp_status); + +#endif diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index c7840fbf2e..ac709d8993 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -23,6 +23,7 @@ #include "mmvec/system_ext_mmvec.h" #include "accel/tcg/getpc.h" #include "accel/tcg/probe.h" +#include "mmvec/hvx_ieee_fp.h" #ifndef QEMU_GENERATE #define VdV (*(MMVector *restrict)(VdV_void)) diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h index 4a4f6cc980..9841687f83 100644 --- a/target/hexagon/mmvec/mmvec.h +++ b/target/hexagon/mmvec/mmvec.h @@ -41,6 +41,8 @@ typedef union { int16_t h[MAX_VEC_SIZE_BYTES / 2]; uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; int8_t b[MAX_VEC_SIZE_BYTES / 1]; + float32 sf[MAX_VEC_SIZE_BYTES / 4]; + float16 hf[MAX_VEC_SIZE_BYTES / 2]; } MMVector; typedef union { From 2843fc5feb5336a313b906d898037ef6dab94578 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:56 -0700 Subject: [PATCH 194/627] target/hexagon: add v68 HVX IEEE float min/max insns Add HVX IEEE floating-point min/max instructions: - vfmin_hf, vfmin_sf: IEEE floating-point minimum - vfmax_hf, vfmax_sf: IEEE floating-point maximum - vmax_hf, vmax_sf: qfloat IEEE maximum - vmin_hf, vmin_sf: qfloat IEEE minimum The Hexagon qfloat variants are similar to the IEEE-754 ones, but they handle NaN slightly differently. See comment on hvx_ieee_fp.h Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/8e274a7a10a5aae23eb1250db0b4f4250c81f3ef.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/attribs_def.h.inc | 2 + target/hexagon/hex_common.py | 1 + target/hexagon/imported/mmvec/encode_ext.def | 10 ++++ target/hexagon/imported/mmvec/ext.idef | 36 +++++++++++++- target/hexagon/mmvec/hvx_ieee_fp.c | 50 ++++++++++++++++++++ target/hexagon/mmvec/hvx_ieee_fp.h | 6 +++ 6 files changed, 104 insertions(+), 1 deletion(-) diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index ecd08d02df..d12f6ac4b1 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -84,6 +84,7 @@ DEF_ATTRIB(CVI_SCATTER, "CVI Scatter operation", "", "") DEF_ATTRIB(CVI_SCATTER_RELEASE, "CVI Store Release for scatter", "", "") DEF_ATTRIB(CVI_TMP_DST, "CVI instruction that doesn't write a register", "", "") DEF_ATTRIB(CVI_SLOT23, "Can execute in slot 2 or slot 3 (HVX)", "", "") +DEF_ATTRIB(CVI_VA_2SRC, "Execs on multimedia vector engine; requires two srcs", "", "") DEF_ATTRIB(VTCM_ALLBANK_ACCESS, "Allocates in all VTCM schedulers.", "", "") @@ -202,6 +203,7 @@ DEF_ATTRIB(HVX_IEEE_FP_ACC, "HVX IEEE FP accumulate instruction", "", "") DEF_ATTRIB(HVX_IEEE_FP_OUT_16, "HVX IEEE FP 16-bit output", "", "") DEF_ATTRIB(HVX_IEEE_FP_OUT_32, "HVX IEEE FP 32-bit output", "", "") DEF_ATTRIB(CVI_VX_NO_TMP_LD, "HVX multiply without tmp load", "", "") +DEF_ATTRIB(HVX_FLT, "This a floating point HVX instruction.", "", "") /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index 602f49e1f5..e33d43e3ce 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -254,6 +254,7 @@ def need_env(tag): "A_CVI_GATHER" in attribdict[tag] or "A_CVI_SCATTER" in attribdict[tag] or "A_HVX_IEEE_FP" in attribdict[tag] or + "A_HVX_FLT" in attribdict[tag] or "A_IMPLICIT_WRITES_USR" in attribdict[tag] or "A_PRIV" in attribdict[tag] or "J2_trap" in tag) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 4ce87d09fd..d7f50db778 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -823,4 +823,14 @@ DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd") DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd") DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd") +/* IEEE FP min/max instructions */ +DEF_ENC(V6_vfmin_hf,"00011100011vvvvvPP1uuuuu000ddddd") +DEF_ENC(V6_vfmin_sf,"00011100011vvvvvPP1uuuuu001ddddd") +DEF_ENC(V6_vfmax_hf,"00011100011vvvvvPP1uuuuu010ddddd") +DEF_ENC(V6_vfmax_sf,"00011100011vvvvvPP1uuuuu011ddddd") +DEF_ENC(V6_vmax_sf,"00011111110vvvvvPP1uuuuu001ddddd") +DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd") +DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd") +DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd") + #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 14df8e4790..0e9cace203 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -43,7 +43,9 @@ EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA), \ DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) - +#define ITERATOR_INSN_ANY_SLOT_2SRC(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) #define ITERATOR_INSN2_ANY_SLOT(WIDTH,TAG,SYNTAX,SYNTAX2,DESCR,CODE) \ ITERATOR_INSN_ANY_SLOT(WIDTH,TAG,SYNTAX2,DESCR,CODE) @@ -3000,6 +3002,38 @@ ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_hf, VddV.v[1].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i+1]), f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status)) +#define ITERATOR_INSN_IEEE_FP_16_32_LATE(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ + ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16,A_HVX_IEEE_FP_OUT_32), \ + DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* IEEE FP min/max instructions */ +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmin_hf, "Vd32.hf=vfmin(Vu32.hf,Vv32.hf)", \ + "Vector IEEE min: hf", VdV.hf[i] = float16_min(VuV.hf[i], VvV.hf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmin_sf, "Vd32.sf=vfmin(Vu32.sf,Vv32.sf)", \ + "Vector IEEE min: sf", VdV.sf[i] = float32_min(VuV.sf[i], VvV.sf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmax_hf, "Vd32.hf=vfmax(Vu32.hf,Vv32.hf)", \ + "Vector IEEE max: hf", VdV.hf[i] = float16_max(VuV.hf[i], VvV.hf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmax_sf, "Vd32.sf=vfmax(Vu32.sf,Vv32.sf)", \ + "Vector IEEE max: sf", VdV.sf[i] = float32_max(VuV.sf[i], VvV.sf[i], \ + &env->hvx_fp_status)) + +ITERATOR_INSN_ANY_SLOT_2SRC(32,vmax_sf,"Vd32.sf=vmax(Vu32.sf,Vv32.sf)", \ + "Vector max of sf input", VdV.sf[i] = qf_max_sf(VuV.sf[i], VvV.sf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_ANY_SLOT_2SRC(32,vmin_sf,"Vd32.sf=vmin(Vu32.sf,Vv32.sf)", \ + "Vector min of sf input", VdV.sf[i] = qf_min_sf(VuV.sf[i], VvV.sf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_ANY_SLOT_2SRC(16,vmax_hf,"Vd32.hf=vmax(Vu32.hf,Vv32.hf)", \ + "Vector max of hf input", VdV.hf[i] = qf_max_hf(VuV.hf[i], VvV.hf[i], \ + &env->hvx_fp_status)) +ITERATOR_INSN_ANY_SLOT_2SRC(16,vmin_hf,"Vd32.hf=vmin(Vu32.hf,Vv32.hf)", \ + "Vector min of hf input", VdV.hf[i] = qf_min_hf(VuV.hf[i], VvV.hf[i], \ + &env->hvx_fp_status)) + /****************************************************************************** DEBUG Vector/Register Printing ******************************************************************************/ diff --git a/target/hexagon/mmvec/hvx_ieee_fp.c b/target/hexagon/mmvec/hvx_ieee_fp.c index 3367226998..2ae79a485a 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.c +++ b/target/hexagon/mmvec/hvx_ieee_fp.c @@ -19,3 +19,53 @@ float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, return float32_add(fp_mult_sf_hf(a1, a3, fp_status), fp_mult_sf_hf(a2, a4, fp_status), fp_status); } + +#define float32_is_pos_nan(X) (float32_is_any_nan(X) && !float32_is_neg(X)) +#define float32_is_neg_nan(X) (float32_is_any_nan(X) && float32_is_neg(X)) +#define float16_is_pos_nan(X) (float16_is_any_nan(X) && !float16_is_neg(X)) +#define float16_is_neg_nan(X) (float16_is_any_nan(X) && float16_is_neg(X)) + +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */ +float32 qf_max_sf(float32 a1, float32 a2, float_status *fp_status) +{ + if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) { + return a1; + } + if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) { + return a2; + } + return float32_max(a1, a2, fp_status); +} + +float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status) +{ + if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) { + return a2; + } + if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) { + return a1; + } + return float32_min(a1, a2, fp_status); +} + +float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status) +{ + if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) { + return a1; + } + if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) { + return a2; + } + return float16_max(a1, a2, fp_status); +} + +float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status) +{ + if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) { + return a2; + } + if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) { + return a1; + } + return float16_min(a1, a2, fp_status); +} diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h index 75008deb3b..dff2fab14c 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.h +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -15,4 +15,10 @@ float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status); float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, float_status *fp_status); +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */ +float32 qf_max_sf(float32 a1, float32 a2, float_status *fp_status); +float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status); +float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status); +float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status); + #endif From 60f11988ebd6a2a44fff8230aa41ad384aac1f97 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:57 -0700 Subject: [PATCH 195/627] target/hexagon: add v68 HVX IEEE float misc insns Add HVX IEEE floating-point miscellaneous instructions: - vassign_fp (vfmv): vector move - vfneg_hf, vfneg_sf: vector floating-point negate - vabs_hf, vabs_sf: vector absolute value Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/0bd3279ca0bbf7c01548e3b4e7a9c8fdbdbe4ee1.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/imported/mmvec/encode_ext.def | 7 +++++++ target/hexagon/imported/mmvec/ext.idef | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index d7f50db778..72daf8724c 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -833,4 +833,11 @@ DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd") DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd") DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd") +/* IEEE FP move, negate, abs instructions */ +DEF_ENC(V6_vassign_fp,"00011110--0-0110PP1uuuuu001ddddd") +DEF_ENC(V6_vfneg_hf,"00011110--0-0110PP1uuuuu010ddddd") +DEF_ENC(V6_vfneg_sf,"00011110--0-0110PP1uuuuu011ddddd") +DEF_ENC(V6_vabs_hf,"00011110--0-0110PP1uuuuu100ddddd") +DEF_ENC(V6_vabs_sf,"00011110--0-0110PP1uuuuu101ddddd") + #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 0e9cace203..1b16ed0628 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -3034,6 +3034,18 @@ ITERATOR_INSN_ANY_SLOT_2SRC(16,vmin_hf,"Vd32.hf=vmin(Vu32.hf,Vv32.hf)", \ "Vector min of hf input", VdV.hf[i] = qf_min_hf(VuV.hf[i], VvV.hf[i], \ &env->hvx_fp_status)) +/* IEEE FP move, negate, abs instructions */ +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vassign_fp, "Vd32.w=vfmv(Vu32.w)", \ + "Vector IEEE move", VdV.w[i] = VuV.w[i]) +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfneg_hf, "Vd32.hf=vfneg(Vu32.hf)", \ + "Vector IEEE neg: hf", VdV.hf[i] = float16_chs(VuV.hf[i])) +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfneg_sf, "Vd32.sf=vfneg(Vu32.sf)", \ + "Vector IEEE neg: sf", VdV.sf[i] = float32_chs(VuV.sf[i])) +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vabs_hf, "Vd32.hf=vabs(Vu32.hf)", \ + "Vector IEEE abs: hf", VdV.hf[i] = float16_abs(VuV.hf[i])) +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vabs_sf, "Vd32.sf=vabs(Vu32.sf)", \ + "Vector IEEE abs: sf", VdV.sf[i] = float32_abs(VuV.sf[i])) + /****************************************************************************** DEBUG Vector/Register Printing ******************************************************************************/ From 011b2512f9551b9c91d760fc38d65e5eb7bc2b3b Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:58 -0700 Subject: [PATCH 196/627] target/hexagon: add v68 HVX IEEE float conversion insns Add HVX IEEE floating-point conversion instructions: - vconv_hf_h, vconv_h_hf, vconv_sf_w, vconv_w_sf: vconv operations - vcvt_hf_sf, vcvt_sf_hf: float <-> half float conversions - vcvt_hf_b, vcvt_hf_h, vcvt_hf_ub, vcvt_hf_uh: int to half float - vcvt_b_hf, vcvt_h_hf, vcvt_ub_hf, vcvt_uh_hf: half float to int Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/beca620d2e5e0bc15886bf967ab3961a49eca5f7.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/imported/mmvec/encode_ext.def | 18 ++++ target/hexagon/imported/mmvec/ext.idef | 97 ++++++++++++++++++++ target/hexagon/mmvec/hvx_ieee_fp.c | 18 ++++ target/hexagon/mmvec/hvx_ieee_fp.h | 4 + 4 files changed, 137 insertions(+) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 72daf8724c..c1ed1b6c23 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -840,4 +840,22 @@ DEF_ENC(V6_vfneg_sf,"00011110--0-0110PP1uuuuu011ddddd") DEF_ENC(V6_vabs_hf,"00011110--0-0110PP1uuuuu100ddddd") DEF_ENC(V6_vabs_sf,"00011110--0-0110PP1uuuuu101ddddd") +/* IEEE FP vcvt instructions */ +DEF_ENC(V6_vcvt_sf_hf,"00011110--0-0100PP1uuuuu100ddddd") +DEF_ENC(V6_vcvt_hf_sf,"00011111011vvvvvPP1uuuuu001ddddd") +DEF_ENC(V6_vcvt_hf_ub,"00011110--0-0100PP1uuuuu001ddddd") +DEF_ENC(V6_vcvt_hf_b,"00011110--0-0100PP1uuuuu010ddddd") +DEF_ENC(V6_vcvt_hf_uh,"00011110--0-0100PP1uuuuu101ddddd") +DEF_ENC(V6_vcvt_hf_h,"00011110--0-0100PP1uuuuu111ddddd") +DEF_ENC(V6_vcvt_uh_hf,"00011110--0--101PP1uuuuu000ddddd") +DEF_ENC(V6_vcvt_h_hf,"00011110--0-0110PP1uuuuu000ddddd") +DEF_ENC(V6_vcvt_ub_hf,"00011111110vvvvvPP1uuuuu101ddddd") +DEF_ENC(V6_vcvt_b_hf,"00011111110vvvvvPP1uuuuu110ddddd") + +/* IEEE FP vconv instructions */ +DEF_ENC(V6_vconv_sf_w,"00011110--0--101PP1uuuuu011ddddd") +DEF_ENC(V6_vconv_w_sf,"00011110--0--101PP1uuuuu001ddddd") +DEF_ENC(V6_vconv_hf_h,"00011110--0--101PP1uuuuu100ddddd") +DEF_ENC(V6_vconv_h_hf,"00011110--0--101PP1uuuuu010ddddd") + #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 1b16ed0628..788ce1d2ae 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -63,6 +63,9 @@ ITERATOR_INSN_ANY_SLOT_DOUBLE_VEC(WIDTH,TAG,SYNTAX2,DESCR,CODE) EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VS), \ DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) +#define ITERATOR_INSN_SHIFT_SLOT_FLT(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VS,A_HVX_FLT), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) #define ITERATOR_INSN_SHIFT3_SLOT(WIDTH,TAG,SYNTAX,DESCR,CODE) \ EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VS,A_CVI_VS_3SRC,A_NOTE_SHIFT_RESOURCE,A_NOTE_NOVP,A_NOTE_VA_UNARY), \ @@ -3046,6 +3049,100 @@ ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vabs_hf, "Vd32.hf=vabs(Vu32.hf)", \ ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vabs_sf, "Vd32.sf=vabs(Vu32.sf)", \ "Vector IEEE abs: sf", VdV.sf[i] = float32_abs(VuV.sf[i])) +/* Two pipes: P2 & P3, two outputs, 16-bit */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_16(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_16), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* Two pipes: P2 & P3, two outputs, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ + ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_32), \ + DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* Single pipe, 16-bit output */ +#define ITERATOR_INSN_IEEE_FP_16(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ + ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16), \ + DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* single pipe, output can feed 16- or 32-bit accumulate */ +#define ITERATOR_INSN_IEEE_FP_16_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ + ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16,A_HVX_IEEE_FP_OUT_32), \ + DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/****************************************************************************** + * IEEE FP convert instructions + ******************************************************************************/ + +ITERATOR_INSN_IEEE_FP_DOUBLE_16(32, vcvt_hf_ub, "Vdd32.hf=vcvt(Vu32.ub)", + "Vector IEEE cvt from int: ub widen to hf", + VddV.v[0].hf[2*i] = uint64_to_float16_scalbn(VuV.ub[4*i], float_round_nearest_even, 0); + VddV.v[0].hf[2*i+1] = uint64_to_float16_scalbn(VuV.ub[4*i+1], float_round_nearest_even, 0); + VddV.v[1].hf[2*i] = uint64_to_float16_scalbn(VuV.ub[4*i+2], float_round_nearest_even, 0); + VddV.v[1].hf[2*i+1] = uint64_to_float16_scalbn(VuV.ub[4*i+3], float_round_nearest_even, 0)) + +ITERATOR_INSN_IEEE_FP_DOUBLE_16(32, vcvt_hf_b, "Vdd32.hf=vcvt(Vu32.b)", + "Vector IEEE cvt from int: b widen to hf", + VddV.v[0].hf[2*i] = int64_to_float16_scalbn(VuV.b[4*i], float_round_nearest_even, 0); + VddV.v[0].hf[2*i+1] = int64_to_float16_scalbn(VuV.b[4*i+1], float_round_nearest_even, 0); + VddV.v[1].hf[2*i] = int64_to_float16_scalbn(VuV.b[4*i+2], float_round_nearest_even, 0); + VddV.v[1].hf[2*i+1] = int64_to_float16_scalbn(VuV.b[4*i+3], float_round_nearest_even, 0)) + +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vcvt_sf_hf, "Vdd32.sf=vcvt(Vu32.hf)", + "Vector IEEE cvt: hf widen to sf", + VddV.v[0].sf[i] = f16_to_f32(VuV.hf[2*i]); + VddV.v[1].sf[i] = f16_to_f32(VuV.hf[2*i+1])) + +ITERATOR_INSN_IEEE_FP_16(16, vcvt_hf_uh, "Vd32.hf=vcvt(Vu32.uh)", + "Vector IEEE cvt from int: uh to hf", + VdV.hf[i] = uint64_to_float16_scalbn(VuV.uh[i], float_round_nearest_even, 0)) +ITERATOR_INSN_IEEE_FP_16(16, vcvt_hf_h, "Vd32.hf=vcvt(Vu32.h)", + "Vector IEEE cvt from int: h to hf", + VdV.hf[i] = int64_to_float16_scalbn(VuV.h[i], float_round_nearest_even, 0)) +ITERATOR_INSN_IEEE_FP_16_32(16, vcvt_uh_hf, "Vd32.uh=vcvt(Vu32.hf)", + "Vector IEEE cvt to int: hf to uh", + VdV.uh[i] = float16_to_uint16_scalbn(VuV.hf[i], float_round_nearest_even, 0, &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16_32(16, vcvt_h_hf, "Vd32.h=vcvt(Vu32.hf)", + "Vector IEEE cvt to int: hf to h", + VdV.h[i] = float16_to_int16_scalbn(VuV.hf[i], float_round_nearest_even, 0, &env->hvx_fp_status)) + +ITERATOR_INSN_IEEE_FP_16(32, vcvt_hf_sf, "Vd32.hf=vcvt(Vu32.sf,Vv32.sf)", + "Vector IEEE cvt: sf to hf", + VdV.hf[2*i] = f32_to_f16(VuV.sf[i]); + VdV.hf[2*i+1] = f32_to_f16(VvV.sf[i])) + +ITERATOR_INSN_IEEE_FP_16_32(32, vcvt_ub_hf, "Vd32.ub=vcvt(Vu32.hf,Vv32.hf)", "Vector cvt to int: hf narrow to ub", + VdV.ub[4*i] = float16_to_uint8_scalbn(VuV.hf[2*i], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.ub[4*i+1] = float16_to_uint8_scalbn(VuV.hf[2*i+1], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.ub[4*i+2] = float16_to_uint8_scalbn(VvV.hf[2*i], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.ub[4*i+3] = float16_to_uint8_scalbn(VvV.hf[2*i+1], float_round_nearest_even, 0, &env->hvx_fp_status)) + +ITERATOR_INSN_IEEE_FP_16_32(32, vcvt_b_hf, "Vd32.b=vcvt(Vu32.hf,Vv32.hf)", + "Vector cvt to int: hf narrow to b", + VdV.b[4*i] = float16_to_int8_scalbn(VuV.hf[2*i], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.b[4*i+1] = float16_to_int8_scalbn(VuV.hf[2*i+1], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.b[4*i+2] = float16_to_int8_scalbn(VvV.hf[2*i], float_round_nearest_even, 0, &env->hvx_fp_status); + VdV.b[4*i+3] = float16_to_int8_scalbn(VvV.hf[2*i+1], float_round_nearest_even, 0, &env->hvx_fp_status)) + +ITERATOR_INSN_SHIFT_SLOT_FLT(32, vconv_w_sf,"Vd32.w=Vu32.sf", + "Vector conversion of sf32 format to int w", + VdV.w[i] = conv_w_sf(VuV.sf[i], &env->hvx_fp_status)) + +ITERATOR_INSN_SHIFT_SLOT_FLT(16, vconv_h_hf,"Vd32.h=Vu32.hf", + "Vector conversion of hf16 format to int hw", + VdV.h[i] = conv_h_hf(VuV.hf[i], &env->hvx_fp_status)) + +ITERATOR_INSN_SHIFT_SLOT_FLT(32, vconv_sf_w,"Vd32.sf=Vu32.w", + "Vector conversion of int w format to sf32", + VdV.sf[i] = int32_to_float32(VuV.w[i], &env->hvx_fp_status)) + +ITERATOR_INSN_SHIFT_SLOT_FLT(16, vconv_hf_h,"Vd32.hf=Vu32.h", + "Vector conversion of int hw format to hf16", + VdV.hf[i] = float16_val(int16_to_float16(VuV.h[i], &env->hvx_fp_status))) + /****************************************************************************** DEBUG Vector/Register Printing ******************************************************************************/ diff --git a/target/hexagon/mmvec/hvx_ieee_fp.c b/target/hexagon/mmvec/hvx_ieee_fp.c index 2ae79a485a..697f35b5ed 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.c +++ b/target/hexagon/mmvec/hvx_ieee_fp.c @@ -69,3 +69,21 @@ float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status) } return float16_min(a1, a2, fp_status); } + +int32_t conv_w_sf(float32 a, float_status *fp_status) +{ + /* float32_to_int32 converts any NaN to MAX, hexagon looks at the sign. */ + if (float32_is_any_nan(a)) { + return float32_is_neg(a) ? INT32_MIN : INT32_MAX; + } + return float32_to_int32_round_to_zero(a, fp_status); +} + +int16_t conv_h_hf(float16 a, float_status *fp_status) +{ + /* float16_to_int16 converts any NaN to MAX, hexagon looks at the sign. */ + if (float16_is_any_nan(a)) { + return float16_is_neg(a) ? INT16_MIN : INT16_MAX; + } + return float16_to_int16_round_to_zero(a, fp_status); +} diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h index dff2fab14c..bdc21e08f0 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.h +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -10,6 +10,7 @@ #include "fpu/softfloat.h" #define f16_to_f32(A) float16_to_float32((A), true, &env->hvx_fp_status) +#define f32_to_f16(A) float32_to_float16((A), true, &env->hvx_fp_status) float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status); float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, @@ -21,4 +22,7 @@ float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status); float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status); float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status); +int32_t conv_w_sf(float32 a, float_status *fp_status); +int16_t conv_h_hf(float16 a, float_status *fp_status); + #endif From 7646bc0b72a78960d497371036d5841dc590412b Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:38:59 -0700 Subject: [PATCH 197/627] target/hexagon: add v68 HVX IEEE float compare insns Add HVX IEEE floating-point compare instructions: - V6_vgthf, V6_vgtsf: greater-than compare - V6_vgthf_and, V6_vgtsf_and: greater-than with predicate-and - V6_vgthf_or, V6_vgtsf_or: greater-than with predicate-or - V6_vgthf_xor, V6_vgtsf_xor: greater-than with predicate-xor Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/96e27588ad5a7d47ba9f56f1d547729a19b691c5.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/imported/mmvec/encode_ext.def | 10 ++++ target/hexagon/imported/mmvec/ext.idef | 61 ++++++++++++++++++++ target/hexagon/mmvec/hvx_ieee_fp.c | 48 +++++++++++++++ target/hexagon/mmvec/hvx_ieee_fp.h | 4 ++ target/hexagon/mmvec/macros.h | 6 +- 5 files changed, 128 insertions(+), 1 deletion(-) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index c1ed1b6c23..3572e4de4c 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -858,4 +858,14 @@ DEF_ENC(V6_vconv_w_sf,"00011110--0--101PP1uuuuu001ddddd") DEF_ENC(V6_vconv_hf_h,"00011110--0--101PP1uuuuu100ddddd") DEF_ENC(V6_vconv_h_hf,"00011110--0--101PP1uuuuu010ddddd") +/* IEEE FP compare instructions */ +DEF_ENC(V6_vgtsf,"00011100100vvvvvPP1uuuuu011100dd") +DEF_ENC(V6_vgthf,"00011100100vvvvvPP1uuuuu011101dd") +DEF_ENC(V6_vgtsf_and,"00011100100vvvvvPP1uuuuu110010xx") +DEF_ENC(V6_vgthf_and,"00011100100vvvvvPP1uuuuu110011xx") +DEF_ENC(V6_vgtsf_or,"00011100100vvvvvPP1uuuuu001100xx") +DEF_ENC(V6_vgthf_or,"00011100100vvvvvPP1uuuuu001101xx") +DEF_ENC(V6_vgtsf_xor,"00011100100vvvvvPP1uuuuu111010xx") +DEF_ENC(V6_vgthf_xor,"00011100100vvvvvPP1uuuuu111011xx") + #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 788ce1d2ae..a7043d598c 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -3143,6 +3143,67 @@ ITERATOR_INSN_SHIFT_SLOT_FLT(16, vconv_hf_h,"Vd32.hf=Vu32.h", "Vector conversion of int hw format to hf16", VdV.hf[i] = float16_val(int16_to_float16(VuV.h[i], &env->hvx_fp_status))) +/****************************************************************************** + * IEEE FP compare instructions + ******************************************************************************/ + +#define VCMPGT_SF(DEST, ASRC, ASRCOP, CMP, N, SRC, MASK, WIDTH) \ +{ \ + for (fHIDE(int) i = 0; i < fVBYTES(); i += WIDTH) { \ + fHIDE(int) VAL = fCMPGT_SF(VuV.SRC[i/WIDTH],VvV.SRC[i/WIDTH]) ? MASK : 0; \ + fSETQBITS(DEST,WIDTH,MASK,i,ASRC ASRCOP VAL); \ + } \ +} + +#define VCMPGT_HF(DEST, ASRC, ASRCOP, CMP, N, SRC, MASK, WIDTH) \ +{ \ + for (fHIDE(int) i = 0; i < fVBYTES(); i += WIDTH) { \ + fHIDE(int) VAL = fCMPGT_HF(VuV.SRC[i/WIDTH],VvV.SRC[i/WIDTH]) ? MASK : 0; \ + fSETQBITS(DEST,WIDTH,MASK,i,ASRC ASRCOP VAL); \ + } \ +} + +/* Vector SF compare */ +#define MMVEC_CMPGT_SF(TYPE,TYPE2,DESCR,N,MASK,WIDTH,SRC) \ + EXTINSN(V6_vgt##TYPE##_and, "Qx4&=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-and", \ + VCMPGT_SF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), &, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_xor, "Qx4^=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-xor", \ + VCMPGT_SF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), ^, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_or, "Qx4|=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-or", \ + VCMPGT_SF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), |, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE, "Qd4=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than", \ + VCMPGT_SF(QdV, , , ">", N, SRC, MASK, WIDTH)) + +/* Vector HF compare */ +#define MMVEC_CMPGT_HF(TYPE,TYPE2,DESCR,N,MASK,WIDTH,SRC) \ + EXTINSN(V6_vgt##TYPE##_and, "Qx4&=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-and", \ + VCMPGT_HF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), &, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_xor, "Qx4^=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-xor", \ + VCMPGT_HF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), ^, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_or, "Qx4|=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-or", \ + VCMPGT_HF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), |, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE, "Qd4=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than", \ + VCMPGT_HF(QdV, , , ">", N, SRC, MASK, WIDTH)) + +MMVEC_CMPGT_SF(sf,"sf","Vector sf Compare ", fVELEM(32), 0xF, 4, sf) +MMVEC_CMPGT_HF(hf,"hf","Vector hf Compare ", fVELEM(16), 0x3, 2, hf) + /****************************************************************************** DEBUG Vector/Register Printing ******************************************************************************/ diff --git a/target/hexagon/mmvec/hvx_ieee_fp.c b/target/hexagon/mmvec/hvx_ieee_fp.c index 697f35b5ed..d7751adbe2 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.c +++ b/target/hexagon/mmvec/hvx_ieee_fp.c @@ -87,3 +87,51 @@ int16_t conv_h_hf(float16 a, float_status *fp_status) } return float16_to_int16_round_to_zero(a, fp_status); } + +/* + * Returns true if f1 > f2, where at least one of the elements is guaranteed + * to be NaN. + * Up to v73, Hexagon HVX IEEE FP follows this order: + * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg + */ +static bool float32_nan_compare(float32 f1, float32 f2, float_status *fp_status) +{ + /* opposite signs case */ + if (float32_is_neg(f1) != float32_is_neg(f2)) { + return !float32_is_neg(f1); + } + + /* same sign case */ + bool result = (float32_is_any_nan(f1) && !float32_is_any_nan(f2)) || + (float32_is_quiet_nan(f1, fp_status) && !float32_is_quiet_nan(f2, fp_status)); + return float32_is_neg(f1) ? !result : result; +} + +static bool float16_nan_compare(float16 f1, float16 f2, float_status *fp_status) +{ + /* opposite signs case */ + if (float16_is_neg(f1) != float16_is_neg(f2)) { + return !float16_is_neg(f1); + } + + /* same sign case */ + bool result = (float16_is_any_nan(f1) && !float16_is_any_nan(f2)) || + (float16_is_quiet_nan(f1, fp_status) && !float16_is_quiet_nan(f2, fp_status)); + return float16_is_neg(f1) ? !result : result; +} + +uint32_t cmpgt_sf(float32 a1, float32 a2, float_status *fp_status) +{ + if (float32_is_any_nan(a1) || float32_is_any_nan(a2)) { + return float32_nan_compare(a1, a2, fp_status); + } + return float32_compare(a1, a2, fp_status) == float_relation_greater; +} + +uint16_t cmpgt_hf(float16 a1, float16 a2, float_status *fp_status) +{ + if (float16_is_any_nan(a1) || float16_is_any_nan(a2)) { + return float16_nan_compare(a1, a2, fp_status); + } + return float16_compare(a1, a2, fp_status) == float_relation_greater; +} diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h index bdc21e08f0..01728121eb 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.h +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -25,4 +25,8 @@ float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status); int32_t conv_w_sf(float32 a, float_status *fp_status); int16_t conv_h_hf(float16 a, float_status *fp_status); +/* IEEE - FP compare instructions */ +uint32_t cmpgt_sf(float32 a1, float32 a2, float_status *fp_status); +uint16_t cmpgt_hf(float16 a1, float16 a2, float_status *fp_status); + #endif diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index ac709d8993..757fbec5c9 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -354,6 +354,10 @@ do { \ COE = (sextract32(VAL, 24 + 2 * POS, 2) << 8) | \ extract32(VAL, POS * 8, 8); \ - } while (0); + } while (0) \ + ; + +#define fCMPGT_SF(A, B) cmpgt_sf(A, B, &env->hvx_fp_status) +#define fCMPGT_HF(A, B) cmpgt_hf(A, B, &env->hvx_fp_status) #endif From 9d70629fa0e03ee2341f1aab4928d43ed1718d93 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:00 -0700 Subject: [PATCH 198/627] target/hexagon: add v73 HVX IEEE bfloat16 insns Add HVX IEEE bfloat16 (bf16) instructions: Arithmetic operations: - V6_vadd_sf_bf, V6_vsub_sf_bf: add/sub bf16 widening to sf output - V6_vmpy_sf_bf: multiply bf16 widening to sf output - V6_vmpy_sf_bf_acc: multiply-accumulate bf16 widening to sf output Min/Max operations: - V6_vmin_bf, V6_vmax_bf: bf16 min/max Comparison operations: - V6_vgtbf: greater-than compare - V6_vgtbf_and, V6_vgtbf_or, V6_vgtbf_xor: predicate variants Conversion operations: - V6_vcvt_bf_sf: convert sf to bf16 Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/1a253373567781e0e141c34b41eaffad4789a493.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- target/hexagon/imported/mmvec/encode_ext.def | 15 +++++ target/hexagon/imported/mmvec/ext.idef | 62 ++++++++++++++++++++ target/hexagon/mmvec/hvx_ieee_fp.h | 37 ++++++++++++ target/hexagon/mmvec/macros.h | 4 ++ target/hexagon/mmvec/mmvec.h | 1 + 5 files changed, 119 insertions(+) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 3572e4de4c..16f043b77d 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -868,4 +868,19 @@ DEF_ENC(V6_vgthf_or,"00011100100vvvvvPP1uuuuu001101xx") DEF_ENC(V6_vgtsf_xor,"00011100100vvvvvPP1uuuuu111010xx") DEF_ENC(V6_vgthf_xor,"00011100100vvvvvPP1uuuuu111011xx") +/* BFLOAT instructions */ +DEF_ENC(V6_vmpy_sf_bf,"00011101010vvvvvPP1uuuuu100ddddd") +DEF_ENC(V6_vmpy_sf_bf_acc,"00011101000vvvvvPP1uuuuu000xxxxx") +DEF_ENC(V6_vadd_sf_bf,"00011101010vvvvvPP1uuuuu110ddddd") +DEF_ENC(V6_vsub_sf_bf,"00011101010vvvvvPP1uuuuu101ddddd") +DEF_ENC(V6_vmax_bf,"00011101010vvvvvPP1uuuuu111ddddd") +DEF_ENC(V6_vmin_bf,"00011101010vvvvvPP1uuuuu000ddddd") +DEF_ENC(V6_vcvt_bf_sf,"00011101010vvvvvPP1uuuuu011ddddd") + +/* BFLOAT compare instructions */ +DEF_ENC(V6_vgtbf,"00011100100vvvvvPP1uuuuu011110dd") +DEF_ENC(V6_vgtbf_and,"00011100100vvvvvPP1uuuuu110100xx") +DEF_ENC(V6_vgtbf_or,"00011100100vvvvvPP1uuuuu001110xx") +DEF_ENC(V6_vgtbf_xor,"00011100100vvvvvPP1uuuuu111100xx") + #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index a7043d598c..857aa6133f 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -3163,6 +3163,15 @@ ITERATOR_INSN_SHIFT_SLOT_FLT(16, vconv_hf_h,"Vd32.hf=Vu32.h", } \ } +#define VCMPGT_BF(DEST, ASRC, ASRCOP, CMP, N, SRC, MASK, WIDTH) \ +{ \ + fBFLOAT(); \ + for (fHIDE(int) i = 0; i < fVBYTES(); i += WIDTH) { \ + fHIDE(int) VAL = fCMPGT_BF(VuV.SRC[i/WIDTH],VvV.SRC[i/WIDTH]) ? MASK : 0; \ + fSETQBITS(DEST,WIDTH,MASK,i,ASRC ASRCOP VAL); \ + } \ +} + /* Vector SF compare */ #define MMVEC_CMPGT_SF(TYPE,TYPE2,DESCR,N,MASK,WIDTH,SRC) \ EXTINSN(V6_vgt##TYPE##_and, "Qx4&=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ @@ -3201,8 +3210,61 @@ ITERATOR_INSN_SHIFT_SLOT_FLT(16, vconv_hf_h,"Vd32.hf=Vu32.h", DESCR" greater than", \ VCMPGT_HF(QdV, , , ">", N, SRC, MASK, WIDTH)) +/* Vector BF compare */ +#define MMVEC_CMPGT_BF(TYPE,TYPE2,DESCR,N,MASK,WIDTH,SRC) \ + EXTINSN(V6_vgt##TYPE##_and, "Qx4&=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")",\ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-and", \ + VCMPGT_BF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), &, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_xor, "Qx4^=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-xor", \ + VCMPGT_BF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), ^, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE##_or, "Qx4|=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than with predicate-or", \ + VCMPGT_BF(QxV, fGETQBITS(QxV,WIDTH,MASK,i), |, ">", N, SRC, MASK, WIDTH)) \ + EXTINSN(V6_vgt##TYPE, "Qd4=vcmp.gt(Vu32." TYPE2 ",Vv32." TYPE2 ")", \ + ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \ + DESCR" greater than", \ + VCMPGT_BF(QdV, , , ">", N, SRC, MASK, WIDTH)) + MMVEC_CMPGT_SF(sf,"sf","Vector sf Compare ", fVELEM(32), 0xF, 4, sf) MMVEC_CMPGT_HF(hf,"hf","Vector hf Compare ", fVELEM(16), 0x3, 2, hf) +MMVEC_CMPGT_BF(bf,"bf","Vector bf Compare ", fVELEM(16), 0x3, 2, bf) + +/****************************************************************************** + BFloat arithmetic and max/min instructions + ******************************************************************************/ + +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vadd_sf_bf, + "Vdd32.sf=vadd(Vu32.bf,Vv32.bf)", "Vector IEEE add: bf widen to sf", + VddV.v[0].sf[i] = fp_add_sf_bf(VuV.bf[2*i], VvV.bf[2*i]); + VddV.v[1].sf[i] = fp_add_sf_bf(VuV.bf[2*i+1], VvV.bf[2*i+1]); fBFLOAT()) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_bf, + "Vdd32.sf=vsub(Vu32.bf,Vv32.bf)", "Vector IEEE sub: bf widen to sf", + VddV.v[0].sf[i] = fp_sub_sf_bf(VuV.bf[2*i], VvV.bf[2*i]); + VddV.v[1].sf[i] = fp_sub_sf_bf(VuV.bf[2*i+1], VvV.bf[2*i+1]); fBFLOAT()) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_bf, + "Vdd32.sf=vmpy(Vu32.bf,Vv32.bf)", "Vector IEEE mul: hf widen to sf", + VddV.v[0].sf[i] = fp_mult_sf_bf(VuV.bf[2*i], VvV.bf[2*i]); + VddV.v[1].sf[i] = fp_mult_sf_bf(VuV.bf[2*i+1], VvV.bf[2*i+1]); fBFLOAT()) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_bf_acc, + "Vxx32.sf+=vmpy(Vu32.bf,Vv32.bf)", "Vector IEEE fma: hf widen to sf", + VxxV.v[0].sf[i] = fp_mult_sf_bf_acc(VuV.bf[2*i], VvV.bf[2*i], VxxV.v[0].sf[i]); + VxxV.v[1].sf[i] = fp_mult_sf_bf_acc(VuV.bf[2*i+1], VvV.bf[2*i+1], VxxV.v[1].sf[i]); + fCVI_VX_NO_TMP_LD(); fBFLOAT()) +ITERATOR_INSN_IEEE_FP_16(32, vcvt_bf_sf, + "Vd32.bf=vcvt(Vu32.sf,Vv32.sf)", "Vector IEEE cvt: sf to bf", + VdV.bf[2*i] = f32_to_bf16(VuV.sf[i], &env->hvx_fp_status); + VdV.bf[2*i+1] = f32_to_bf16(VvV.sf[i], &env->hvx_fp_status); fBFLOAT()) + +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vmax_bf, "Vd32.bf=vmax(Vu32.bf,Vv32.bf)", + "Vector IEEE max: bf", VdV.bf[i] = fp_max_bf(VuV.bf[i], VvV.bf[i]); + fBFLOAT()) +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vmin_bf, "Vd32.bf=vmin(Vu32.bf,Vv32.bf)", + "Vector IEEE min: bf", VdV.bf[i] = fp_min_bf(VuV.bf[i], VvV.bf[i]); + fBFLOAT()) /****************************************************************************** DEBUG Vector/Register Printing diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h index 01728121eb..b7e379b089 100644 --- a/target/hexagon/mmvec/hvx_ieee_fp.h +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -9,8 +9,11 @@ #include "fpu/softfloat.h" +#define FP32_DEF_NAN 0x7FFFFFFF + #define f16_to_f32(A) float16_to_float32((A), true, &env->hvx_fp_status) #define f32_to_f16(A) float32_to_float16((A), true, &env->hvx_fp_status) +#define bf16_to_f32(A) bfloat16_to_float32(A, &env->hvx_fp_status) float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status); float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, @@ -29,4 +32,38 @@ int16_t conv_h_hf(float16 a, float_status *fp_status); uint32_t cmpgt_sf(float32 a1, float32 a2, float_status *fp_status); uint16_t cmpgt_hf(float16 a1, float16 a2, float_status *fp_status); +/* IEEE BFloat instructions */ + +#define fp_mult_sf_bf(A, B) \ + float32_mul(bf16_to_f32(A), bf16_to_f32(B), &env->hvx_fp_status) + +#define fp_add_sf_bf(A, B) \ + float32_add(bf16_to_f32(A), bf16_to_f32(B), &env->hvx_fp_status) + +#define fp_sub_sf_bf(A, B) \ + float32_sub(bf16_to_f32(A), bf16_to_f32(B), &env->hvx_fp_status) + +#define fp_mult_sf_bf_acc(f1, f2, f3) \ + float32_muladd(bf16_to_f32(f1), bf16_to_f32(f2), f3, 0, &env->hvx_fp_status) + +static inline bfloat16 f32_to_bf16(float32 A, float_status *fp_status) +{ + uint32_t rslt = A; + if ((rslt & 0x1FFFF) == 0x08000) { + /* do not round up if exactly .5 and even already */ + } else if ((rslt & 0x8000) == 0x8000) { + rslt += 0x8000; /* rounding to nearest number */ + } + rslt = float32_is_any_nan(A) ? FP32_DEF_NAN : rslt; + return float32_to_bfloat16(rslt, fp_status); +} + +#define fp_min_bf(A, B) \ + f32_to_bf16(float32_min(bf16_to_f32(A), bf16_to_f32(B), &env->hvx_fp_status), \ + &env->hvx_fp_status); + +#define fp_max_bf(A, B) \ + f32_to_bf16(float32_max(bf16_to_f32(A), bf16_to_f32(B), &env->hvx_fp_status), \ + &env->hvx_fp_status); + #endif diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index 757fbec5c9..b36f833b1d 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -25,6 +25,9 @@ #include "accel/tcg/probe.h" #include "mmvec/hvx_ieee_fp.h" +#define fBFLOAT() +#define fCVI_VX_NO_TMP_LD() + #ifndef QEMU_GENERATE #define VdV (*(MMVector *restrict)(VdV_void)) #define VsV (*(MMVector *restrict)(VsV_void)) @@ -359,5 +362,6 @@ #define fCMPGT_SF(A, B) cmpgt_sf(A, B, &env->hvx_fp_status) #define fCMPGT_HF(A, B) cmpgt_hf(A, B, &env->hvx_fp_status) +#define fCMPGT_BF(A, B) fCMPGT_SF((uint32_t)(A) << 16, (uint32_t)(B) << 16) #endif diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h index 9841687f83..8e72f2f6ae 100644 --- a/target/hexagon/mmvec/mmvec.h +++ b/target/hexagon/mmvec/mmvec.h @@ -43,6 +43,7 @@ typedef union { int8_t b[MAX_VEC_SIZE_BYTES / 1]; float32 sf[MAX_VEC_SIZE_BYTES / 4]; float16 hf[MAX_VEC_SIZE_BYTES / 2]; + bfloat16 bf[MAX_VEC_SIZE_BYTES / 2]; } MMVector; typedef union { From 449e485814ddadb1ae6f50ca9c9e01a248985eae Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:01 -0700 Subject: [PATCH 199/627] tests/hexagon: add tests for v68 HVX IEEE float arithmetics Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/791f122bfd744a77177608b524d852fe826cd595.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/Makefile.target | 8 ++ tests/tcg/hexagon/fp_hvx.c | 155 ++++++++++++++++++++++++++++ tests/tcg/hexagon/fp_hvx_disabled.c | 57 ++++++++++ tests/tcg/hexagon/hex_test.h | 4 + tests/tcg/hexagon/hvx_misc.h | 41 ++++++++ 5 files changed, 265 insertions(+) create mode 100644 tests/tcg/hexagon/fp_hvx.c create mode 100644 tests/tcg/hexagon/fp_hvx_disabled.c diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 80e56f7d05..2a5958711b 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -50,6 +50,8 @@ HEX_TESTS += vector_add_int HEX_TESTS += scatter_gather HEX_TESTS += hvx_misc HEX_TESTS += hvx_histogram +HEX_TESTS += fp_hvx +HEX_TESTS += fp_hvx_disabled HEX_TESTS += invalid-slots HEX_TESTS += valid-slots HEX_TESTS += invalid-encoding @@ -136,6 +138,12 @@ v68_hvx: CFLAGS += -mhvx -Wno-unused-function v69_hvx: v69_hvx.c hvx_misc.h v69_hvx: CFLAGS += -mhvx -Wno-unused-function v73_scalar: CFLAGS += -Wno-unused-function +fp_hvx: fp_hvx.c hvx_misc.h hex_test.h +fp_hvx: CFLAGS += -mhvx -mhvx-ieee-fp +fp_hvx_disabled: fp_hvx_disabled.c hvx_misc.h hex_test.h +fp_hvx_disabled: CFLAGS += -mhvx -mhvx-ieee-fp + +run-fp_hvx_disabled: QEMU_OPTS += -cpu v73,ieee-fp=false hvx_histogram: hvx_histogram.c hvx_histogram_row.S $(CC) $(CFLAGS) $(CROSS_CC_GUEST_CFLAGS) $^ -o $@ $(LDFLAGS) diff --git a/tests/tcg/hexagon/fp_hvx.c b/tests/tcg/hexagon/fp_hvx.c new file mode 100644 index 0000000000..a309654ed7 --- /dev/null +++ b/tests/tcg/hexagon/fp_hvx.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include + +int err; +#include "hvx_misc.h" + +#if __HEXAGON_ARCH__ > 75 +#error "After v75, compiler will replace some FP HVX instructions." +#endif + +/****************************************************************************** + * NAN handling + *****************************************************************************/ + +#define isnan(X) \ + (sizeof(X) == bytes_hf ? ((raw_hf(X) & ~0x8000) > 0x7c00) : \ + ((raw_sf(X) & ~(1 << 31)) > 0x7f800000UL)) + +#define CHECK_NAN(A, DEF_NAN) (isnan(A) ? DEF_NAN : (A)) +#define NAN_SF float_sf(0x7FFFFFFF) +#define NAN_HF float_hf(0x7FFF) + +/****************************************************************************** + * Binary operations + *****************************************************************************/ + +#define DEF_TEST_OP_2(vop, op, type_res, type_arg) \ + static void test_##vop##_##type_res##_##type_arg(void) \ + { \ + memset(expect, 0xff, sizeof(expect)); \ + memset(output, 0xff, sizeof(output)); \ + for (int i = 0; i < BUFSIZE; i++) { \ + HVX_Vector *hvx_output = (HVX_Vector *)&output[i]; \ + HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; \ + HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; \ + *hvx_output = \ + Q6_V##type_res##_##vop##_V##type_arg##V##type_arg(hvx_buffer0, \ + hvx_buffer1); \ + for (int j = 0; j < MAX_VEC_SIZE_BYTES / bytes_##type_res; j++) { \ + expect[i].type_res[j] = \ + raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[j]), \ + float_##type_arg(buffer1[i].type_arg[j]))); \ + } \ + } \ + check_output_##type_res(__LINE__, BUFSIZE); \ + } + +#define SUM(X, Y, DEF_NAN) CHECK_NAN((X) + (Y), DEF_NAN) +#define SUB(X, Y, DEF_NAN) CHECK_NAN((X) - (Y), DEF_NAN) +#define MULT(X, Y, DEF_NAN) CHECK_NAN((X) * (Y), DEF_NAN) + +#define SUM_SF(X, Y) SUM(X, Y, NAN_SF) +#define SUM_HF(X, Y) SUM(X, Y, NAN_HF) +#define SUB_SF(X, Y) SUB(X, Y, NAN_SF) +#define SUB_HF(X, Y) SUB(X, Y, NAN_HF) +#define MULT_SF(X, Y) MULT(X, Y, NAN_SF) +#define MULT_HF(X, Y) MULT(X, Y, NAN_HF) + +DEF_TEST_OP_2(vadd, SUM_SF, sf, sf); +DEF_TEST_OP_2(vadd, SUM_HF, hf, hf); +DEF_TEST_OP_2(vsub, SUB_SF, sf, sf); +DEF_TEST_OP_2(vsub, SUB_HF, hf, hf); +DEF_TEST_OP_2(vmpy, MULT_SF, sf, sf); +DEF_TEST_OP_2(vmpy, MULT_HF, hf, hf); + +/****************************************************************************** + * Other tests + *****************************************************************************/ + +static void test_vdmpy_sf_hf(bool acc) +{ + memset(expect, 0xff, sizeof(expect)); + + for (int i = 0; i < BUFSIZE; i++) { + HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; + HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; + HVX_Vector *hvx_output = (HVX_Vector *)&output[i]; + + uint32_t PREFIL_VAL = 0x111222; + *hvx_output = Q6_V_vsplat_R(PREFIL_VAL); + + if (!acc) { + *hvx_output = Q6_Vsf_vdmpy_VhfVhf(hvx_buffer0, hvx_buffer1); + } else { + *hvx_output = Q6_Vsf_vdmpyacc_VsfVhfVhf(*hvx_output, hvx_buffer0, + hvx_buffer1); + } + + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { + float a1 = float_hf_to_sf(float_hf(buffer0[i].hf[2 * j + 1])); + float a2 = float_hf_to_sf(float_hf(buffer0[i].hf[2 * j])); + float a3 = float_hf_to_sf(float_hf(buffer1[i].hf[2 * j + 1])); + float a4 = float_hf_to_sf(float_hf(buffer1[i].hf[2 * j])); + /* + * Note, IEEE FP specifies +0.0 + -0.0 == +0.0. So we use -0.0 in + * the default case to preserve the zero sign. + */ + float prev = acc ? float_sf(PREFIL_VAL) : -0.0; + expect[i].sf[j] = raw_sf(CHECK_NAN((a1 * a3) + (a2 * a4) + prev, NAN_SF)); + } + } + check_output_sf(__LINE__, BUFSIZE); +} + +static void test_new(void) +{ + asm volatile("r0 = #%2\n" + "v0 = vsplat(r0)\n" + "vmem(%1 + #0) = v0\n" + "r1 = #%3\n" + "v1 = vsplat(r1)\n" + "v2 = vsplat(r1)\n" + "{\n" + " v0.sf = vadd(v1.sf, v2.sf)\n" + " vmem(%0 + #0) = v0.new\n" + "}\n" + : + : "r"(output), "r"(expect), "i"(SF_two), "i"(SF_one) + : "r0", "r1", "v0", "v1", "v2", "memory"); + check_output_w(__LINE__, 1); +} + +int main(void) +{ + init_buffers_fp(); + + /* add/sub */ + test_vadd_sf_sf(); + test_vadd_hf_hf(); + test_vsub_sf_sf(); + test_vsub_hf_hf(); + + /* multiply */ + test_vmpy_sf_sf(); + test_vmpy_hf_hf(); + + /* dot product */ + test_vdmpy_sf_hf(false); + test_vdmpy_sf_hf(true); + + test_new(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} diff --git a/tests/tcg/hexagon/fp_hvx_disabled.c b/tests/tcg/hexagon/fp_hvx_disabled.c new file mode 100644 index 0000000000..388a42e2b7 --- /dev/null +++ b/tests/tcg/hexagon/fp_hvx_disabled.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include + +int err; +#include "hvx_misc.h" + +static void test_disabled(void) +{ + memset(output, 0xAA, sizeof(output)); + memset(expect, 0, sizeof(expect)); + asm volatile("r0 = #0xff\n" + "v0 = vsplat(r0)\n" + "r1 = #0x1\n" + "v1 = vsplat(r1)\n" + "v2 = vsplat(r1)\n" + "v0.sf = vadd(v1.sf, v2.sf)\n" + "vmem(%0 + #0) = v0\n" + : + : "r"(output) + : "r0", "r1", "v0", "v1", "v2", "memory"); + check_output_w(__LINE__, 1); +} + +static void test_disabled_with_new(void) +{ + memset(output, 0xAA, sizeof(output)); + memset(expect, 0, sizeof(expect)); + asm volatile("r0 = #0xff\n" + "v0 = vsplat(r0)\n" + "r1 = #0x1\n" + "v1 = vsplat(r1)\n" + "v2 = vsplat(r1)\n" + "{\n" + " v0.sf = vadd(v1.sf, v2.sf)\n" + " vmem(%0 + #0) = v0.new\n" + "}\n" + : + : "r"(output) + : "r0", "r1", "v0", "v1", "v2", "memory"); + check_output_w(__LINE__, 1); +} + +int main(void) +{ + test_disabled(); + test_disabled_with_new(); + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} diff --git a/tests/tcg/hexagon/hex_test.h b/tests/tcg/hexagon/hex_test.h index cfed06a58b..e7a6644d41 100644 --- a/tests/tcg/hexagon/hex_test.h +++ b/tests/tcg/hexagon/hex_test.h @@ -19,6 +19,8 @@ #ifndef HEX_TEST_H #define HEX_TEST_H +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + static inline void __check32(int line, uint32_t val, uint32_t expect) { if (val != expect) { @@ -110,6 +112,7 @@ static inline void __check64_ne(int line, uint64_t val, uint64_t expect) /* Some useful floating point values */ const uint32_t SF_INF = 0x7f800000; +const uint32_t SF_INF_neg = 0xff800000; const uint32_t SF_QNaN = 0x7fc00000; const uint32_t SF_QNaN_special = 0x7f800001; const uint32_t SF_SNaN = 0x7fb00000; @@ -128,6 +131,7 @@ const uint32_t SF_large_pos = 0x5afa572e; const uint32_t SF_any = 0x3f800000; const uint32_t SF_denorm = 0x00000001; const uint32_t SF_random = 0x346001d6; +const uint32_t SF_neg_two = 0xc0000000; const uint64_t DF_QNaN = 0x7ff8000000000000ULL; const uint64_t DF_SNaN = 0x7ff7000000000000ULL; diff --git a/tests/tcg/hexagon/hvx_misc.h b/tests/tcg/hexagon/hvx_misc.h index 2e868340fd..0330cb289d 100644 --- a/tests/tcg/hexagon/hvx_misc.h +++ b/tests/tcg/hexagon/hvx_misc.h @@ -18,6 +18,8 @@ #ifndef HVX_MISC_H #define HVX_MISC_H +#include "hex_test.h" + static inline void check(int line, int i, int j, uint64_t result, uint64_t expect) { @@ -34,8 +36,10 @@ typedef union { uint64_t ud[MAX_VEC_SIZE_BYTES / 8]; int64_t d[MAX_VEC_SIZE_BYTES / 8]; uint32_t uw[MAX_VEC_SIZE_BYTES / 4]; + uint32_t sf[MAX_VEC_SIZE_BYTES / 4]; /* convenience alias */ int32_t w[MAX_VEC_SIZE_BYTES / 4]; uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; + uint16_t hf[MAX_VEC_SIZE_BYTES / 2]; /* convenience alias */ int16_t h[MAX_VEC_SIZE_BYTES / 2]; uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; int8_t b[MAX_VEC_SIZE_BYTES / 1]; @@ -63,7 +67,9 @@ static inline void check_output_##FIELD(int line, size_t num_vectors) \ CHECK_OUTPUT_FUNC(d, 8) CHECK_OUTPUT_FUNC(w, 4) +CHECK_OUTPUT_FUNC(sf, 4) CHECK_OUTPUT_FUNC(h, 2) +CHECK_OUTPUT_FUNC(hf, 2) CHECK_OUTPUT_FUNC(b, 1) static inline void init_buffers(void) @@ -81,6 +87,33 @@ static inline void init_buffers(void) } } +static const uint32_t FP_VALUES[] = { + SF_INF, SF_INF_neg, SF_QNaN, SF_QNaN_special, SF_SNaN, SF_QNaN_neg, + SF_SNaN_neg, SF_HEX_NaN, SF_zero, SF_zero_neg, SF_one, SF_one_recip, + SF_one_invsqrta, SF_two, SF_four, SF_small_neg, SF_large_pos, SF_any, + SF_denorm, SF_random, SF_neg_two, +}; +#define FP_VALUES_MAX ARRAY_SIZE(FP_VALUES) + +static inline void init_buffers_fp(void) +{ + _Static_assert(BUFSIZE * (MAX_VEC_SIZE_BYTES / 4) > + FP_VALUES_MAX * FP_VALUES_MAX, + "test arrays can't fit all FP_VALUES combinations"); + int counter1 = 0, counter2 = 0; + for (int i = 0; i < BUFSIZE; i++) { + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) { + buffer0[i].sf[j] = FP_VALUES[counter1]; + buffer1[i].sf[j] = FP_VALUES[counter2]; + counter2++; + if (counter2 == FP_VALUES_MAX) { + counter2 = 0; + counter1 = (counter1 + 1) % FP_VALUES_MAX; + } + } + } +} + #define VEC_OP1(ASM, EL, IN, OUT) \ asm("v2 = vmem(%0 + #0)\n\t" \ "v2" #EL " = " #ASM "(v2" #EL ")\n\t" \ @@ -175,4 +208,12 @@ static inline void test_##NAME(bool invert) \ check_output_b(__LINE__, BUFSIZE); \ } +#define float_sf(x) ({ typeof(x) _x = (x); *((float *)&(_x)); }) +#define float_hf(x) ({ typeof(x) _x = (x); *((_Float16 *) &(_x)); }) +#define raw_sf(x) ({ typeof(x) _x = (x); *((uint32_t *)&(_x)); }) +#define raw_hf(x) ({ typeof(x) _x = (x); *((uint16_t *)&(_x)); }) +#define float_hf_to_sf(x) ((float)x) +#define bytes_hf 2 +#define bytes_sf 4 + #endif From 7f3a641101f683549e60de55d30c5006ee97d996 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:02 -0700 Subject: [PATCH 200/627] tests/hexagon: add tests for v68 HVX IEEE float min/max Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/7fdbc12ed4c62a16068c380a85ee2356051e61ea.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/fp_hvx.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/tcg/hexagon/fp_hvx.c b/tests/tcg/hexagon/fp_hvx.c index a309654ed7..dee0781bd7 100644 --- a/tests/tcg/hexagon/fp_hvx.c +++ b/tests/tcg/hexagon/fp_hvx.c @@ -73,6 +73,30 @@ DEF_TEST_OP_2(vsub, SUB_HF, hf, hf); DEF_TEST_OP_2(vmpy, MULT_SF, sf, sf); DEF_TEST_OP_2(vmpy, MULT_HF, hf, hf); +#define signbit_fp(X) \ + (sizeof(X) == bytes_hf ? ((raw_hf(X) & 0x8000) != 0) : \ + ((raw_sf(X) & 0x80000000) != 0)) + +#define STD_MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#define STD_MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +#define MIN(X, Y, DEF_NAN) \ + ((isnan(X) || isnan(Y)) ? DEF_NAN : \ + ((X) != (Y)) ? STD_MIN(X, Y) : (signbit_fp(X) ? (X) : (Y))) /* -0 < +0 */ +#define MAX(X, Y, DEF_NAN) \ + ((isnan(X) || isnan(Y)) ? DEF_NAN : \ + ((X) != (Y)) ? STD_MAX(X, Y) : (signbit_fp(X) ? (Y) : (X))) /* -0 < +0 */ + +#define MIN_HF(X, Y) MIN(X, Y, NAN_HF) +#define MAX_HF(X, Y) MAX(X, Y, NAN_HF) +#define MIN_SF(X, Y) MIN(X, Y, NAN_SF) +#define MAX_SF(X, Y) MAX(X, Y, NAN_SF) + +DEF_TEST_OP_2(vfmin, MIN_SF, sf, sf); +DEF_TEST_OP_2(vfmax, MAX_SF, sf, sf); +DEF_TEST_OP_2(vfmin, MIN_HF, hf, hf); +DEF_TEST_OP_2(vfmax, MAX_HF, hf, hf); + /****************************************************************************** * Other tests *****************************************************************************/ @@ -150,6 +174,12 @@ int main(void) test_new(); + /* min/max */ + test_vfmin_sf_sf(); + test_vfmin_hf_hf(); + test_vfmax_sf_sf(); + test_vfmax_hf_hf(); + puts(err ? "FAIL" : "PASS"); return err ? 1 : 0; } From 57da1eb994e4fe7073e9079864ba6d94a7a55ee7 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:03 -0700 Subject: [PATCH 201/627] tests/hexagon: add tests for v68 HVX IEEE float conversions Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/ec6af07a285c47e5f6df343860bfedce5bed9421.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/Makefile.target | 3 + tests/tcg/hexagon/fp_hvx_cvt.c | 188 ++++++++++++++++++++++++++++++ tests/tcg/hexagon/hex_test.h | 14 +++ tests/tcg/hexagon/hvx_misc.h | 2 + 4 files changed, 207 insertions(+) create mode 100644 tests/tcg/hexagon/fp_hvx_cvt.c diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 2a5958711b..0978e7ca91 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -51,6 +51,7 @@ HEX_TESTS += scatter_gather HEX_TESTS += hvx_misc HEX_TESTS += hvx_histogram HEX_TESTS += fp_hvx +HEX_TESTS += fp_hvx_cvt HEX_TESTS += fp_hvx_disabled HEX_TESTS += invalid-slots HEX_TESTS += valid-slots @@ -142,6 +143,8 @@ fp_hvx: fp_hvx.c hvx_misc.h hex_test.h fp_hvx: CFLAGS += -mhvx -mhvx-ieee-fp fp_hvx_disabled: fp_hvx_disabled.c hvx_misc.h hex_test.h fp_hvx_disabled: CFLAGS += -mhvx -mhvx-ieee-fp +fp_hvx_cvt: fp_hvx_cvt.c hvx_misc.h hex_test.h +fp_hvx_cvt: CFLAGS += -mhvx -mhvx-ieee-fp run-fp_hvx_disabled: QEMU_OPTS += -cpu v73,ieee-fp=false diff --git a/tests/tcg/hexagon/fp_hvx_cvt.c b/tests/tcg/hexagon/fp_hvx_cvt.c new file mode 100644 index 0000000000..b08eba92da --- /dev/null +++ b/tests/tcg/hexagon/fp_hvx_cvt.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include + +#if __HEXAGON_ARCH__ > 75 +#error "After v75, compiler will replace some FP HVX instructions." +#endif + +int err; +#include "hvx_misc.h" +#include "hex_test.h" + +#define TEST_EXP(TO, FROM, VAL, EXP) do { \ + ((MMVector *)&buffer)->FROM[index] = VAL; \ + expect[0].TO[index] = EXP; \ + index++; \ +} while (0) + +#define DEF_TEST_CVT(TO, FROM, TESTS) \ + static void test_vcvt_##TO##_##FROM(void) \ + { \ + HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \ + HVX_Vector buffer; \ + int index = 0; \ + memset(&buffer, 0, sizeof(buffer)); \ + memset(expect, 0, sizeof(expect)); \ + TESTS \ + * hvx_output = Q6_V##TO##_vcvt_V##FROM(buffer); \ + check_output_##TO(__LINE__, 1); \ + } + +DEF_TEST_CVT(uh, hf, { \ + TEST_EXP(uh, hf, HF_QNaN, UINT16_MAX); \ + TEST_EXP(uh, hf, HF_SNaN, UINT16_MAX); \ + TEST_EXP(uh, hf, HF_QNaN_neg, UINT16_MAX); \ + TEST_EXP(uh, hf, HF_INF, UINT16_MAX); \ + TEST_EXP(uh, hf, HF_INF_neg, 0); \ + TEST_EXP(uh, hf, HF_neg_two, 0); \ + TEST_EXP(uh, hf, HF_zero_neg, 0); \ + TEST_EXP(uh, hf, raw_hf((_Float16)2.1), 2); \ + TEST_EXP(uh, hf, HF_one_recip, 1); \ +}) + +DEF_TEST_CVT(h, hf, { \ + TEST_EXP(h, hf, HF_QNaN, INT16_MAX); \ + TEST_EXP(h, hf, HF_SNaN, INT16_MAX); \ + TEST_EXP(h, hf, HF_QNaN_neg, INT16_MAX); \ + TEST_EXP(h, hf, HF_INF, INT16_MAX); \ + TEST_EXP(h, hf, HF_INF_neg, INT16_MIN); \ + TEST_EXP(h, hf, HF_neg_two, -2); \ + TEST_EXP(h, hf, HF_zero_neg, 0); \ + TEST_EXP(h, hf, raw_hf((_Float16)2.1), 2); \ + TEST_EXP(h, hf, HF_one_recip, 1); \ +}) + +/* + * Some cvt operations take two vectors as input and perform the following: + * VdV.TO[4*i] = OP(VuV.FROM[2*i]); + * VdV.TO[4*i+1] = OP(VuV.FROM[2*i+1]); + * VdV.TO[4*i+2] = OP(VvV.FROM[2*i]); + * VdV.TO[4*i+3] = OP(VvV.FROM[2*i+1])) + * We use bf_index and index in a way that the tests are always done either + * using the first or third line of the above snippet. + */ +#define TEST_EXP_2(TO, FROM, VAL, EXP) do { \ + ((MMVector *)&buffers[bf_index])->FROM[2 * index] = VAL; \ + expect[0].TO[(4 * index) + (2 * bf_index)] = EXP; \ + index++; \ + bf_index = (bf_index + 1) % 2; \ +} while (0) + +#define DEF_TEST_CVT_2(TO, FROM, TESTS) \ + static void test_vcvt_##TO##_##FROM(void) \ + { \ + HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \ + HVX_Vector buffers[2]; \ + int index = 0, bf_index = 0; \ + memset(&buffers, 0, sizeof(buffers)); \ + memset(expect, 0, sizeof(expect)); \ + TESTS \ + * hvx_output = Q6_V##TO##_vcvt_V##FROM##V##FROM(buffers[0], buffers[1]); \ + check_output_##TO(__LINE__, 1); \ + } + +DEF_TEST_CVT_2(ub, hf, { \ + TEST_EXP_2(ub, hf, HF_QNaN, UINT8_MAX); \ + TEST_EXP_2(ub, hf, HF_SNaN, UINT8_MAX); \ + TEST_EXP_2(ub, hf, HF_QNaN_neg, UINT8_MAX); \ + TEST_EXP_2(ub, hf, HF_INF, UINT8_MAX); \ + TEST_EXP_2(ub, hf, HF_INF_neg, 0); \ + TEST_EXP_2(ub, hf, HF_small_neg, 0); \ + TEST_EXP_2(ub, hf, HF_neg_two, 0); \ + TEST_EXP_2(ub, hf, HF_zero_neg, 0); \ + TEST_EXP_2(ub, hf, raw_hf((_Float16)2.1), 2); \ + TEST_EXP_2(ub, hf, HF_one_recip, 1); \ +}) + +DEF_TEST_CVT_2(b, hf, { \ + TEST_EXP_2(b, hf, HF_QNaN, INT8_MAX); \ + TEST_EXP_2(b, hf, HF_SNaN, INT8_MAX); \ + TEST_EXP_2(b, hf, HF_QNaN_neg, INT8_MAX); \ + TEST_EXP_2(b, hf, HF_INF, INT8_MAX); \ + TEST_EXP_2(b, hf, HF_INF_neg, INT8_MIN); \ + TEST_EXP_2(b, hf, HF_small_neg, 0); \ + TEST_EXP_2(b, hf, HF_neg_two, -2); \ + TEST_EXP_2(b, hf, HF_zero_neg, 0); \ + TEST_EXP_2(b, hf, raw_hf((_Float16)2.1), 2); \ + TEST_EXP_2(b, hf, HF_one_recip, 1); \ +}) + +#define DEF_TEST_VCONV(TO, FROM, TESTS) \ + static void test_vconv_##TO##_##FROM(void) \ + { \ + HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; \ + HVX_Vector buffer; \ + int index = 0; \ + memset(&buffer, 0, sizeof(buffer)); \ + memset(expect, 0, sizeof(expect)); \ + TESTS \ + * hvx_output = Q6_V##TO##_equals_V##FROM(buffer); \ + check_output_##TO(__LINE__, 1); \ + } + +DEF_TEST_VCONV(w, sf, { \ + TEST_EXP(w, sf, SF_QNaN, INT32_MAX); \ + TEST_EXP(w, sf, SF_SNaN, INT32_MAX); \ + TEST_EXP(w, sf, SF_QNaN_neg, INT32_MIN); \ + TEST_EXP(w, sf, SF_INF, INT32_MAX); \ + TEST_EXP(w, sf, SF_INF_neg, INT32_MIN); \ + TEST_EXP(w, sf, SF_small_neg, 0); \ + TEST_EXP(w, sf, SF_neg_two, -2); \ + TEST_EXP(w, sf, SF_zero_neg, 0); \ + TEST_EXP(w, sf, raw_sf(2.1f), 2); \ + TEST_EXP(w, sf, raw_sf(2.8f), 2); \ +}) + +DEF_TEST_VCONV(h, hf, { \ + TEST_EXP(h, hf, HF_QNaN, INT16_MAX); \ + TEST_EXP(h, hf, HF_SNaN, INT16_MAX); \ + TEST_EXP(h, hf, HF_QNaN_neg, INT16_MIN); \ + TEST_EXP(h, hf, HF_INF, INT16_MAX); \ + TEST_EXP(h, hf, HF_INF_neg, INT16_MIN); \ + TEST_EXP(h, hf, HF_small_neg, 0); \ + TEST_EXP(h, hf, HF_neg_two, -2); \ + TEST_EXP(h, hf, HF_zero_neg, 0); \ + TEST_EXP(h, hf, raw_hf((_Float16)2.1), 2); \ + TEST_EXP(h, hf, raw_hf((_Float16)2.8), 2); \ +}) + +DEF_TEST_VCONV(hf, h, { \ + TEST_EXP(hf, h, 0, HF_zero); \ + TEST_EXP(hf, h, 2, HF_two); \ + TEST_EXP(hf, h, -2, HF_neg_two); \ + TEST_EXP(hf, h, 2049, raw_hf((_Float16)2048)); /* rounds DOWN */ \ + TEST_EXP(hf, h, 2051, raw_hf((_Float16)2052)); /* rounds UP */ \ +}) + +DEF_TEST_VCONV(sf, w, { \ + TEST_EXP(sf, w, 0, SF_zero); \ + TEST_EXP(sf, w, 2, SF_two); \ + TEST_EXP(sf, w, -2, SF_neg_two); \ + TEST_EXP(sf, w, 16777217, raw_sf((float)16777216)); /* rounds DOWN */ \ + TEST_EXP(sf, w, 16777219, raw_sf((float)16777220)); /* rounds UP */ \ +}) + +int main(void) +{ + test_vcvt_uh_hf(); + test_vcvt_h_hf(); + test_vcvt_ub_hf(); + test_vcvt_b_hf(); + test_vconv_w_sf(); + test_vconv_sf_w(); + test_vconv_h_hf(); + test_vconv_hf_h(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} diff --git a/tests/tcg/hexagon/hex_test.h b/tests/tcg/hexagon/hex_test.h index e7a6644d41..d5da8ad240 100644 --- a/tests/tcg/hexagon/hex_test.h +++ b/tests/tcg/hexagon/hex_test.h @@ -111,6 +111,20 @@ static inline void __check64_ne(int line, uint64_t val, uint64_t expect) "usr = r2\n\t" /* Some useful floating point values */ +const uint16_t HF_INF = 0x7c00; +const uint16_t HF_INF_neg = 0xfc00; +const uint16_t HF_QNaN = 0x7e00; +const uint16_t HF_SNaN = 0x7d00; +const uint16_t HF_QNaN_neg = 0xfe00; +const uint16_t HF_zero = 0x0000; +const uint16_t HF_zero_neg = 0x8000; +const uint16_t HF_one = 0x3c00; +const uint16_t HF_one_recip = 0x3bf9; +const uint16_t HF_two = 0x4000; +const uint16_t HF_small_neg = 0x8010; +const uint16_t HF_any = 0x3c00; +const uint16_t HF_neg_two = 0xc000; + const uint32_t SF_INF = 0x7f800000; const uint32_t SF_INF_neg = 0xff800000; const uint32_t SF_QNaN = 0x7fc00000; diff --git a/tests/tcg/hexagon/hvx_misc.h b/tests/tcg/hexagon/hvx_misc.h index 0330cb289d..43de20da6a 100644 --- a/tests/tcg/hexagon/hvx_misc.h +++ b/tests/tcg/hexagon/hvx_misc.h @@ -69,7 +69,9 @@ CHECK_OUTPUT_FUNC(d, 8) CHECK_OUTPUT_FUNC(w, 4) CHECK_OUTPUT_FUNC(sf, 4) CHECK_OUTPUT_FUNC(h, 2) +CHECK_OUTPUT_FUNC(uh, 2) CHECK_OUTPUT_FUNC(hf, 2) +CHECK_OUTPUT_FUNC(ub, 1) CHECK_OUTPUT_FUNC(b, 1) static inline void init_buffers(void) From 6bebed5a4771eb8149a9560c762e7dd326f35429 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:04 -0700 Subject: [PATCH 202/627] tests/hexagon: add tests for v68 HVX IEEE float comparisons Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/53e73707092d31bcde6ed8189c5496b00345f8fa.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/Makefile.target | 3 + tests/tcg/hexagon/fp_hvx_cmp.c | 224 ++++++++++++++++++++++++++++++ tests/tcg/hexagon/hex_test.h | 1 + 3 files changed, 228 insertions(+) create mode 100644 tests/tcg/hexagon/fp_hvx_cmp.c diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 0978e7ca91..61adf6356e 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -52,6 +52,7 @@ HEX_TESTS += hvx_misc HEX_TESTS += hvx_histogram HEX_TESTS += fp_hvx HEX_TESTS += fp_hvx_cvt +HEX_TESTS += fp_hvx_cmp HEX_TESTS += fp_hvx_disabled HEX_TESTS += invalid-slots HEX_TESTS += valid-slots @@ -145,6 +146,8 @@ fp_hvx_disabled: fp_hvx_disabled.c hvx_misc.h hex_test.h fp_hvx_disabled: CFLAGS += -mhvx -mhvx-ieee-fp fp_hvx_cvt: fp_hvx_cvt.c hvx_misc.h hex_test.h fp_hvx_cvt: CFLAGS += -mhvx -mhvx-ieee-fp +fp_hvx_cmp: fp_hvx_cmp.c hvx_misc.h hex_test.h +fp_hvx_cmp: CFLAGS += -mhvx -mhvx-ieee-fp run-fp_hvx_disabled: QEMU_OPTS += -cpu v73,ieee-fp=false diff --git a/tests/tcg/hexagon/fp_hvx_cmp.c b/tests/tcg/hexagon/fp_hvx_cmp.c new file mode 100644 index 0000000000..8068d1c3ee --- /dev/null +++ b/tests/tcg/hexagon/fp_hvx_cmp.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include +#include + +#if __HEXAGON_ARCH__ > 75 +#error "After v75, compiler will replace some FP HVX instructions." +#endif + +int err; +#include "hvx_misc.h" +#include "hex_test.h" + +#define MAX_TESTS_hf (MAX_VEC_SIZE_BYTES / 2) +#define MAX_TESTS_sf (MAX_VEC_SIZE_BYTES / 4) + +#define TRUE_MASK_sf 0xffffffff +#define TRUE_MASK_hf 0xffff + +static const char *comparisons[MAX_TESTS_sf][2]; +static HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; +static HVX_Vector buffers[2], true_vec, false_vec; +static int exp_index; + +#define ADD_TEST_CMP(TYPE, VAL1, VAL2, EXP) do { \ + ((MMVector *)&buffers[0])->TYPE[exp_index] = VAL1; \ + ((MMVector *)&buffers[1])->TYPE[exp_index] = VAL2; \ + expect[0].TYPE[exp_index] = EXP ? TRUE_MASK_##TYPE : 0; \ + comparisons[exp_index][0] = #VAL1; \ + comparisons[exp_index][1] = #VAL2; \ + assert(exp_index < MAX_TESTS_##TYPE); \ + exp_index++; \ +} while (0) + +#define TEST_CMP_GT(TYPE, VAL1, VAL2) do { \ + ADD_TEST_CMP(TYPE, VAL1, VAL2, true); \ + ADD_TEST_CMP(TYPE, VAL2, VAL1, false); \ +} while (0) + +#define PREP_TEST() do { \ + memset(&buffers, 0, sizeof(buffers)); \ + memset(expect, 0, sizeof(expect)); \ + exp_index = 0; \ +} while (0) + +#define CHECK(TYPE, TYPESZ) do { \ + HVX_VectorPred pred = Q6_Q_vcmp_gt_V##TYPE##V##TYPE(buffers[0], buffers[1]); \ + *hvx_output = Q6_V_vmux_QVV(pred, true_vec, false_vec); \ + for (int j = 0; j < MAX_VEC_SIZE_BYTES / TYPESZ; j++) { \ + if (output[0].TYPE[j] != expect[0].TYPE[j]) { \ + printf("ERROR: expected %s %s %s\n", comparisons[j][0], \ + (expect[0].TYPE[j] != 0 ? ">" : "<="), comparisons[j][1]); \ + err++; \ + } \ + } \ +} while (0) + +static void test_cmp_sf(void) +{ + /* + * General ordering for sf: + * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg + */ + + /* Test equality */ + PREP_TEST(); + ADD_TEST_CMP(sf, raw_sf(2.2), raw_sf(2.2), false); + ADD_TEST_CMP(sf, SF_SNaN, SF_SNaN, false); + CHECK(sf, 4); + + /* Common numbers */ + PREP_TEST(); + TEST_CMP_GT(sf, raw_sf(2.2), raw_sf(2.1)); + TEST_CMP_GT(sf, raw_sf(0), raw_sf(-2.2)); + CHECK(sf, 4); + + /* Infinity vs Infinity/NaN */ + PREP_TEST(); + TEST_CMP_GT(sf, SF_QNaN, SF_INF); + TEST_CMP_GT(sf, SF_SNaN, SF_INF); + TEST_CMP_GT(sf, SF_INF, SF_INF_neg); + TEST_CMP_GT(sf, SF_INF, SF_SNaN_neg); + TEST_CMP_GT(sf, SF_INF, SF_QNaN_neg); + TEST_CMP_GT(sf, SF_INF_neg, SF_SNaN_neg); + TEST_CMP_GT(sf, SF_INF_neg, SF_QNaN_neg); + TEST_CMP_GT(sf, SF_SNaN, SF_INF_neg); + TEST_CMP_GT(sf, SF_QNaN, SF_INF_neg); + CHECK(sf, 4); + + /* NaN vs NaN */ + PREP_TEST(); + TEST_CMP_GT(sf, SF_QNaN, SF_SNaN); + TEST_CMP_GT(sf, SF_SNaN, SF_SNaN_neg); + TEST_CMP_GT(sf, SF_SNaN_neg, SF_QNaN_neg); + CHECK(sf, 4); + + /* NaN vs non-NaN */ + PREP_TEST(); + TEST_CMP_GT(sf, SF_QNaN, SF_one); + TEST_CMP_GT(sf, SF_SNaN, SF_one); + TEST_CMP_GT(sf, SF_one, SF_QNaN_neg); + TEST_CMP_GT(sf, SF_one, SF_SNaN_neg); + CHECK(sf, 4); +} + +static void test_cmp_hf(void) +{ + /* + * General ordering for hf: + * QNaN > SNaN > +Inf > numbers > -Inf > QSNaN_neg > QNaN_neg + */ + + /* Test equality */ + PREP_TEST(); + ADD_TEST_CMP(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.2), false); + ADD_TEST_CMP(hf, HF_SNaN, HF_SNaN, false); + CHECK(hf, 2); + + /* Common numbers */ + PREP_TEST(); + TEST_CMP_GT(hf, raw_hf((_Float16)2.2), raw_hf((_Float16)2.1)); + TEST_CMP_GT(hf, raw_hf((_Float16)0), raw_hf((_Float16) - 2.2)); + CHECK(hf, 2); + + /* Infinity vs Infinity/NaN */ + PREP_TEST(); + TEST_CMP_GT(hf, HF_QNaN, HF_INF); + TEST_CMP_GT(hf, HF_SNaN, HF_INF); + TEST_CMP_GT(hf, HF_INF, HF_INF_neg); + TEST_CMP_GT(hf, HF_INF, HF_SNaN_neg); + TEST_CMP_GT(hf, HF_INF, HF_QNaN_neg); + TEST_CMP_GT(hf, HF_INF_neg, HF_SNaN_neg); + TEST_CMP_GT(hf, HF_INF_neg, HF_QNaN_neg); + TEST_CMP_GT(hf, HF_SNaN, HF_INF_neg); + TEST_CMP_GT(hf, HF_QNaN, HF_INF_neg); + CHECK(hf, 2); + + /* NaN vs NaN */ + PREP_TEST(); + TEST_CMP_GT(hf, HF_QNaN, HF_SNaN); + TEST_CMP_GT(hf, HF_SNaN, HF_SNaN_neg); + TEST_CMP_GT(hf, HF_SNaN_neg, HF_QNaN_neg); + CHECK(hf, 2); + + /* NaN vs non-NaN */ + PREP_TEST(); + TEST_CMP_GT(hf, HF_QNaN, HF_one); + TEST_CMP_GT(hf, HF_SNaN, HF_one); + TEST_CMP_GT(hf, HF_one, HF_QNaN_neg); + TEST_CMP_GT(hf, HF_one, HF_SNaN_neg); + CHECK(hf, 2); +} + +static void check_byte_pred(HVX_VectorPred pred, int byte_idx, uint8_t exp_mask, + int line) +{ + /* + * Note: ((uint8_t *)&pred)[N] returns the expanded value of bit N: + * 0xFF if bit is set, 0x00 if clear. + */ + for (int i = 0; i < 8; i++) { + int idx = byte_idx * 8 + i; + int val = ((uint8_t *)&pred)[idx]; + int exp = (exp_mask >> i) & 1 ? 0xff : 0x00; + if (exp != val) { + printf("ERROR line %d: pred bit %d is 0x%x, should be 0x%x\n", + line, idx, val, exp); + err++; + } + } +} + +#define CHECK_BYTE_PRED(PRED, BYTE, EXP) check_byte_pred(PRED, BYTE, EXP, __LINE__) + +static void test_cmp_variants(void) +{ + HVX_VectorPred pred; + + /* + * Setup: comparison result will have bits 4-7 set (0xF0 in pred byte 0) + * - sf[0]: SF_zero > SF_one = false -> bits 0-3 = 0 + * - sf[1]: SF_one > SF_zero = true -> bits 4-7 = 1 + */ + PREP_TEST(); + ADD_TEST_CMP(sf, SF_zero, SF_one, false); + ADD_TEST_CMP(sf, SF_one, SF_zero, true); + + /* greater and: 0xF0 & 0xF0 = 0xF0 */ + memset(&pred, 0xF0, sizeof(pred)); + pred = Q6_Q_vcmp_gtand_QVsfVsf(pred, buffers[0], buffers[1]); + CHECK_BYTE_PRED(pred, 0, 0xF0); + + /* greater or: 0x0F | 0xF0 = 0xFF */ + memset(&pred, 0x0F, sizeof(pred)); + pred = Q6_Q_vcmp_gtor_QVsfVsf(pred, buffers[0], buffers[1]); + CHECK_BYTE_PRED(pred, 0, 0xFF); + + /* greater xor: 0xFF ^ 0xF0 = 0x0F */ + memset(&pred, 0xFF, sizeof(pred)); + pred = Q6_Q_vcmp_gtxacc_QVsfVsf(pred, buffers[0], buffers[1]); + CHECK_BYTE_PRED(pred, 0, 0x0F); +} + +int main(void) +{ + memset(&true_vec, 0xff, sizeof(true_vec)); + memset(&false_vec, 0, sizeof(false_vec)); + + test_cmp_sf(); + test_cmp_hf(); + test_cmp_variants(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} diff --git a/tests/tcg/hexagon/hex_test.h b/tests/tcg/hexagon/hex_test.h index d5da8ad240..79d30ec61c 100644 --- a/tests/tcg/hexagon/hex_test.h +++ b/tests/tcg/hexagon/hex_test.h @@ -115,6 +115,7 @@ const uint16_t HF_INF = 0x7c00; const uint16_t HF_INF_neg = 0xfc00; const uint16_t HF_QNaN = 0x7e00; const uint16_t HF_SNaN = 0x7d00; +const uint16_t HF_SNaN_neg = 0xfd00; const uint16_t HF_QNaN_neg = 0xfe00; const uint16_t HF_zero = 0x0000; const uint16_t HF_zero_neg = 0x8000; From 2e555f5b44d1586517e44d47f73afa6062f48b93 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Thu, 16 Apr 2026 04:39:05 -0700 Subject: [PATCH 203/627] tests/hexagon: add tests for HVX bfloat Reviewed-by: Taylor Simpson Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Brian Cain Link: https://lore.kernel.org/qemu-devel/392114c4c16e6f7f2835a6513987aafea82b565c.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain --- tests/tcg/hexagon/fp_hvx.c | 41 +++++++++++++++++++++++++++ tests/tcg/hexagon/fp_hvx_cmp.c | 51 ++++++++++++++++++++++++++++++++++ tests/tcg/hexagon/fp_hvx_cvt.c | 31 +++++++++++++++++++++ tests/tcg/hexagon/hex_test.h | 13 +++++++++ tests/tcg/hexagon/hvx_misc.h | 30 ++++++++++++++++++++ 5 files changed, 166 insertions(+) diff --git a/tests/tcg/hexagon/fp_hvx.c b/tests/tcg/hexagon/fp_hvx.c index dee0781bd7..4543a0aa8c 100644 --- a/tests/tcg/hexagon/fp_hvx.c +++ b/tests/tcg/hexagon/fp_hvx.c @@ -29,6 +29,7 @@ int err; #define CHECK_NAN(A, DEF_NAN) (isnan(A) ? DEF_NAN : (A)) #define NAN_SF float_sf(0x7FFFFFFF) #define NAN_HF float_hf(0x7FFF) +#define NAN_BF float_hf(0x7FFF) /****************************************************************************** * Binary operations @@ -91,11 +92,43 @@ DEF_TEST_OP_2(vmpy, MULT_HF, hf, hf); #define MAX_HF(X, Y) MAX(X, Y, NAN_HF) #define MIN_SF(X, Y) MIN(X, Y, NAN_SF) #define MAX_SF(X, Y) MAX(X, Y, NAN_SF) +#define MIN_BF(X, Y) MIN(X, Y, NAN_BF) +#define MAX_BF(X, Y) MAX(X, Y, NAN_BF) DEF_TEST_OP_2(vfmin, MIN_SF, sf, sf); DEF_TEST_OP_2(vfmax, MAX_SF, sf, sf); DEF_TEST_OP_2(vfmin, MIN_HF, hf, hf); DEF_TEST_OP_2(vfmax, MAX_HF, hf, hf); +DEF_TEST_OP_2(vmin, MIN_BF, bf, bf); +DEF_TEST_OP_2(vmax, MAX_BF, bf, bf); + +#define DEF_TEST_OP_2_INTERLEAVED(vop, op, type_res, type_arg) \ + static void test_##vop##_##type_res##_##type_arg(void) \ + { \ + memset(expect, 0xff, sizeof(expect)); \ + memset(output, 0xff, sizeof(output)); \ + for (int i = 0; i < BUFSIZE / 2; i++) { \ + HVX_VectorPair *hvx_output = (HVX_VectorPair *)&output[2 * i]; \ + HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; \ + HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; \ + *hvx_output = \ + Q6_W##type_res##_##vop##_V##type_arg##V##type_arg(hvx_buffer0, \ + hvx_buffer1); \ + for (int j = 0; j < MAX_VEC_SIZE_BYTES / bytes_##type_res; j++) { \ + expect[2 * i].type_res[j] = \ + raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j]), \ + float_##type_arg(buffer1[i].type_arg[2 * j]))); \ + expect[2 * i + 1].type_res[j] = \ + raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j + 1]), \ + float_##type_arg(buffer1[i].type_arg[2 * j + 1]))); \ + } \ + } \ + check_output_##type_res(__LINE__, BUFSIZE); \ + } + +DEF_TEST_OP_2_INTERLEAVED(vadd, SUM_SF, sf, bf); +DEF_TEST_OP_2_INTERLEAVED(vsub, SUB_SF, sf, bf); +DEF_TEST_OP_2_INTERLEAVED(vmpy, MULT_SF, sf, bf); /****************************************************************************** * Other tests @@ -180,6 +213,14 @@ int main(void) test_vfmax_sf_sf(); test_vfmax_hf_hf(); + /* bfloat */ + init_buffers_bf(); + test_vmin_bf_bf(); + test_vmax_bf_bf(); + test_vadd_sf_bf(); + test_vsub_sf_bf(); + test_vmpy_sf_bf(); + puts(err ? "FAIL" : "PASS"); return err ? 1 : 0; } diff --git a/tests/tcg/hexagon/fp_hvx_cmp.c b/tests/tcg/hexagon/fp_hvx_cmp.c index 8068d1c3ee..63fb423941 100644 --- a/tests/tcg/hexagon/fp_hvx_cmp.c +++ b/tests/tcg/hexagon/fp_hvx_cmp.c @@ -22,9 +22,11 @@ int err; #define MAX_TESTS_hf (MAX_VEC_SIZE_BYTES / 2) #define MAX_TESTS_sf (MAX_VEC_SIZE_BYTES / 4) +#define MAX_TESTS_bf (MAX_VEC_SIZE_BYTES / 2) #define TRUE_MASK_sf 0xffffffff #define TRUE_MASK_hf 0xffff +#define TRUE_MASK_bf 0xffff static const char *comparisons[MAX_TESTS_sf][2]; static HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; @@ -160,6 +162,54 @@ static void test_cmp_hf(void) CHECK(hf, 2); } +static void test_cmp_bf(void) +{ + /* + * General ordering for bf: + * QNaN > SNaN > +Inf > numbers > -Inf > SNaN_neg > QNaN_neg + */ + + /* Test equality */ + PREP_TEST(); + ADD_TEST_CMP(bf, 0, 0, false); + ADD_TEST_CMP(bf, BF_SNaN, BF_SNaN, false); + CHECK(bf, 2); + + /* Common numbers */ + PREP_TEST(); + TEST_CMP_GT(bf, BF_two, BF_one); + TEST_CMP_GT(bf, BF_one, BF_zero); + CHECK(bf, 2); + + /* Infinity vs Infinity/NaN */ + PREP_TEST(); + TEST_CMP_GT(bf, BF_QNaN, BF_INF); + TEST_CMP_GT(bf, BF_SNaN, BF_INF); + TEST_CMP_GT(bf, BF_INF, BF_INF_neg); + TEST_CMP_GT(bf, BF_INF, BF_SNaN_neg); + TEST_CMP_GT(bf, BF_INF, BF_QNaN_neg); + TEST_CMP_GT(bf, BF_INF_neg, BF_SNaN_neg); + TEST_CMP_GT(bf, BF_INF_neg, BF_QNaN_neg); + TEST_CMP_GT(bf, BF_SNaN, BF_INF_neg); + TEST_CMP_GT(bf, BF_QNaN, BF_INF_neg); + CHECK(bf, 2); + + /* NaN vs NaN */ + PREP_TEST(); + TEST_CMP_GT(bf, BF_QNaN, BF_SNaN); + TEST_CMP_GT(bf, BF_SNaN, BF_SNaN_neg); + TEST_CMP_GT(bf, BF_SNaN_neg, BF_QNaN_neg); + CHECK(bf, 2); + + /* NaN vs non-NaN */ + PREP_TEST(); + TEST_CMP_GT(bf, BF_QNaN, BF_one); + TEST_CMP_GT(bf, BF_SNaN, BF_one); + TEST_CMP_GT(bf, BF_one, BF_QNaN_neg); + TEST_CMP_GT(bf, BF_one, BF_SNaN_neg); + CHECK(bf, 2); +} + static void check_byte_pred(HVX_VectorPred pred, int byte_idx, uint8_t exp_mask, int line) { @@ -217,6 +267,7 @@ int main(void) test_cmp_sf(); test_cmp_hf(); + test_cmp_bf(); test_cmp_variants(); puts(err ? "FAIL" : "PASS"); diff --git a/tests/tcg/hexagon/fp_hvx_cvt.c b/tests/tcg/hexagon/fp_hvx_cvt.c index b08eba92da..7196bc9a33 100644 --- a/tests/tcg/hexagon/fp_hvx_cvt.c +++ b/tests/tcg/hexagon/fp_hvx_cvt.c @@ -19,6 +19,8 @@ int err; #include "hvx_misc.h" #include "hex_test.h" +#define NAN_BF 0x7FFF + #define TEST_EXP(TO, FROM, VAL, EXP) do { \ ((MMVector *)&buffer)->FROM[index] = VAL; \ expect[0].TO[index] = EXP; \ @@ -172,6 +174,34 @@ DEF_TEST_VCONV(sf, w, { \ TEST_EXP(sf, w, 16777219, raw_sf((float)16777220)); /* rounds UP */ \ }) +#define TEST_EXP_BF(VAL, EXP) do { \ + ((MMVector *)&buffers[1])->sf[index] = VAL; \ + ((MMVector *)&buffers[0])->sf[index] = VAL; \ + expect[0].bf[2 * index] = EXP; \ + expect[0].bf[2 * index + 1] = EXP; \ + index++; \ +} while (0) + +static void test_vconv_bf_sf(void) +{ + HVX_Vector *hvx_output = (HVX_Vector *)&output[0]; + HVX_Vector buffers[2]; + int index = 0; + memset(&buffers, 0, sizeof(buffers)); + memset(expect, 0, sizeof(expect)); + + TEST_EXP_BF(SF_QNaN, NAN_BF); + TEST_EXP_BF(SF_SNaN, NAN_BF); + TEST_EXP_BF(SF_QNaN_neg, NAN_BF); + TEST_EXP_BF(SF_INF, BF_INF); + TEST_EXP_BF(SF_INF_neg, BF_INF_neg); + TEST_EXP_BF(SF_one, BF_one); + TEST_EXP_BF(SF_zero_neg, BF_zero_neg); + + *hvx_output = Q6_Vbf_vcvt_VsfVsf(buffers[0], buffers[1]); + check_output_hf(__LINE__, 1); +} + int main(void) { test_vcvt_uh_hf(); @@ -182,6 +212,7 @@ int main(void) test_vconv_sf_w(); test_vconv_h_hf(); test_vconv_hf_h(); + test_vconv_bf_sf(); puts(err ? "FAIL" : "PASS"); return err ? 1 : 0; diff --git a/tests/tcg/hexagon/hex_test.h b/tests/tcg/hexagon/hex_test.h index 79d30ec61c..f86e6e1a69 100644 --- a/tests/tcg/hexagon/hex_test.h +++ b/tests/tcg/hexagon/hex_test.h @@ -126,6 +126,19 @@ const uint16_t HF_small_neg = 0x8010; const uint16_t HF_any = 0x3c00; const uint16_t HF_neg_two = 0xc000; +const uint16_t BF_INF = 0x7f80; +const uint16_t BF_INF_neg = 0xff80; +const uint16_t BF_QNaN = 0x7fc0; +const uint16_t BF_SNaN = 0x7f81; +const uint16_t BF_QNaN_neg = 0xffc0; +const uint16_t BF_SNaN_neg = 0xff81; +const uint16_t BF_HEX_NaN = 0x7fff; +const uint16_t BF_zero = 0x0000; +const uint16_t BF_zero_neg = 0x8000; +const uint16_t BF_one = 0x3f80; +const uint16_t BF_two = 0x4000; +const uint16_t BF_four = 0x4080; + const uint32_t SF_INF = 0x7f800000; const uint32_t SF_INF_neg = 0xff800000; const uint32_t SF_QNaN = 0x7fc00000; diff --git a/tests/tcg/hexagon/hvx_misc.h b/tests/tcg/hexagon/hvx_misc.h index 43de20da6a..c21ea975c1 100644 --- a/tests/tcg/hexagon/hvx_misc.h +++ b/tests/tcg/hexagon/hvx_misc.h @@ -41,6 +41,7 @@ typedef union { uint16_t uh[MAX_VEC_SIZE_BYTES / 2]; uint16_t hf[MAX_VEC_SIZE_BYTES / 2]; /* convenience alias */ int16_t h[MAX_VEC_SIZE_BYTES / 2]; + uint16_t bf[MAX_VEC_SIZE_BYTES / 2]; uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; int8_t b[MAX_VEC_SIZE_BYTES / 1]; } MMVector; @@ -73,6 +74,7 @@ CHECK_OUTPUT_FUNC(uh, 2) CHECK_OUTPUT_FUNC(hf, 2) CHECK_OUTPUT_FUNC(ub, 1) CHECK_OUTPUT_FUNC(b, 1) +CHECK_OUTPUT_FUNC(bf, 2) static inline void init_buffers(void) { @@ -97,6 +99,12 @@ static const uint32_t FP_VALUES[] = { }; #define FP_VALUES_MAX ARRAY_SIZE(FP_VALUES) +static const uint16_t BF_VALUES[] = { + BF_INF, BF_INF_neg, BF_QNaN, BF_SNaN, BF_QNaN_neg, BF_SNaN_neg, + BF_HEX_NaN, BF_zero, BF_zero_neg, BF_one, BF_two, BF_four, +}; +#define BF_VALUES_MAX ARRAY_SIZE(BF_VALUES) + static inline void init_buffers_fp(void) { _Static_assert(BUFSIZE * (MAX_VEC_SIZE_BYTES / 4) > @@ -116,6 +124,25 @@ static inline void init_buffers_fp(void) } } +static inline void init_buffers_bf(void) +{ + _Static_assert(BUFSIZE * (MAX_VEC_SIZE_BYTES / 2) > + BF_VALUES_MAX * BF_VALUES_MAX, + "test arrays can't fit all BF_VALUES combinations"); + int counter1 = 0, counter2 = 0; + for (int i = 0; i < BUFSIZE; i++) { + for (int j = 0; j < MAX_VEC_SIZE_BYTES / 2; j++) { + buffer0[i].bf[j] = BF_VALUES[counter1]; + buffer1[i].bf[j] = BF_VALUES[counter2]; + counter2++; + if (counter2 == BF_VALUES_MAX) { + counter2 = 0; + counter1 = (counter1 + 1) % BF_VALUES_MAX; + } + } + } +} + #define VEC_OP1(ASM, EL, IN, OUT) \ asm("v2 = vmem(%0 + #0)\n\t" \ "v2" #EL " = " #ASM "(v2" #EL ")\n\t" \ @@ -212,10 +239,13 @@ static inline void test_##NAME(bool invert) \ #define float_sf(x) ({ typeof(x) _x = (x); *((float *)&(_x)); }) #define float_hf(x) ({ typeof(x) _x = (x); *((_Float16 *) &(_x)); }) +#define float_bf(x) ({ uint32_t _u = ((uint32_t)(x)) << 16; *((float *)&(_u)); }) #define raw_sf(x) ({ typeof(x) _x = (x); *((uint32_t *)&(_x)); }) #define raw_hf(x) ({ typeof(x) _x = (x); *((uint16_t *)&(_x)); }) +#define raw_bf(x) ({ typeof(x) _x = (x); (uint16_t)(*((uint32_t *)&(_x)) >> 16); }) #define float_hf_to_sf(x) ((float)x) #define bytes_hf 2 #define bytes_sf 4 +#define bytes_bf 2 #endif From 21e726d226e53896a0e6dcbb732b93bcea89115e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 204/627] target/arm: Implement FTMOPA (non-widening, FP32) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/helper-sme-defs.h | 2 ++ target/arm/tcg/sme.decode | 10 +++++++ target/arm/tcg/sme_helper.c | 49 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 26 +++++++++++++++++ 5 files changed, 92 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index fb5ed25ad0..6370c03e2a 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1590,6 +1590,11 @@ 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_sme_tmop(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, STMOP); +} + 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 7fc7129e54..8107eb40af 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -404,3 +404,5 @@ 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) + +DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 53e7e67feb..0250177d0d 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1131,3 +1131,13 @@ 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 + +# SME TMOP Sparse outer products + +&tmop zad zn zm zk idx +%tmop_zk 10:3 !function=expand_tmop_zk + +@tmop_o2 .... .... ... zm:5 ... ... .... idx:2 .. zad:2 \ + &tmop zn=%zn_ax2 zk=%tmop_zk + +FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 23bb816b6a..571b0add34 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -2636,6 +2636,49 @@ void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque, } } +/* + * Sparse outer product, non-widening. ESZ in {16, 32}. + */ +static void sme_tmop(void *vza, void *vzn, void *vzm, uint64_t *zk, + void *fn_opaque, uint32_t desc, MemOp esz, + void (*fn)(void *, void *, void *, void *)) +{ + intptr_t oprsz = simd_maxsz(desc); + intptr_t index = simd_data(desc); + intptr_t esize = 1 << esz; + intptr_t host_adj = HOST_BIG_ENDIAN ? 8 - esize : 0; + /* Base in bits for op3[index*:csize], csize = (VL * 2) / esize. */ + intptr_t ctrl_base = index * oprsz * 2; + /* Create a zero for use with the largest esz. */ + uint32_t zero = 0; + + for (intptr_t row = 0; row < oprsz; row += esize) { + void *vza_row = vza + tile_vslice_offset(row); + + for (intptr_t col = 0; col < oprsz; col += esize) { + void *e2 = vzm + (col ^ host_adj); + void *e3 = vza_row + (col ^ host_adj); + + /* + * Two control bits select one element: + * Zn[row], if [0] is set, + * Zn+1[row], if [1] is set, + * 0, otherwise. + * Compute the address of that element. + */ + void *e1 = &zero; + uint64_t this_ctrl = extractn(zk, (ctrl_base + 2 * col) >> esz, 2); + if (this_ctrl) { + e1 = vzn + (row ^ host_adj); + if (!(this_ctrl & 1)) { + e1 += sizeof(ARMVectorReg); + } + } + fn(e3, e1, e2, fn_opaque); + } + } +} + static void inner_fmop4a_hh(void *vd, void *vn, void *vm, void *vinfo) { float16 *d = vd, *n = vn, *m = vm; @@ -2692,6 +2735,12 @@ void HELPER(sme_fmop4a_ss)(void *vza, void *vzn, void *vzm, sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float32), inner_fmop4a_ss); } +void HELPER(sme_ftmopa_ss)(void *vza, void *vzn, void *vzm, void *vzk, + float_status *fpst, uint32_t desc) +{ + sme_tmop(vza, vzn, vzm, vzk, fpst, desc, MO_32, inner_fmop4a_ss); +} + static void inner_fmop4s_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 0794794e3d..3cfd52dca4 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -31,6 +31,12 @@ * Include the generated decoder. */ +static int expand_tmop_zk(DisasContext *s, int x) +{ + /* Pseudocode for 1:K:1:zk. */ + return 0b10100 | ((x & 4) << 1) | (x & 3); +} + #include "decode-sme.c.inc" static bool sme2_zt0_enabled_check(DisasContext *s) @@ -2132,3 +2138,23 @@ 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) + +static bool do_tmop_fp(DisasContext *s, arg_tmop *a, MemOp esz, + int e_fpst, gen_helper_gvec_4_ptr *fn) +{ + if (sme_smza_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, a->idx); + 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); + TCGv_ptr zk = vec_full_reg_ptr(s, a->zm); + TCGv_ptr fpst = (e_fpst >= 0 ? fpstatus_ptr(e_fpst) : tcg_env); + + fn(za, zn, zm, zk, fpst, tcg_constant_i32(desc)); + } + return true; +} + +TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp, + a, MO_32, FPST_ZA, gen_helper_sme_ftmopa_ss) From 76bc7dc82d2c37295aca07757e7623d3bfc650a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 205/627] target/arm: Implement FTMOPA (non-widening, FP16) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/helper-sme-defs.h | 1 + target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 6 ++++++ target/arm/tcg/translate-sme.c | 2 ++ 5 files changed, 17 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 6370c03e2a..4190398a1d 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1842,6 +1842,11 @@ 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); } +static inline bool isar_feature_aa64_sme_tmop_f16f16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_tmop(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 8107eb40af..84707e6c71 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -405,4 +405,5 @@ 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) +DEF_HELPER_FLAGS_6(sme_ftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 0250177d0d..16ed3ca391 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1137,7 +1137,10 @@ USMOP4_dh 1010 0001 110. ...0 0000 00.. ..0. 1... @mop4_o3 &tmop zad zn zm zk idx %tmop_zk 10:3 !function=expand_tmop_zk +@tmop_o1 .... .... ... zm:5 ... ... .... idx:2 ... zad:1 \ + &tmop zn=%zn_ax2 zk=%tmop_zk @tmop_o2 .... .... ... zm:5 ... ... .... idx:2 .. zad:2 \ &tmop zn=%zn_ax2 zk=%tmop_zk +FTMOPA_hh 1000 0001 010 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 571b0add34..49fd3d07e4 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -2693,6 +2693,12 @@ void HELPER(sme_fmop4a_hh)(void *vza, void *vzn, void *vzm, sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(float16), inner_fmop4a_hh); } +void HELPER(sme_ftmopa_hh)(void *vza, void *vzn, void *vzm, void *vzk, + float_status *fpst, uint32_t desc) +{ + sme_tmop(vza, vzn, vzm, vzk, fpst, desc, MO_16, inner_fmop4a_hh); +} + static void inner_fmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) { float16 *d = vd, *n = vn, *m = vm; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 3cfd52dca4..5ad59ab99b 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2156,5 +2156,7 @@ static bool do_tmop_fp(DisasContext *s, arg_tmop *a, MemOp esz, return true; } +TRANS_FEAT(FTMOPA_hh, aa64_sme_tmop_f16f16, do_tmop_fp, + a, MO_16, FPST_ZA_F16, gen_helper_sme_ftmopa_hh) TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp, a, MO_32, FPST_ZA, gen_helper_sme_ftmopa_ss) From aa8965de49e66cc4c04dbd99274d108418687a8e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 206/627] target/arm: Implement BFTMOPA (non-widening) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/helper-sme-defs.h | 1 + target/arm/tcg/sme.decode | 1 + target/arm/tcg/sme_helper.c | 6 ++++++ target/arm/tcg/translate-sme.c | 2 ++ 5 files changed, 15 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 4190398a1d..d3bf0746cb 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1842,6 +1842,11 @@ 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); } +static inline bool isar_feature_aa64_sme_tmop_b16b16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_tmop(id) && isar_feature_aa64_sme_b16b16(id); +} + static inline bool isar_feature_aa64_sme_tmop_f16f16(const ARMISARegisters *id) { return isar_feature_aa64_sme_tmop(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 84707e6c71..224de45294 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -405,5 +405,6 @@ 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) +DEF_HELPER_FLAGS_6(sme_bftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 16ed3ca391..f0f9b3f61d 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1142,5 +1142,6 @@ USMOP4_dh 1010 0001 110. ...0 0000 00.. ..0. 1... @mop4_o3 @tmop_o2 .... .... ... zm:5 ... ... .... idx:2 .. zad:2 \ &tmop zn=%zn_ax2 zk=%tmop_zk +BFTMOPA_hh 1000 0001 011 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_hh 1000 0001 010 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 49fd3d07e4..e57c56d5f2 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -2831,6 +2831,12 @@ void HELPER(sme_bfmop4a_hh)(void *vza, void *vzn, void *vzm, sme_mop4(vza, vzn, vzm, fpst, desc, sizeof(bfloat16), inner_bfmop4a_hh); } +void HELPER(sme_bftmopa_hh)(void *vza, void *vzn, void *vzm, void *vzk, + float_status *fpst, uint32_t desc) +{ + sme_tmop(vza, vzn, vzm, vzk, fpst, desc, MO_16, inner_bfmop4a_hh); +} + static void inner_bfmop4s_hh(void *vd, void *vn, void *vm, void *vinfo) { bfloat16 *d = vd, *n = vn, *m = vm; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 5ad59ab99b..04e1550c05 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2156,6 +2156,8 @@ static bool do_tmop_fp(DisasContext *s, arg_tmop *a, MemOp esz, return true; } +TRANS_FEAT(BFTMOPA_hh, aa64_sme_tmop_b16b16, do_tmop_fp, + a, MO_16, FPST_ZA, gen_helper_sme_bftmopa_hh) TRANS_FEAT(FTMOPA_hh, aa64_sme_tmop_f16f16, do_tmop_fp, a, MO_16, FPST_ZA_F16, gen_helper_sme_ftmopa_hh) TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp, From cfe1e6503a0b828b7237d5c16c3b7f59f5bd7449 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 207/627] target/arm: Implement BFTMOPA (widening) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/helper-sme-defs.h | 2 ++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/sme_helper.c | 54 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 3 ++ 4 files changed, 61 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index 224de45294..f05b53f412 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -408,3 +408,5 @@ DEF_HELPER_FLAGS_4(sme_usmop4s_dh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_6(sme_bftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(sme_bftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index f0f9b3f61d..49af8fd19e 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1145,3 +1145,5 @@ USMOP4_dh 1010 0001 110. ...0 0000 00.. ..0. 1... @mop4_o3 BFTMOPA_hh 1000 0001 011 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_hh 1000 0001 010 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 + +BFTMOPA_sh 1000 0001 010 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index e57c56d5f2..91447d9c0e 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -2679,6 +2679,50 @@ static void sme_tmop(void *vza, void *vzn, void *vzm, uint64_t *zk, } } +/* + * Sparse outer product, widening 2-way, 16 to 32-bit. + */ +static void sme_tmop_2way_sh(uint32_t *za, uint16_t *zn0, uint32_t *zm, + uint64_t *zk, void *fn_opaque, uint32_t desc, + void (*fn)(void *, void *, void *, void *)) +{ + intptr_t oprsz = simd_maxsz(desc); + intptr_t dim = oprsz >> MO_32; + intptr_t index = simd_data(desc); + intptr_t ctrl_base = (index * oprsz) >> 1; + uint16_t *zn1 = zn0 + sizeof(ARMVectorReg) / 2; + + for (intptr_t row = 0; row < dim; row++) { + uint32_t *za_row = za + tile_vslice_offset(row); + + for (intptr_t col = 0; col < dim; col++) { + uint32_t *e2 = zm + H4(col); + uint32_t *e3 = za_row + H4(col); + uint32_t e1 = 0; + + /* + * Four control bits select two elements. The two elements + * may be non-contiguous, so assemble them locally into e1. + * Pseudo-code has a double loop running forward, with a + * test for (i < 2) to limit construction to 2 elements. + * Easier to run a single loop backward, shifting extra + * elements off the top of our uint32_t. + */ + uint64_t this_ctrl = extractn(zk, ctrl_base + col * 4, 4); + for (int i = 3; i >= 0; i--) { + if (this_ctrl & (1 << i)) { + bool e = i & 1; + bool r = i & 2; + uint16_t *p = (r ? zn1 : zn0) + H2(2 * row + e); + e1 = (e1 << 16) | *p; + } + } + + fn(e3, &e1, e2, fn_opaque); + } + } +} + static void inner_fmop4a_hh(void *vd, void *vn, void *vm, void *vinfo) { float16 *d = vd, *n = vn, *m = vm; @@ -2893,6 +2937,16 @@ void HELPER(sme_bfmop4a_sh)(void *vza, void *vzn, void *vzm, : inner_bfmop4a_sh); } +void HELPER(sme_bftmopa_sh)(void *vza, void *vzn, void *vzm, void *vzk, + CPUArchState *env, uint32_t desc) +{ + float_status fpst; + + sme_tmop_2way_sh(vza, vzn, vzm, vzk, &fpst, desc, + 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; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 04e1550c05..66bba48d99 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2162,3 +2162,6 @@ TRANS_FEAT(FTMOPA_hh, aa64_sme_tmop_f16f16, do_tmop_fp, a, MO_16, FPST_ZA_F16, gen_helper_sme_ftmopa_hh) TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp, a, MO_32, FPST_ZA, gen_helper_sme_ftmopa_ss) + +TRANS_FEAT(BFTMOPA_sh, aa64_sme_tmop, do_tmop_fp, + a, MO_32, FPST_ENV, gen_helper_sme_bftmopa_sh) From f6a2d780f1489de6f3453e0c0ef70ae9813a412c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 208/627] target/arm: Implement FTMOPA (widening, 2-way, FP16 to FP32) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/helper-sme-defs.h | 1 + target/arm/tcg/sme.decode | 1 + target/arm/tcg/sme_helper.c | 6 ++++++ target/arm/tcg/translate-sme.c | 2 ++ 4 files changed, 10 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index f05b53f412..8a959447b2 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -410,3 +410,4 @@ DEF_HELPER_FLAGS_6(sme_ftmopa_hh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fps DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_6(sme_bftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(sme_ftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 49af8fd19e..5c453ea729 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1147,3 +1147,4 @@ FTMOPA_hh 1000 0001 010 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 BFTMOPA_sh 1000 0001 010 ..... 000 ... .... .. 00 .. @tmop_o2 +FTMOPA_sh 1000 0001 011 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 91447d9c0e..c2b7c23d6c 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -3020,6 +3020,12 @@ void HELPER(sme_fmop4a_sh)(void *vza, void *vzn, void *vzm, sme_mop4(vza, vzn, vzm, env, desc, sizeof(float32), inner_fmop4a_sh); } +void HELPER(sme_ftmopa_sh)(void *vza, void *vzn, void *vzm, void *vzk, + CPUArchState *env, uint32_t desc) +{ + sme_tmop_2way_sh(vza, vzn, vzm, vzk, env, desc, inner_fmop4a_sh); +} + static void inner_fmop4s_sh(void *vd, void *vn, void *vm, void *vinfo) { float32 *d = vd; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 66bba48d99..8a55b79727 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2165,3 +2165,5 @@ TRANS_FEAT(FTMOPA_ss, aa64_sme_tmop, do_tmop_fp, TRANS_FEAT(BFTMOPA_sh, aa64_sme_tmop, do_tmop_fp, a, MO_32, FPST_ENV, gen_helper_sme_bftmopa_sh) +TRANS_FEAT(FTMOPA_sh, aa64_sme_tmop, do_tmop_fp, + a, MO_32, FPST_ENV, gen_helper_sme_ftmopa_sh) From e921da8b98f0be99edf973e3d623d79ac2cd3705 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 209/627] target/arm: Implement FTMOPA (widening, 2-way, FP8 to FP16) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/fp8_helper.c | 43 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/translate-sme.c | 12 +++++++++ 5 files changed, 64 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index d3bf0746cb..1ab6c90b8c 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1852,6 +1852,11 @@ static inline bool isar_feature_aa64_sme_tmop_f16f16(const ARMISARegisters *id) return isar_feature_aa64_sme_tmop(id) && isar_feature_aa64_sme_f16f16(id); } +static inline bool isar_feature_aa64_sme_tmop_f8f16(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_tmop(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 4b046f5f26..305cafdc9b 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -1005,3 +1005,46 @@ void HELPER(sme_fmop4a_hb)(void *vza, void *vzn, void *vzm, FP8MulContext ctx = fp8_mul_start(env, 0xf); sme_mop4(vza, vzn, vzm, &ctx, desc, sizeof(float16), inner_fmop4a_hb); } + +void HELPER(sme_ftmopa_hb)(void *vza, void *vzn, void *vzm, void *vzk, + CPUArchState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + intptr_t oprsz = simd_maxsz(desc); + intptr_t dim = oprsz >> MO_16; + intptr_t index = simd_data(desc); + intptr_t ctrl_base = (index * oprsz) >> 1; + uint8_t *zn0 = vzn, *zn1 = vzn + sizeof(ARMVectorReg); + uint16_t *za = vza, *zm = vzm; + uint64_t *zk = vzk; + + for (intptr_t row = 0; row < dim; row++) { + uint16_t *za_row = za + tile_vslice_offset(row); + + for (intptr_t col = 0; col < dim; col++) { + uint16_t e2 = zm[H2(col)]; + uint16_t *e3 = za_row + H2(col); + uint16_t e1 = 0; + + /* + * Four control bits select two elements. The two elements + * may be non-contiguous, so assemble them locally into e1. + * Pseudo-code has a double loop running forward, with a + * test for (i < 2) to limit construction to 2 elements. + * Easier to run a single loop backward, shifting extra + * elements off the top of our uint16_t. + */ + uint64_t this_ctrl = extractn(zk, ctrl_base + col * 4, 4); + for (int i = 3; i >= 0; i--) { + if (this_ctrl & (1 << i)) { + bool e = i & 1; + bool r = i & 2; + uint8_t *p = (r ? zn1 : zn0) + H1(2 * row + e); + e1 = (e1 << 8) | *p; + } + } + + *e3 = f8dotadd_h(e1, e2, 2, *e3, &ctx); + } + } +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index dedbd8541c..13be62aa15 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -47,3 +47,5 @@ DEF_HELPER_FLAGS_5(sme_fvdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, 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) + +DEF_HELPER_FLAGS_6(sme_ftmopa_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 5c453ea729..da6f4686d3 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1148,3 +1148,5 @@ FTMOPA_ss 1000 0000 010 ..... 000 ... .... .. 00 .. @tmop_o2 BFTMOPA_sh 1000 0001 010 ..... 000 ... .... .. 00 .. @tmop_o2 FTMOPA_sh 1000 0001 011 ..... 000 ... .... .. 00 .. @tmop_o2 + +FTMOPA_hb 1000 0000 011 ..... 000 ... .... .. 100 . @tmop_o1 diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 8a55b79727..206f078bfb 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2167,3 +2167,15 @@ TRANS_FEAT(BFTMOPA_sh, aa64_sme_tmop, do_tmop_fp, a, MO_32, FPST_ENV, gen_helper_sme_bftmopa_sh) TRANS_FEAT(FTMOPA_sh, aa64_sme_tmop, do_tmop_fp, a, MO_32, FPST_ENV, gen_helper_sme_ftmopa_sh) + +static bool do_tmop_fp8(DisasContext *s, arg_tmop *a, MemOp esz, + gen_helper_gvec_4_ptr *fn) +{ + if (!fpmr_access_check(s)) { + return true; + } + return do_tmop_fp(s, a, esz, FPST_ENV, fn); +} + +TRANS_FEAT(FTMOPA_hb, aa64_sme_tmop_f8f16, do_tmop_fp8, + a, MO_16, gen_helper_sme_ftmopa_hb) From 1c7b4f9db3ed05a09431e3e1363b4af47c28df2b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 210/627] target/arm: Implement FTMOPA (widening, 4-way, FP8 to FP32) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/fp8_helper.c | 7 +++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/sme.decode | 1 + target/arm/tcg/sme_helper.c | 44 ++++++++++++++++++++++++++++++++ target/arm/tcg/translate-sme.c | 2 ++ target/arm/tcg/vec_internal.h | 7 +++++ 7 files changed, 67 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 1ab6c90b8c..280ead6f9c 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -1857,6 +1857,11 @@ static inline bool isar_feature_aa64_sme_tmop_f8f16(const ARMISARegisters *id) return isar_feature_aa64_sme_tmop(id) && isar_feature_aa64_sme_f8f16(id); } +static inline bool isar_feature_aa64_sme_tmop_f8f32(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme_tmop(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 305cafdc9b..0be811e71b 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -1048,3 +1048,10 @@ void HELPER(sme_ftmopa_hb)(void *vza, void *vzn, void *vzm, void *vzk, } } } + +void HELPER(sme_ftmopa_sb)(void *vza, void *vzn, void *vzm, void *vzk, + CPUArchState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + sme_tmop_4way_sb(vza, vzn, vzm, vzk, &ctx, desc, inner_fmop4a_sb); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index 13be62aa15..e2cf2ba8c7 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -49,3 +49,4 @@ 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) DEF_HELPER_FLAGS_6(sme_ftmopa_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(sme_ftmopa_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index da6f4686d3..eab1f7e8fb 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1150,3 +1150,4 @@ BFTMOPA_sh 1000 0001 010 ..... 000 ... .... .. 00 .. @tmop_o2 FTMOPA_sh 1000 0001 011 ..... 000 ... .... .. 00 .. @tmop_o2 FTMOPA_hb 1000 0000 011 ..... 000 ... .... .. 100 . @tmop_o1 +FTMOPA_sb 1000 0000 011 ..... 000 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index c2b7c23d6c..3d7aefac5b 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -2723,6 +2723,50 @@ static void sme_tmop_2way_sh(uint32_t *za, uint16_t *zn0, uint32_t *zm, } } +void sme_tmop_4way_sb(uint32_t *za, uint8_t *zn0, uint32_t *zm, + uint64_t *zk, void *fn_opaque, uint32_t desc, + void (*fn)(void *, void *, void *, void *)) +{ + intptr_t oprsz = simd_maxsz(desc); + intptr_t dim = oprsz >> MO_32; + intptr_t index = simd_data(desc); + intptr_t ctrl_base = (index * oprsz) >> 1; + uint8_t *zn1 = zn0 + sizeof(ARMVectorReg); + + for (intptr_t row = 0; row < dim; row++) { + uint32_t *za_row = za + tile_vslice_offset(row); + + for (intptr_t col = 0; col < dim; col++) { + uint32_t *e2 = zm + H4(col); + uint32_t *e3 = za_row + H4(col); + uint16_t e1l = 0, e1h = 0; + uint32_t e1; + + /* + * Eight control bits select two elements from each row. + * The elements may be non-contiguous, so assemble them + * locally into e1. + * Pseudo-code has a triple loop running forward, with a + * test for (i < 2) to limit construction to 2 elements. + * Easier to run a single loop backward, shifting extra + * elements off the top. + */ + uint64_t this_ctrl = extractn(zk, ctrl_base + col * 8, 8); + for (int e = 3; e >= 0; e--) { + if (this_ctrl & (0x01 << e)) { + e1l = (e1l << 8) | zn0[H1(4 * row + e)]; + } + if (this_ctrl & (0x10 << e)) { + e1h = (e1h << 8) | zn1[H1(4 * row + e)]; + } + } + e1 = (e1h << 16) | e1l; + + fn(e3, &e1, e2, fn_opaque); + } + } +} + static void inner_fmop4a_hh(void *vd, void *vn, void *vm, void *vinfo) { float16 *d = vd, *n = vn, *m = vm; diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index 206f078bfb..ceed864da8 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2179,3 +2179,5 @@ static bool do_tmop_fp8(DisasContext *s, arg_tmop *a, MemOp esz, TRANS_FEAT(FTMOPA_hb, aa64_sme_tmop_f8f16, do_tmop_fp8, a, MO_16, gen_helper_sme_ftmopa_hb) +TRANS_FEAT(FTMOPA_sb, aa64_sme_tmop_f8f32, do_tmop_fp8, + a, MO_32, gen_helper_sme_ftmopa_sb) diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index 038a2a3439..8f6d8a984b 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -555,4 +555,11 @@ void sme_mop4(void *vza, void *vzn, void *vzm, void *fn_opaque, uint32_t desc, size_t esize, void (*fn)(void *, void *, void *, void *)); +/* + * Perform SME sparse outer product, 4-way, 8 to 32-bit. + */ +void sme_tmop_4way_sb(uint32_t *za, uint8_t *zn0, uint32_t *zm, + uint64_t *zk, void *fn_opaque, uint32_t desc, + void (*fn)(void *, void *, void *, void *)); + #endif /* TARGET_ARM_VEC_INTERNAL_H */ From 695e4e87a437e1d2d50755b0ed906cc54898813c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 211/627] target/arm: Implement [SU]TMOPA (2-way) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/helper-sme-defs.h | 3 +++ target/arm/tcg/sme.decode | 3 +++ target/arm/tcg/sme_helper.c | 12 ++++++++++++ target/arm/tcg/translate-sme.c | 21 +++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index 8a959447b2..1de72b7472 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -411,3 +411,6 @@ DEF_HELPER_FLAGS_6(sme_ftmopa_ss, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, fps DEF_HELPER_FLAGS_6(sme_bftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_6(sme_ftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(sme_stmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_utmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index eab1f7e8fb..08036c60c0 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1151,3 +1151,6 @@ FTMOPA_sh 1000 0001 011 ..... 000 ... .... .. 00 .. @tmop_o2 FTMOPA_hb 1000 0000 011 ..... 000 ... .... .. 100 . @tmop_o1 FTMOPA_sb 1000 0000 011 ..... 000 ... .... .. 00 .. @tmop_o2 + +STMOPA_sh 1000 0000 010 ..... 100 ... .... .. 10 .. @tmop_o2 +UTMOPA_sh 1000 0001 010 ..... 100 ... .... .. 10 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 3d7aefac5b..951cbbf58e 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -3123,6 +3123,18 @@ IMOP4_2WAY(umop4s_sh, -, int32_t, uint16_t, uint16_t) #undef IMOP4_2WAY +#define ITMOP_2WAY(TNAME, MNAME) \ +void HELPER(sme_##TNAME)(void *vza, void *vzn, void *vzm, \ + void *vzk, uint32_t desc) \ +{ \ + sme_tmop_2way_sh(vza, vzn, vzm, vzk, NULL, desc, inner_##MNAME); \ +} + +ITMOP_2WAY(stmopa_sh, smop4a_sh) +ITMOP_2WAY(utmopa_sh, umop4a_sh) + +#undef ITMOP_2WAY + #define IMOP4_4WAY(NAME, OP, TYPED, TYPEN, TYPEM) \ static void inner_##NAME(void *vd, void *vn, void *vm, void *vinfo) \ { \ diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index ceed864da8..abdf98a40c 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2181,3 +2181,24 @@ TRANS_FEAT(FTMOPA_hb, aa64_sme_tmop_f8f16, do_tmop_fp8, a, MO_16, gen_helper_sme_ftmopa_hb) TRANS_FEAT(FTMOPA_sb, aa64_sme_tmop_f8f32, do_tmop_fp8, a, MO_32, gen_helper_sme_ftmopa_sb) + +static bool do_tmop_int(DisasContext *s, arg_tmop *a, MemOp esz, + gen_helper_gvec_4 *fn) +{ + if (sme_smza_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + uint32_t desc = simd_desc(svl, svl, a->idx); + 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); + TCGv_ptr zk = vec_full_reg_ptr(s, a->zm); + + fn(za, zn, zm, zk, tcg_constant_i32(desc)); + } + return true; +} + +TRANS_FEAT(STMOPA_sh, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_stmopa_sh) +TRANS_FEAT(UTMOPA_sh, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_utmopa_sh) From e56b670ea130b05c6abd3218357996a14c88338d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 212/627] target/arm: Implement {S,SU,US,U}TMOPA (4-way) Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/helper-sme-defs.h | 5 +++++ target/arm/tcg/sme.decode | 5 +++++ target/arm/tcg/sme_helper.c | 14 ++++++++++++++ target/arm/tcg/translate-sme.c | 9 +++++++++ 4 files changed, 33 insertions(+) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index 1de72b7472..b8cb643367 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -414,3 +414,8 @@ DEF_HELPER_FLAGS_6(sme_ftmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env DEF_HELPER_FLAGS_5(sme_stmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sme_utmopa_sh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(sme_stmopa_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_sutmopa_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_utmopa_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sme_ustmopa_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index 08036c60c0..e8176fffdb 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -1154,3 +1154,8 @@ FTMOPA_sb 1000 0000 011 ..... 000 ... .... .. 00 .. @tmop_o2 STMOPA_sh 1000 0000 010 ..... 100 ... .... .. 10 .. @tmop_o2 UTMOPA_sh 1000 0001 010 ..... 100 ... .... .. 10 .. @tmop_o2 + +STMOPA_sb 1000 0000 010 ..... 100 ... .... .. 00 .. @tmop_o2 +SUTMOPA_sb 1000 0000 011 ..... 100 ... .... .. 00 .. @tmop_o2 +USTMOPA_sb 1000 0001 010 ..... 100 ... .... .. 00 .. @tmop_o2 +UTMOPA_sb 1000 0001 011 ..... 100 ... .... .. 00 .. @tmop_o2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 951cbbf58e..9de95428d2 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -3168,3 +3168,17 @@ IMOP4_4WAY(usmop4a_dh, +, int64_t, uint16_t, int16_t) IMOP4_4WAY(usmop4s_dh, -, int64_t, uint16_t, int16_t) #undef IMOP4_4WAY + +#define ITMOP_4WAY(TNAME, MNAME) \ +void HELPER(sme_##TNAME)(void *vza, void *vzn, void *vzm, \ + void *vzk, uint32_t desc) \ +{ \ + sme_tmop_4way_sb(vza, vzn, vzm, vzk, NULL, desc, inner_##MNAME); \ +} + +ITMOP_4WAY(stmopa_sb, smop4a_sb) +ITMOP_4WAY(utmopa_sb, umop4a_sb) +ITMOP_4WAY(sutmopa_sb, sumop4a_sb) +ITMOP_4WAY(ustmopa_sb, usmop4a_sb) + +#undef ITMOP_4WAY diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index abdf98a40c..768b76f01e 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -2202,3 +2202,12 @@ TRANS_FEAT(STMOPA_sh, aa64_sme_tmop, do_tmop_int, a, MO_32, gen_helper_sme_stmopa_sh) TRANS_FEAT(UTMOPA_sh, aa64_sme_tmop, do_tmop_int, a, MO_32, gen_helper_sme_utmopa_sh) + +TRANS_FEAT(STMOPA_sb, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_stmopa_sb) +TRANS_FEAT(SUTMOPA_sb, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_sutmopa_sb) +TRANS_FEAT(USTMOPA_sb, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_ustmopa_sb) +TRANS_FEAT(UTMOPA_sb, aa64_sme_tmop, do_tmop_int, + a, MO_32, gen_helper_sme_utmopa_sb) From 8ae365bdc8395e54fe0e137143858b505409d82a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 213/627] target/arm: Enable FEAT_SME_TMOP for -cpu max Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260713230244.70174-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 9930974a50..cc42db9e0b 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -188,6 +188,7 @@ 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_SME_MOP4 (Quarter-tile outer product instructions) +- FEAT_SME_TMOP (Structured sparsity 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 64e25a04e3..48be49580a 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -177,6 +177,7 @@ abi_ulong get_elf_hwcap(CPUState *cs) 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); + GET_FEATURE_ID(aa64_sme_tmop, ARM_HWCAP_A64_SME_STMOP); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 8a3ebf6321..24f34947ec 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1384,8 +1384,9 @@ 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, SMOP4, 1); /* FEAT_SME_MOP4 */ + t = FIELD_DP64(t, ID_AA64SMFR0, STMOP, 1); /* FEAT_SME_TMOP */ + 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 */ From 33a71a68c6e137c80c9f6a7370d546404ed38513 Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 214/627] hw/arm: Add Axiado SoC AX3000 This patch adds new model for Axiado SoC AX3000 which supports 4 Cortex-A53 ARM64 CPUs Arm Generic Interrupt Controller v3 4 Cadence UARTs Signed-off-by: Kuan-Jui Chiu Message-id: 20260713073033.3883619-2-kchiu@axiado.com Reviewed-by: Peter Maydell [PMM: Kconfig for the SoC shouldn't depend on ARM] Signed-off-by: Peter Maydell --- MAINTAINERS | 7 ++ hw/arm/Kconfig | 6 ++ hw/arm/ax3000-soc.c | 182 ++++++++++++++++++++++++++++++++++++ hw/arm/meson.build | 3 + include/hw/arm/ax3000-soc.h | 68 ++++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 hw/arm/ax3000-soc.c create mode 100644 include/hw/arm/ax3000-soc.h diff --git a/MAINTAINERS b/MAINTAINERS index 4628793dde..fce65e370f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1300,6 +1300,13 @@ M: Manos Pitsidianakis S: Maintained F: rust/hw/char/pl011/ +Axiado SoCs and EVKs +M: Kuan-Jui Chiu +L: qemu-arm@nongnu.org +S: Maintained +F: hw/arm/ax3000*.c +F: include/hw/arm/ax3000*.h + AVR Machines ------------- diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 82e0bc2e70..2ed2c2c6e8 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -725,3 +725,9 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config AXIADO_SOC + bool + select ARM_GIC + select CADENCE # UART + select UNIMP diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c new file mode 100644 index 0000000000..b528f8af53 --- /dev/null +++ b/hw/arm/ax3000-soc.c @@ -0,0 +1,182 @@ +/* + * Axiado SoC AX3000 + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "system/address-spaces.h" +#include "hw/arm/bsa.h" +#include "hw/arm/ax3000-soc.h" +#include "hw/misc/unimp.h" +#include "system/system.h" +#include "qobject/qlist.h" +#include "qom/object.h" +#include "hw/core/boards.h" + +static void ax3000_init(Object *obj) +{ + Ax3000SoCState *s = AX3000_SOC(obj); + Ax3000SoCClass *sc = AX3000_SOC_GET_CLASS(s); + + for (int i = 0; i < sc->num_cpus; i++) { + g_autofree char *name = g_strdup_printf("cpu%d", i); + object_initialize_child(obj, name, &s->cpu[i], + ARM_CPU_TYPE_NAME("cortex-a53")); + } + + object_initialize_child(obj, "gic", &s->gic, gicv3_class_name()); + + for (int i = 0; i < AX3000_NUM_UARTS; i++) { + g_autofree char *name = g_strdup_printf("uart%d", i); + object_initialize_child(obj, name, &s->uart[i], TYPE_CADENCE_UART); + } +} + +static void ax3000_realize(DeviceState *dev, Error **errp) +{ + Ax3000SoCState *s = AX3000_SOC(dev); + Ax3000SoCClass *sc = AX3000_SOC_GET_CLASS(s); + SysBusDevice *gic_sbd = SYS_BUS_DEVICE(&s->gic); + DeviceState *gic_dev = DEVICE(&s->gic); + QList *redist_region_count; + SysBusDevice *sdhci0_sbd; + DeviceState *card; + + /* CPUs */ + for (int i = 0; i < sc->num_cpus; i++) { + object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000, + &error_abort); + + if (object_property_find(OBJECT(&s->cpu[i]), "has_el3")) { + object_property_set_bool(OBJECT(&s->cpu[i]), "has_el3", + false, &error_abort); + } + + if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) { + return; + } + } + + /* GIC */ + qdev_prop_set_uint32(gic_dev, "num-cpu", sc->num_cpus); + qdev_prop_set_uint32(gic_dev, "num-irq", + AX3000_NUM_IRQS + GIC_INTERNAL); + + redist_region_count = qlist_new(); + qlist_append_int(redist_region_count, sc->num_cpus); + qdev_prop_set_array(gic_dev, "redist-region-count", redist_region_count); + + if (!sysbus_realize(gic_sbd, errp)) { + return; + } + + sysbus_mmio_map(gic_sbd, 0, AX3000_GIC_DIST_BASE); + sysbus_mmio_map(gic_sbd, 1, AX3000_GIC_REDIST_BASE); + + /* + * Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs. + */ + 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 + }; + + /* + * 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 (int i = 0; i < sc->num_cpus; i++) { + DeviceState *cpu_dev = DEVICE(&s->cpu[i]); + int intidbase = AX3000_NUM_IRQS + i * GIC_INTERNAL; + qemu_irq irq; + + for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) { + irq = qdev_get_gpio_in(gic_dev, intidbase + timer_irqs[j]); + qdev_connect_gpio_out(cpu_dev, j, irq); + } + + irq = qdev_get_gpio_in(gic_dev, intidbase + ARCH_GIC_MAINT_IRQ); + qdev_connect_gpio_out_named(cpu_dev, "gicv3-maintenance-interrupt", + 0, irq); + + sysbus_connect_irq(gic_sbd, i, + qdev_get_gpio_in(cpu_dev, ARM_CPU_IRQ)); + sysbus_connect_irq(gic_sbd, i + sc->num_cpus, + qdev_get_gpio_in(cpu_dev, ARM_CPU_FIQ)); + sysbus_connect_irq(gic_sbd, i + 2 * sc->num_cpus, + qdev_get_gpio_in(cpu_dev, ARM_CPU_VIRQ)); + sysbus_connect_irq(gic_sbd, i + 3 * sc->num_cpus, + qdev_get_gpio_in(cpu_dev, ARM_CPU_VFIQ)); + } + + /* DRAM */ + const struct { + hwaddr addr; + size_t size; + const char *name; + } dram_table[] = { + { AX3000_DRAM0_BASE, AX3000_DRAM0_SIZE, "dram0" }, + { AX3000_DRAM1_BASE, AX3000_DRAM1_SIZE, "dram1" } + }; + + for (int i = 0; i < AX3000_NUM_BANKS; i++) { + memory_region_init_ram(&s->dram[i], OBJECT(s), dram_table[i].name, + dram_table[i].size, &error_fatal); + memory_region_add_subregion(get_system_memory(), dram_table[i].addr, + &s->dram[i]); + } + + /* UARTs */ + const struct { + hwaddr addr; + unsigned int irq; + } serial_table[] = { + { AX3000_UART0_BASE, AX3000_UART0_IRQ }, + { AX3000_UART1_BASE, AX3000_UART1_IRQ }, + { AX3000_UART2_BASE, AX3000_UART2_IRQ }, + { AX3000_UART3_BASE, AX3000_UART3_IRQ } + }; + + for (int i = 0; i < AX3000_NUM_UARTS; i++) { + 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(gic_dev, serial_table[i].irq)); + } + + /* Timer control */ + create_unimplemented_device("ax3000.timerctrl", AX3000_TIMER_CTRL, 32); +} + +static void ax3000_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + Ax3000SoCClass *sc = AX3000_SOC_CLASS(oc); + + dc->desc = "Axiado SoC AX3000"; + dc->realize = ax3000_realize; + sc->num_cpus = AX3000_NUM_CPUS; +} + +static const TypeInfo axiado_soc_types[] = { + { + .name = TYPE_AX3000_SOC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Ax3000SoCState), + .instance_init = ax3000_init, + .class_init = ax3000_class_init, + } +}; + +DEFINE_TYPES(axiado_soc_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 4233a800be..0254b82df1 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -110,6 +110,9 @@ arm_common_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) +arm_common_ss.add(when: ['CONFIG_AXIADO_SOC', 'TARGET_AARCH64'], if_true: files( + 'ax3000-soc.c')) + arm_common_ss.add(files('boot.c')) hw_common_arch += {'arm': arm_common_ss} diff --git a/include/hw/arm/ax3000-soc.h b/include/hw/arm/ax3000-soc.h new file mode 100644 index 0000000000..b984d7a8ec --- /dev/null +++ b/include/hw/arm/ax3000-soc.h @@ -0,0 +1,68 @@ +/* + * Axiado SoC AX3000 + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef AXIADO_AX3000_H +#define AXIADO_AX3000_H + +#include "cpu.h" +#include "hw/intc/arm_gicv3_common.h" +#include "hw/char/cadence_uart.h" +#include "hw/core/sysbus.h" +#include "qemu/units.h" + +#define TYPE_AX3000_SOC "ax3000" +OBJECT_DECLARE_TYPE(Ax3000SoCState, Ax3000SoCClass, AX3000_SOC) + +#define AX3000_DRAM0_BASE 0x3C000000 +#define AX3000_DRAM0_SIZE (1088 * MiB) +#define AX3000_DRAM1_BASE 0x400000000 +#define AX3000_DRAM1_SIZE (2 * GiB) + +#define AX3000_GIC_DIST_BASE 0x80300000 +#define AX3000_GIC_DIST_SIZE (64 * KiB) +#define AX3000_GIC_REDIST_BASE 0x80380000 +#define AX3000_GIC_REDIST_SIZE (512 * KiB) + +#define AX3000_UART0_BASE 0x80520000 +#define AX3000_UART1_BASE 0x805a0000 +#define AX3000_UART2_BASE 0x80620000 +#define AX3000_UART3_BASE 0x80520800 + +#define AX3000_TIMER_CTRL 0x8A020000 +#define AX3000_PLL_BASE 0x80000000 + +enum Ax3000Configuration { + AX3000_NUM_CPUS = 4, + AX3000_NUM_IRQS = 224, + AX3000_NUM_BANKS = 2, + AX3000_NUM_UARTS = 4, +}; + +typedef struct Ax3000SoCState { + SysBusDevice parent; + + ARMCPU cpu[AX3000_NUM_CPUS]; + GICv3State gic; + MemoryRegion dram[AX3000_NUM_BANKS]; + CadenceUARTState uart[AX3000_NUM_UARTS]; +} Ax3000SoCState; + +typedef struct Ax3000SoCClass { + SysBusDeviceClass parent; + + uint32_t num_cpus; +} Ax3000SoCClass; + +enum Ax3000Irqs { + AX3000_UART0_IRQ = 112, + AX3000_UART1_IRQ = 113, + AX3000_UART2_IRQ = 114, + AX3000_UART3_IRQ = 170, +}; + +#endif /* AXIADO_AX3000_H */ From 38b52563758ec3fe5df2ba8efa86b155ad79649d Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 215/627] hw/misc: Add AX3000 clock control This patch adds a new model for Axiado AX3000 clock control which supports to read ID and status Signed-off-by: Kuan-Jui Chiu Message-id: 20260713073033.3883619-3-kchiu@axiado.com [PMM: use HWADDR_PRIx] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/Kconfig | 3 ++ hw/misc/axiado_clk.c | 79 ++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 3 ++ include/hw/misc/axiado_clk.h | 26 ++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 hw/misc/axiado_clk.c create mode 100644 include/hw/misc/axiado_clk.h diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 1543ee6653..b8860dd3e7 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -257,4 +257,7 @@ config XLNX_VERSAL_TRNG config XLNX_ZYNQ_DDRC bool +config AXIADO_CLK + bool + source macio/Kconfig diff --git a/hw/misc/axiado_clk.c b/hw/misc/axiado_clk.c new file mode 100644 index 0000000000..090beb38b5 --- /dev/null +++ b/hw/misc/axiado_clk.c @@ -0,0 +1,79 @@ +/* + * Axiado Clock Control + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/misc/axiado_clk.h" +#include "qemu/log.h" + +#define CLKRST_CPU_PLL_POSTDIV_OFFSET 0x0C +#define CLKRST_CPU_PLL_STS_OFFSET 0x14 + +static uint64_t pll_read(void *opaque, hwaddr offset, unsigned size) +{ + switch (offset) { + case CLKRST_CPU_PLL_POSTDIV_OFFSET: + return 0x20891b; + case CLKRST_CPU_PLL_STS_OFFSET: + return 0x01; + default: + qemu_log_mask(LOG_UNIMP, + "Register 0x%" HWADDR_PRIx " not implemented\n", offset); + break; + } + return 0x00; +} + +static void pll_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, + "Register 0x%" HWADDR_PRIx " not implemented\n", offset); +} + +static const MemoryRegionOps pll_ops = { + .read = pll_read, + .write = pll_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +static void ax3000_clk_init(Object *obj) +{ + Ax3000ClkState *s = AX3000_CLK(obj); + + memory_region_init_io(&s->pll_ctrl, obj, &pll_ops, s, + TYPE_AX3000_CLK, AX3000_CLK_PLL_CTRL_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->pll_ctrl); +} + +static void ax3000_clk_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "Axiado AX3000 Clock Control"; +} + +static const TypeInfo ax3000_clk_info = { + .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_AX3000_CLK, + .instance_size = sizeof(Ax3000ClkState), + .instance_init = ax3000_clk_init, + .class_init = ax3000_clk_class_init, +}; + +static void axiado_clk_register_type(void) +{ + type_register_static(&ax3000_clk_info); +} +type_init(axiado_clk_register_type); diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 23265f6035..e86d9ad6b3 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -1,4 +1,5 @@ system_ss.add(when: 'CONFIG_APPLESMC', if_true: files('applesmc.c')) + system_ss.add(when: 'CONFIG_EDU', if_true: files('edu.c')) system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c')) system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c')) @@ -168,3 +169,5 @@ system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) + +system_ss.add(when: 'CONFIG_AXIADO_CLK', if_true: files('axiado_clk.c')) diff --git a/include/hw/misc/axiado_clk.h b/include/hw/misc/axiado_clk.h new file mode 100644 index 0000000000..6e12a509d7 --- /dev/null +++ b/include/hw/misc/axiado_clk.h @@ -0,0 +1,26 @@ +/* + * Axiado AX3000 Clock Control + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef AXIADO_AX3000_CLK_H +#define AXIADO_AX3000_CLK_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define TYPE_AX3000_CLK "ax3000-clk" +OBJECT_DECLARE_SIMPLE_TYPE(Ax3000ClkState, AX3000_CLK) + +#define AX3000_CLK_PLL_CTRL_SIZE 0x1000 + +typedef struct Ax3000ClkState { + SysBusDevice parent; + + MemoryRegion pll_ctrl; +} Ax3000ClkState; + +#endif /* AXIADO_AX3000_CLK_H */ From 406738e50861b2deb19414a73b8a9079565523d8 Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 216/627] hw/arm: ax3000-soc: Enable Ax3000 clock control Signed-off-by: Kuan-Jui Chiu Message-id: 20260713073033.3883619-4-kchiu@axiado.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/ax3000-soc.c | 8 ++++++++ include/hw/arm/ax3000-soc.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 2ed2c2c6e8..69161a439c 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -730,4 +730,5 @@ config AXIADO_SOC bool select ARM_GIC select CADENCE # UART + select AXIADO_CLK select UNIMP diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c index b528f8af53..aaeae11074 100644 --- a/hw/arm/ax3000-soc.c +++ b/hw/arm/ax3000-soc.c @@ -33,6 +33,8 @@ static void ax3000_init(Object *obj) g_autofree char *name = g_strdup_printf("uart%d", i); object_initialize_child(obj, name, &s->uart[i], TYPE_CADENCE_UART); } + + object_initialize_child(obj, "clk", &s->ax3000_clk, TYPE_AX3000_CLK); } static void ax3000_realize(DeviceState *dev, Error **errp) @@ -157,6 +159,12 @@ static void ax3000_realize(DeviceState *dev, Error **errp) /* Timer control */ create_unimplemented_device("ax3000.timerctrl", AX3000_TIMER_CTRL, 32); + + /* Clock control */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ax3000_clk), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ax3000_clk), 0, AX3000_PLL_BASE); } static void ax3000_class_init(ObjectClass *oc, const void *data) diff --git a/include/hw/arm/ax3000-soc.h b/include/hw/arm/ax3000-soc.h index b984d7a8ec..329aa4e769 100644 --- a/include/hw/arm/ax3000-soc.h +++ b/include/hw/arm/ax3000-soc.h @@ -12,6 +12,7 @@ #include "cpu.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/char/cadence_uart.h" +#include "hw/misc/axiado_clk.h" #include "hw/core/sysbus.h" #include "qemu/units.h" @@ -49,6 +50,7 @@ typedef struct Ax3000SoCState { ARMCPU cpu[AX3000_NUM_CPUS]; GICv3State gic; MemoryRegion dram[AX3000_NUM_BANKS]; + Ax3000ClkState ax3000_clk; CadenceUARTState uart[AX3000_NUM_UARTS]; } Ax3000SoCState; From 8c55a630c5b91fd7292fb11ee0e69a5914b66487 Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 217/627] hw/sd: Add Axiado SD host controller with eMMC PHY This patch add a new model for Axiado SD host controller which is compatible with SDHCI 3.0 spec This device model also includes a eMMC PHY which helps to control SD/eMMC Signed-off-by: Kuan-Jui Chiu Reviewed-by: Peter Maydell Message-id: 20260713073033.3883619-5-kchiu@axiado.com [PMM: Use HWADDR_PRIx] Signed-off-by: Peter Maydell --- MAINTAINERS | 2 + hw/sd/Kconfig | 4 ++ hw/sd/axiado_sdhci.c | 119 +++++++++++++++++++++++++++++++++++ hw/sd/meson.build | 1 + include/hw/sd/axiado_sdhci.h | 21 +++++++ 5 files changed, 147 insertions(+) create mode 100644 hw/sd/axiado_sdhci.c create mode 100644 include/hw/sd/axiado_sdhci.h diff --git a/MAINTAINERS b/MAINTAINERS index fce65e370f..7a02fed0d6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1305,7 +1305,9 @@ M: Kuan-Jui Chiu L: qemu-arm@nongnu.org S: Maintained F: hw/arm/ax3000*.c +F: hw/*/axiado*.c F: include/hw/arm/ax3000*.h +F: include/hw/*/axiado*.h AVR Machines ------------- diff --git a/hw/sd/Kconfig b/hw/sd/Kconfig index 633b9afec9..c69bf24f8d 100644 --- a/hw/sd/Kconfig +++ b/hw/sd/Kconfig @@ -23,3 +23,7 @@ config SDHCI_PCI config CADENCE_SDHCI bool select SDHCI + +config AXIADO_SDHCI + bool + select SDHCI diff --git a/hw/sd/axiado_sdhci.c b/hw/sd/axiado_sdhci.c new file mode 100644 index 0000000000..2e88bffdd1 --- /dev/null +++ b/hw/sd/axiado_sdhci.c @@ -0,0 +1,119 @@ +/* + * Axiado SD Host Controller with embedded PHY + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/sd/axiado_sdhci.h" +#include "sdhci-internal.h" +#include "qapi/error.h" +#include "hw/core/qdev-properties.h" +#include "qemu/log.h" + +#define EMMC_PHY_ID 0x00 +#define EMMC_PHY_STATUS 0x50 + +#define DLL_RDY (1u << 0) +#define CAL_DONE (1u << 6) + +static uint64_t emmc_phy_read(void *opaque, hwaddr offset, unsigned size) +{ + uint32_t val = 0x00; + + switch (offset) { + case EMMC_PHY_ID: + val = 0x3dff6870; + break; + case EMMC_PHY_STATUS: + val = DLL_RDY | CAL_DONE; + break; + default: + qemu_log_mask(LOG_UNIMP, + "Register 0x%" HWADDR_PRIx " not implemented\n", offset); + break; + } + + return val; +} + +static void emmc_phy_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + qemu_log_mask(LOG_UNIMP, + "Register 0x%" HWADDR_PRIx " not implemented\n", offset); +} + +static const MemoryRegionOps emmc_phy_ops = { + .read = emmc_phy_read, + .write = emmc_phy_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +static void axiado_sdhci_realize(DeviceState *dev, Error **errp) +{ + AxiadoSDHCIState *s = AXIADO_SDHCI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SysBusDevice *sdhci_sbd; + + qdev_prop_set_uint64(DEVICE(&s->sdhci), "capareg", 0x216737eed0b0); + qdev_prop_set_uint64(DEVICE(&s->sdhci), "sd-spec-version", 3); + + sdhci_sbd = SYS_BUS_DEVICE(&s->sdhci); + if (!sysbus_realize(sdhci_sbd, errp)) { + return; + } + + sysbus_init_mmio(sbd, sysbus_mmio_get_region(sdhci_sbd, 0)); + + /* Propagate IRQ from SDHCI and SD bus */ + sysbus_pass_irq(sbd, sdhci_sbd); + s->sd_bus = qdev_get_child_bus(DEVICE(sdhci_sbd), "sd-bus"); + + /* Initialize eMMC PHY MMIO */ + memory_region_init_io(&s->emmc_phy, OBJECT(s), &emmc_phy_ops, s, + "axiado.emmc-phy", 0x1000); + + sysbus_init_mmio(sbd, &s->emmc_phy); +} + +static void axiado_sdhci_instance_init(Object *obj) +{ + AxiadoSDHCIState *s = AXIADO_SDHCI(obj); + + object_initialize_child(OBJECT(s), "sdhci", &s->sdhci, + TYPE_SYSBUS_SDHCI); +} + +static void axiado_sdhci_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = axiado_sdhci_realize; + dc->desc = "Axiado SD Host Controller with eMMC PHY"; +} + +static const TypeInfo axiado_sdhci_info = { + .name = TYPE_AXIADO_SDHCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AxiadoSDHCIState), + .instance_init = axiado_sdhci_instance_init, + .class_init = axiado_sdhci_class_init, +}; + +static void axiado_sdhci_register_types(void) +{ + type_register_static(&axiado_sdhci_info); +} + +type_init(axiado_sdhci_register_types); diff --git a/hw/sd/meson.build b/hw/sd/meson.build index b43d45bc56..ebf09e30a4 100644 --- a/hw/sd/meson.build +++ b/hw/sd/meson.build @@ -10,3 +10,4 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c')) system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c')) system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_sdhci.c')) system_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c')) +system_ss.add(when: 'CONFIG_AXIADO_SDHCI', if_true: files('axiado_sdhci.c')) diff --git a/include/hw/sd/axiado_sdhci.h b/include/hw/sd/axiado_sdhci.h new file mode 100644 index 0000000000..85afebad93 --- /dev/null +++ b/include/hw/sd/axiado_sdhci.h @@ -0,0 +1,21 @@ +/* + * Axiado SD Host Controller + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "hw/sd/sdhci.h" +#include "qom/object.h" + +#define TYPE_AXIADO_SDHCI "axiado-sdhci" +OBJECT_DECLARE_SIMPLE_TYPE(AxiadoSDHCIState, AXIADO_SDHCI) + +typedef struct AxiadoSDHCIState { + SysBusDevice parent; + + SDHCIState sdhci; + MemoryRegion emmc_phy; + BusState *sd_bus; +} AxiadoSDHCIState; From 2019f4e0ddb3f7c0d3246042ee7535b7348792ce Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 218/627] hw/arm: ax3000-soc: Enable Axiado SD host controller Enable SD host controller into Axiado AX3000 SoC to load kernel and rootfs from eMMC. Signed-off-by: Kuan-Jui Chiu Reviewed-by: Peter Maydell Message-id: 20260713073033.3883619-6-kchiu@axiado.com Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/ax3000-soc.c | 22 ++++++++++++++++++++++ include/hw/arm/ax3000-soc.h | 7 +++++++ 3 files changed, 30 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 69161a439c..32e7d83339 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -731,4 +731,5 @@ config AXIADO_SOC select ARM_GIC select CADENCE # UART select AXIADO_CLK + select AXIADO_SDHCI select UNIMP diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c index aaeae11074..23903b081b 100644 --- a/hw/arm/ax3000-soc.c +++ b/hw/arm/ax3000-soc.c @@ -35,6 +35,7 @@ static void ax3000_init(Object *obj) } object_initialize_child(obj, "clk", &s->ax3000_clk, TYPE_AX3000_CLK); + object_initialize_child(obj, "sdhci0", &s->sdhci0, TYPE_AXIADO_SDHCI); } static void ax3000_realize(DeviceState *dev, Error **errp) @@ -46,6 +47,7 @@ static void ax3000_realize(DeviceState *dev, Error **errp) QList *redist_region_count; SysBusDevice *sdhci0_sbd; DeviceState *card; + DriveInfo *dinfo; /* CPUs */ for (int i = 0; i < sc->num_cpus; i++) { @@ -165,6 +167,26 @@ static void ax3000_realize(DeviceState *dev, Error **errp) return; } sysbus_mmio_map(SYS_BUS_DEVICE(&s->ax3000_clk), 0, AX3000_PLL_BASE); + + /* SDHCI */ + sdhci0_sbd = SYS_BUS_DEVICE(&s->sdhci0); + if (!sysbus_realize(sdhci0_sbd, errp)) { + return; + } + + sysbus_mmio_map(sdhci0_sbd, 0, AX3000_SDHCI0_BASE); + sysbus_mmio_map(sdhci0_sbd, 1, AX3000_EMMC_PHY_BASE); + sysbus_connect_irq(sdhci0_sbd, 0, + qdev_get_gpio_in(gic_dev, AX3000_SDHCI0_IRQ)); + + dinfo = drive_get(IF_SD, 0, 0); + if (dinfo) { + card = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive_err(card, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); + qdev_realize_and_unref(card, s->sdhci0.sd_bus, &error_fatal); + } } static void ax3000_class_init(ObjectClass *oc, const void *data) diff --git a/include/hw/arm/ax3000-soc.h b/include/hw/arm/ax3000-soc.h index 329aa4e769..52b47aa829 100644 --- a/include/hw/arm/ax3000-soc.h +++ b/include/hw/arm/ax3000-soc.h @@ -13,6 +13,7 @@ #include "hw/intc/arm_gicv3_common.h" #include "hw/char/cadence_uart.h" #include "hw/misc/axiado_clk.h" +#include "hw/sd/axiado_sdhci.h" #include "hw/core/sysbus.h" #include "qemu/units.h" @@ -34,6 +35,9 @@ OBJECT_DECLARE_TYPE(Ax3000SoCState, Ax3000SoCClass, AX3000_SOC) #define AX3000_UART2_BASE 0x80620000 #define AX3000_UART3_BASE 0x80520800 +#define AX3000_SDHCI0_BASE 0x86000000 +#define AX3000_EMMC_PHY_BASE 0x80801C00 + #define AX3000_TIMER_CTRL 0x8A020000 #define AX3000_PLL_BASE 0x80000000 @@ -52,6 +56,7 @@ typedef struct Ax3000SoCState { MemoryRegion dram[AX3000_NUM_BANKS]; Ax3000ClkState ax3000_clk; CadenceUARTState uart[AX3000_NUM_UARTS]; + AxiadoSDHCIState sdhci0; } Ax3000SoCState; typedef struct Ax3000SoCClass { @@ -65,6 +70,8 @@ enum Ax3000Irqs { AX3000_UART1_IRQ = 113, AX3000_UART2_IRQ = 114, AX3000_UART3_IRQ = 170, + + AX3000_SDHCI0_IRQ = 123, }; #endif /* AXIADO_AX3000_H */ From 4e5205339fc4b5e56ed4d97d4a504bdee779fb8f Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 219/627] hw/arm: Add Axiado EVK SCM3003 Add EVK axiado-scm3003 built with AX3000 SoC Signed-off-by: Kuan-Jui Chiu Message-id: 20260713073033.3883619-7-kchiu@axiado.com Reviewed-by: Peter Maydell [PMM: KConfig for the board has to depend on TCG && ARM] Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 6 ++++ hw/arm/ax3000-boards.c | 56 ++++++++++++++++++++++++++++++++++ hw/arm/ax3000-evk.c | 27 ++++++++++++++++ hw/arm/meson.build | 3 ++ include/hw/arm/ax3000-boards.h | 28 +++++++++++++++++ 5 files changed, 120 insertions(+) create mode 100644 hw/arm/ax3000-boards.c create mode 100644 hw/arm/ax3000-evk.c create mode 100644 include/hw/arm/ax3000-boards.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 32e7d83339..d16b3d2f47 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -733,3 +733,9 @@ config AXIADO_SOC select AXIADO_CLK select AXIADO_SDHCI select UNIMP + +config AXIADO_EVK + bool + default y + depends on TCG && ARM + select AXIADO_SOC diff --git a/hw/arm/ax3000-boards.c b/hw/arm/ax3000-boards.c new file mode 100644 index 0000000000..4b8deec15c --- /dev/null +++ b/hw/arm/ax3000-boards.c @@ -0,0 +1,56 @@ +/* + * Axiado Boards + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/arm/ax3000-boards.h" +#include "hw/arm/boot.h" +#include "hw/arm/machines-qom.h" +#include "qemu/error-report.h" +#include "qom/object.h" + +static struct arm_boot_info ax3000_binfo = { + .loader_start = AX3000_DRAM0_BASE, + .board_id = -1, +}; + +static void ax3000_machine_init(MachineState *machine) +{ + Ax3000MachineState *ams = AX3000_MACHINE(machine); + + ams->soc = AX3000_SOC(object_new(TYPE_AX3000_SOC)); + object_property_add_child(OBJECT(machine), "soc", OBJECT(ams->soc)); + sysbus_realize_and_unref(SYS_BUS_DEVICE(ams->soc), &error_fatal); + + ax3000_binfo.ram_size = machine->ram_size; + arm_load_kernel(&ams->soc->cpu[0], machine, &ax3000_binfo); +} + +static void ax3000_machine_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = ax3000_machine_init; + mc->default_cpus = AX3000_NUM_CPUS; + mc->min_cpus = AX3000_NUM_CPUS; + mc->max_cpus = AX3000_NUM_CPUS; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"); +} + +static const TypeInfo ax3000_machine_types[] = { + { + .name = TYPE_AX3000_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(Ax3000MachineState), + .class_size = sizeof(Ax3000MachineClass), + .class_init = ax3000_machine_class_init, + .interfaces = aarch64_machine_interfaces, + .abstract = true, + } +}; + +DEFINE_TYPES(ax3000_machine_types) diff --git a/hw/arm/ax3000-evk.c b/hw/arm/ax3000-evk.c new file mode 100644 index 0000000000..a170848871 --- /dev/null +++ b/hw/arm/ax3000-evk.c @@ -0,0 +1,27 @@ +/* + * Axiado Evaluation Kit Emulation + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/arm/ax3000-boards.h" + +static void axiado_scm3003_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "Axiado SCM3003 EVK Board"; +} + +static const TypeInfo ax3000_evk_types[] = { + { + .name = MACHINE_TYPE_NAME("axiado-scm3003"), + .parent = TYPE_AX3000_MACHINE, + .class_init = axiado_scm3003_class_init, + } +}; + +DEFINE_TYPES(ax3000_evk_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 0254b82df1..8ee5307a91 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -112,6 +112,9 @@ arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) arm_common_ss.add(when: ['CONFIG_AXIADO_SOC', 'TARGET_AARCH64'], if_true: files( 'ax3000-soc.c')) +arm_common_ss.add(when: ['CONFIG_AXIADO_EVK', 'TARGET_AARCH64'], if_true: files( + 'ax3000-boards.c', + 'ax3000-evk.c')) arm_common_ss.add(files('boot.c')) diff --git a/include/hw/arm/ax3000-boards.h b/include/hw/arm/ax3000-boards.h new file mode 100644 index 0000000000..4a632661e1 --- /dev/null +++ b/include/hw/arm/ax3000-boards.h @@ -0,0 +1,28 @@ +/* + * Axiado Boards + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef AXIADO_BOARD_H +#define AXIADO_BOARD_H + +#include "hw/core/boards.h" +#include "hw/arm/ax3000-soc.h" + +#define TYPE_AX3000_MACHINE MACHINE_TYPE_NAME("ax3000") +OBJECT_DECLARE_TYPE(Ax3000MachineState, Ax3000MachineClass, AX3000_MACHINE) + +typedef struct Ax3000MachineState { + MachineState parent; + + Ax3000SoCState *soc; +} Ax3000MachineState; + +typedef struct Ax3000MachineClass { + MachineClass parent; + +} Ax3000MachineClass; +#endif From cc57a945feb0906af6b56591c790f60bfd65945c Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 220/627] hw/gpio: Add Cadence GPIO controller This patch add a new model for Cadence GPIO controller which supports 32 pins and interrupts for level-triggered/edge-triggered type on input pins. Also define new trace functions for analysis purpose and new configuration to enable this model. Signed-off-by: Kuan-Jui Chiu Message-id: 20260713073033.3883619-8-kchiu@axiado.com [PMM: drop unnecessary and marker comments] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/gpio/Kconfig | 3 + hw/gpio/cadence_gpio.c | 292 +++++++++++++++++++++++++++++++++ hw/gpio/meson.build | 1 + hw/gpio/trace-events | 5 + include/hw/gpio/cadence_gpio.h | 53 ++++++ 5 files changed, 354 insertions(+) create mode 100644 hw/gpio/cadence_gpio.c create mode 100644 include/hw/gpio/cadence_gpio.h diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig index a209294c20..fcc7c70bd5 100644 --- a/hw/gpio/Kconfig +++ b/hw/gpio/Kconfig @@ -30,3 +30,6 @@ config PCF8574 config ZAURUS_SCOOP bool + +config CADENCE_GPIO + bool diff --git a/hw/gpio/cadence_gpio.c b/hw/gpio/cadence_gpio.c new file mode 100644 index 0000000000..ce8256b381 --- /dev/null +++ b/hw/gpio/cadence_gpio.c @@ -0,0 +1,292 @@ +/* + * Cadence GPIO emulation. + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/gpio/cadence_gpio.h" +#include "hw/core/irq.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "trace.h" + +static void cdns_gpio_update_irq(CadenceGPIOState *s) +{ + qemu_set_irq(s->irq, s->isr ? 1 : 0); +} + +static void cdns_gpio_update_isr_with_inpvr(CadenceGPIOState *s, uint32_t new) +{ + uint32_t new_isr = 0; + uint32_t any_edges, rising_edges, falling_edges, deassert_mask; + + /* + * If ITR is set, this is level triggered: + * set corresponding ISR bits when IVR matches new inpvr value. + */ + new_isr |= s->itr & ~(s->ivr ^ new); + + /* + * If ITR is not set, this is edge-triggered: + * If IOAR bit is set, trigger on any edge; + * otherwise trigger on rising edge if IVR is set, + * trigger on falling edge if IVR bit is 0. + */ + any_edges = s->ioar & (s->inpvr ^ new); + rising_edges = s->ivr & ~s->inpvr & new; + falling_edges = ~s->ivr & s->inpvr & ~new; + new_isr |= ~s->itr & (any_edges | rising_edges | falling_edges); + + /* + * In bypass mode or if this isn't an input pin, the corresponding ISR + * bit is forced to zero. + */ + deassert_mask = s->bmr | ~s->dmr | s->imr; + + new_isr &= ~deassert_mask; + s->isr = new_isr; + + cdns_gpio_update_irq(s); +} + +static void cdns_gpio_update_isr(CadenceGPIOState *s) +{ + cdns_gpio_update_isr_with_inpvr(s, s->inpvr); +} + +static void cdns_gpio_set(void *opaque, int line, int level) +{ + CadenceGPIOState *s = CADENCE_GPIO(opaque); + uint32_t new_inpvr = deposit32(s->inpvr, line, 1, level ? 1 : 0); + + trace_cdns_gpio_set(DEVICE(s)->canonical_path, line, level); + + cdns_gpio_update_isr_with_inpvr(s, new_inpvr); + + /* Sync INPVR with new value */ + s->inpvr = new_inpvr; +} + +static inline void cdns_gpio_update_output_irq(CadenceGPIOState *s) +{ + uint32_t is_output = ~s->bmr & ~s->dmr & s->oer; + + for (int i = 0; i < CDNS_GPIO_NUM; i++) { + if (extract32(is_output, i, 1)) { + /* Forward the output value to corresponding irq */ + qemu_set_irq(s->output[i], extract32(s->ovr, i, 1)); + } + } +} + +static uint64_t cdns_gpio_read(void *opaque, hwaddr offset, unsigned size) +{ + CadenceGPIOState *s = CADENCE_GPIO(opaque); + uint32_t reg_value = 0x0; + + switch (offset) { + case CDNS_GPIO_BYPASS_MODE: + reg_value = s->bmr; + break; + + case CDNS_GPIO_DIRECTION_MODE: + reg_value = s->dmr; + break; + + case CDNS_GPIO_OUTPUT_EN: + reg_value = s->oer; + break; + + case CDNS_GPIO_OUTPUT_VALUE: + reg_value = s->ovr; + break; + + case CDNS_GPIO_INPUT_VALUE: + reg_value = s->inpvr; + break; + + case CDNS_GPIO_IRQ_MASK: + reg_value = s->imr; + break; + + case CDNS_GPIO_IRQ_STATUS: + reg_value = s->isr; + break; + + case CDNS_GPIO_IRQ_TYPE: + reg_value = s->itr; + break; + + case CDNS_GPIO_IRQ_VALUE: + reg_value = s->ivr; + break; + + case CDNS_GPIO_IRQ_ANY_EDGE: + reg_value = s->ioar; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_CADENCE_GPIO, __func__, offset); + break; + } + + trace_cdns_gpio_read(DEVICE(s)->canonical_path, offset, reg_value); + + return reg_value; +} + +static void cdns_gpio_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + CadenceGPIOState *s = CADENCE_GPIO(opaque); + + trace_cdns_gpio_write(DEVICE(s)->canonical_path, offset, value); + + switch (offset) { + case CDNS_GPIO_BYPASS_MODE: + s->bmr = value; + cdns_gpio_update_output_irq(s); + cdns_gpio_update_isr(s); + break; + + case CDNS_GPIO_DIRECTION_MODE: + s->dmr = value; + cdns_gpio_update_output_irq(s); + cdns_gpio_update_isr(s); + break; + + case CDNS_GPIO_OUTPUT_EN: + s->oer = value; + cdns_gpio_update_output_irq(s); + break; + + case CDNS_GPIO_OUTPUT_VALUE: + s->ovr = value; + cdns_gpio_update_output_irq(s); + break; + + case CDNS_GPIO_IRQ_EN: + s->imr &= ~value; + cdns_gpio_update_isr(s); + break; + + case CDNS_GPIO_IRQ_DIS: + s->imr |= value; + cdns_gpio_update_isr(s); + break; + + case CDNS_GPIO_IRQ_TYPE: + s->itr = value; + break; + + case CDNS_GPIO_IRQ_VALUE: + s->ivr = value; + break; + + case CDNS_GPIO_IRQ_ANY_EDGE: + s->ioar = value; + break; + + case CDNS_GPIO_INPUT_VALUE: + case CDNS_GPIO_IRQ_MASK: + case CDNS_GPIO_IRQ_STATUS: + /* Read-Only */ + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_CADENCE_GPIO, __func__, offset); + break; + } +} + +static const MemoryRegionOps cdns_gpio_ops = { + .read = cdns_gpio_read, + .write = cdns_gpio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +static const VMStateDescription vmstate_cdns_gpio = { + .name = TYPE_CADENCE_GPIO, + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(bmr, CadenceGPIOState), + VMSTATE_UINT32(dmr, CadenceGPIOState), + VMSTATE_UINT32(oer, CadenceGPIOState), + VMSTATE_UINT32(ovr, CadenceGPIOState), + VMSTATE_UINT32(inpvr, CadenceGPIOState), + VMSTATE_UINT32(imr, CadenceGPIOState), + VMSTATE_UINT32(isr, CadenceGPIOState), + VMSTATE_UINT32(itr, CadenceGPIOState), + VMSTATE_UINT32(ivr, CadenceGPIOState), + VMSTATE_UINT32(ioar, CadenceGPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static void cdns_gpio_reset(DeviceState *dev) +{ + CadenceGPIOState *s = CADENCE_GPIO(dev); + + s->bmr = 0; + s->dmr = 0; + s->oer = 0; + s->ovr = 0; + s->inpvr = 0; + s->imr = 0xffffffff; + s->isr = 0; + s->itr = 0; + s->ivr = 0; + s->ioar = 0; +} + +static void cdns_gpio_init(Object *obj) +{ + CadenceGPIOState *s = CADENCE_GPIO(obj); + + memory_region_init_io(&s->iomem, obj, &cdns_gpio_ops, s, + TYPE_CADENCE_GPIO, CDNS_GPIO_REG_SIZE); + + qdev_init_gpio_in(DEVICE(s), cdns_gpio_set, CDNS_GPIO_NUM); + qdev_init_gpio_out(DEVICE(s), s->output, CDNS_GPIO_NUM); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); +} + +static void cdns_gpio_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_legacy_reset(dc, cdns_gpio_reset); + dc->vmsd = &vmstate_cdns_gpio; + dc->desc = "Cadence GPIO controller"; +} + +static const TypeInfo cdns_gpio_info = { + .name = TYPE_CADENCE_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(CadenceGPIOState), + .instance_init = cdns_gpio_init, + .class_init = cdns_gpio_class_init, +}; + +static void cdns_gpio_register_types(void) +{ + type_register_static(&cdns_gpio_info); +} + +type_init(cdns_gpio_register_types) diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 6a67ee958f..0555f44b6a 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -19,3 +19,4 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c')) system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sgpio.c')) system_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c')) system_ss.add(when: 'CONFIG_PCF8574', if_true: files('pcf8574.c')) +system_ss.add(when: 'CONFIG_CADENCE_GPIO', if_true: files('cadence_gpio.c')) diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events index cea896b28f..80ca783a03 100644 --- a/hw/gpio/trace-events +++ b/hw/gpio/trace-events @@ -46,3 +46,8 @@ stm32l4x5_gpio_read(char *gpio, uint64_t addr) "GPIO%s addr: 0x%" PRIx64 " " stm32l4x5_gpio_write(char *gpio, uint64_t addr, uint64_t data) "GPIO%s addr: 0x%" PRIx64 " val: 0x%" PRIx64 "" stm32l4x5_gpio_update_idr(char *gpio, uint32_t old_idr, uint32_t new_idr) "GPIO%s from: 0x%x to: 0x%x" stm32l4x5_gpio_pins(char *gpio, uint16_t disconnected, uint16_t high) "GPIO%s disconnected pins: 0x%x levels: 0x%x" + +# cadence_gpio.c +cdns_gpio_read(const char *path, uint64_t offset, uint32_t value) "%s:reg[0x%04" PRIx64 "] -> 0x%" PRIx32 +cdns_gpio_write(const char *path, uint64_t offset, uint64_t value) "%s:reg[0x%04" PRIx64 "] <- 0x%04" PRIx64 +cdns_gpio_set(const char *path, int line, int level) "%s:[%d] <- %d" diff --git a/include/hw/gpio/cadence_gpio.h b/include/hw/gpio/cadence_gpio.h new file mode 100644 index 0000000000..69646ba639 --- /dev/null +++ b/include/hw/gpio/cadence_gpio.h @@ -0,0 +1,53 @@ +/* + * Cadence GPIO registers definition. + * + * Author: Kuan-Jui Chiu + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef CADENCE_GPIO_H +#define CADENCE_GPIO_H + +#include "hw/core/sysbus.h" +#include "qom/object.h" + +#define TYPE_CADENCE_GPIO "cadence_gpio" +OBJECT_DECLARE_SIMPLE_TYPE(CadenceGPIOState, CADENCE_GPIO) + +#define CDNS_GPIO_REG_SIZE 0x400 +#define CDNS_GPIO_NUM 32 + +#define CDNS_GPIO_BYPASS_MODE 0x00 +#define CDNS_GPIO_DIRECTION_MODE 0x04 +#define CDNS_GPIO_OUTPUT_EN 0x08 +#define CDNS_GPIO_OUTPUT_VALUE 0x0c +#define CDNS_GPIO_INPUT_VALUE 0x10 +#define CDNS_GPIO_IRQ_MASK 0x14 +#define CDNS_GPIO_IRQ_EN 0x18 +#define CDNS_GPIO_IRQ_DIS 0x1c +#define CDNS_GPIO_IRQ_STATUS 0x20 +#define CDNS_GPIO_IRQ_TYPE 0x24 +#define CDNS_GPIO_IRQ_VALUE 0x28 +#define CDNS_GPIO_IRQ_ANY_EDGE 0x2c + +struct CadenceGPIOState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + uint32_t bmr; + uint32_t dmr; + uint32_t oer; + uint32_t ovr; + uint32_t inpvr; + uint32_t imr; + uint32_t isr; + uint32_t itr; + uint32_t ivr; + uint32_t ioar; + qemu_irq irq; + qemu_irq output[CDNS_GPIO_NUM]; +}; + +#endif /* CADENCE_GPIO_H */ From a4256760c0e0a123569be2e99d8749f00b812c1d Mon Sep 17 00:00:00 2001 From: Kuan-Jui Chiu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 221/627] hw/arm: ax3000-soc: Enable Cadence GPIO controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable 8 Cadence GPIO controllers into Axiado AX3000 SoC Signed-off-by: Kuan-Jui Chiu Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260713073033.3883619-9-kchiu@axiado.com Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/ax3000-soc.c | 30 ++++++++++++++++++++++++++++++ include/hw/arm/ax3000-soc.h | 21 +++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index d16b3d2f47..e22c34a2e1 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -731,6 +731,7 @@ config AXIADO_SOC select ARM_GIC select CADENCE # UART select AXIADO_CLK + select CADENCE_GPIO select AXIADO_SDHCI select UNIMP diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c index 23903b081b..71e31c6fb4 100644 --- a/hw/arm/ax3000-soc.c +++ b/hw/arm/ax3000-soc.c @@ -36,6 +36,11 @@ static void ax3000_init(Object *obj) object_initialize_child(obj, "clk", &s->ax3000_clk, TYPE_AX3000_CLK); object_initialize_child(obj, "sdhci0", &s->sdhci0, TYPE_AXIADO_SDHCI); + + for (int i = 0; i < AX3000_NUM_GPIOS; i++) { + g_autofree char *name = g_strdup_printf("gpio%d", i); + object_initialize_child(obj, name, &s->gpio[i], TYPE_CADENCE_GPIO); + } } static void ax3000_realize(DeviceState *dev, Error **errp) @@ -187,6 +192,31 @@ static void ax3000_realize(DeviceState *dev, Error **errp) &error_fatal); qdev_realize_and_unref(card, s->sdhci0.sd_bus, &error_fatal); } + + /* GPIOs */ + const struct { + hwaddr addr; + unsigned int irq; + } gpio_table[] = { + { AX3000_GPIO0_BASE, AX3000_GPIO0_IRQ }, + { AX3000_GPIO1_BASE, AX3000_GPIO1_IRQ }, + { AX3000_GPIO2_BASE, AX3000_GPIO2_IRQ }, + { AX3000_GPIO3_BASE, AX3000_GPIO3_IRQ }, + { AX3000_GPIO4_BASE, AX3000_GPIO4_IRQ }, + { AX3000_GPIO5_BASE, AX3000_GPIO5_IRQ }, + { AX3000_GPIO6_BASE, AX3000_GPIO6_IRQ }, + { AX3000_GPIO7_BASE, AX3000_GPIO7_IRQ } + }; + + for (int i = 0; i < AX3000_NUM_GPIOS; i++) { + 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(gic_dev, gpio_table[i].irq)); + } } static void ax3000_class_init(ObjectClass *oc, const void *data) diff --git a/include/hw/arm/ax3000-soc.h b/include/hw/arm/ax3000-soc.h index 52b47aa829..344fcb6f3c 100644 --- a/include/hw/arm/ax3000-soc.h +++ b/include/hw/arm/ax3000-soc.h @@ -13,6 +13,7 @@ #include "hw/intc/arm_gicv3_common.h" #include "hw/char/cadence_uart.h" #include "hw/misc/axiado_clk.h" +#include "hw/gpio/cadence_gpio.h" #include "hw/sd/axiado_sdhci.h" #include "hw/core/sysbus.h" #include "qemu/units.h" @@ -38,6 +39,15 @@ OBJECT_DECLARE_TYPE(Ax3000SoCState, Ax3000SoCClass, AX3000_SOC) #define AX3000_SDHCI0_BASE 0x86000000 #define AX3000_EMMC_PHY_BASE 0x80801C00 +#define AX3000_GPIO0_BASE 0x80500000 +#define AX3000_GPIO1_BASE 0x80580000 +#define AX3000_GPIO2_BASE 0x80600000 +#define AX3000_GPIO3_BASE 0x80680000 +#define AX3000_GPIO4_BASE 0x80700000 +#define AX3000_GPIO5_BASE 0x80780000 +#define AX3000_GPIO6_BASE 0x80800000 +#define AX3000_GPIO7_BASE 0x80880000 + #define AX3000_TIMER_CTRL 0x8A020000 #define AX3000_PLL_BASE 0x80000000 @@ -46,6 +56,7 @@ enum Ax3000Configuration { AX3000_NUM_IRQS = 224, AX3000_NUM_BANKS = 2, AX3000_NUM_UARTS = 4, + AX3000_NUM_GPIOS = 8, }; typedef struct Ax3000SoCState { @@ -56,6 +67,7 @@ typedef struct Ax3000SoCState { MemoryRegion dram[AX3000_NUM_BANKS]; Ax3000ClkState ax3000_clk; CadenceUARTState uart[AX3000_NUM_UARTS]; + CadenceGPIOState gpio[AX3000_NUM_GPIOS]; AxiadoSDHCIState sdhci0; } Ax3000SoCState; @@ -72,6 +84,15 @@ enum Ax3000Irqs { AX3000_UART3_IRQ = 170, AX3000_SDHCI0_IRQ = 123, + + AX3000_GPIO0_IRQ = 183, + AX3000_GPIO1_IRQ = 184, + AX3000_GPIO2_IRQ = 185, + AX3000_GPIO3_IRQ = 186, + AX3000_GPIO4_IRQ = 187, + AX3000_GPIO5_IRQ = 188, + AX3000_GPIO6_IRQ = 189, + AX3000_GPIO7_IRQ = 190, }; #endif /* AXIADO_AX3000_H */ From 000ef0d13b4fb82a0e4279d6409df805fc28815b Mon Sep 17 00:00:00 2001 From: Simon Xu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 222/627] hw/arm/armsse.c: fix SSE-300 s32kwatchdog address The SSE-300 SLOWCLK Secure Watchdog Timer is only defined at address 0x5802e000 in the secure region. Page 45 of the SSE-300 TRM specifies that "the watchdog is Secure access only". SSE-300 TRM: https://support.arm.com/documentation/101773/latest/ Fixes: 8901bb414a24 ("hw/arm/armsse: Add SSE-300 support") Suggested-by: Peter Maydell Signed-off-by: Simon Xu Message-id: 20260805191257.11303-2-simonxhy0404@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/armsse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index ddb210c895..e99b491bd9 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -409,7 +409,7 @@ static const ARMSSEDeviceInfo sse300_devices[] = { .name = "s32kwatchdog", .type = TYPE_CMSDK_APB_WATCHDOG, .index = 0, - .addr = 0x4802e000, + .addr = 0x5802e000, .ppc = NO_PPC, .irq = NMI_0, .slowclk = true, From 024c539a625c4cb15bc5e2f50b4a91672eef3f77 Mon Sep 17 00:00:00 2001 From: Simon Xu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 223/627] hw/arm/armsse.c: fix SSE-300 PPU addresses The SSE-300 CPU0_PPU, MGMT_PPU, DEBUG_PPU had the wrong addresses that were the same as the SSE-200 addresses. Page 146 of the SSE-300 TRM defines the addresses of the PPUs. SSE-300 TRM: https://support.arm.com/documentation/101773/latest/ Fixes: 8901bb414a24 ("hw/arm/armsse: Add SSE-300 support") Signed-off-by: Simon Xu Message-id: 20260805191257.11303-3-simonxhy0404@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/armsse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index e99b491bd9..55fbc2c290 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -452,7 +452,7 @@ static const ARMSSEDeviceInfo sse300_devices[] = { .name = "CPU0CORE_PPU", .type = TYPE_UNIMPLEMENTED_DEVICE, .index = 2, - .addr = 0x50023000, + .addr = 0x58023000, .size = 0x1000, .ppc = NO_PPC, .irq = NO_IRQ, @@ -461,7 +461,7 @@ static const ARMSSEDeviceInfo sse300_devices[] = { .name = "MGMT_PPU", .type = TYPE_UNIMPLEMENTED_DEVICE, .index = 3, - .addr = 0x50028000, + .addr = 0x58028000, .size = 0x1000, .ppc = NO_PPC, .irq = NO_IRQ, @@ -470,7 +470,7 @@ static const ARMSSEDeviceInfo sse300_devices[] = { .name = "DEBUG_PPU", .type = TYPE_UNIMPLEMENTED_DEVICE, .index = 4, - .addr = 0x50029000, + .addr = 0x58029000, .size = 0x1000, .ppc = NO_PPC, .irq = NO_IRQ, From 230edd14d5554bd35fe5ffee37a34437973ed9c2 Mon Sep 17 00:00:00 2001 From: Simon Xu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 224/627] hw/arm/mps2-tz.c: fix AN547 APB PPC EXP0 MPC ports The AN547 TRM defines them to be on ports [15:13], not [2:0]. AN547 TRM: https://developer.arm.com/documentation/dai0547/latest/ Fixes: eb09d533d87f ("hw/arm/mps2-tz: Add new mps3-an547 board") Suggested-by: Peter Maydell Signed-off-by: Simon Xu Message-id: 20260805191257.11303-4-simonxhy0404@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2-tz.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index f101c1b7c3..81e64a91de 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -1048,6 +1048,19 @@ static void mps2tz_common_init(MachineState *machine) const PPCInfo an547_ppcs[] = { { .name = "apb_ppcexp0", .ports = { + { /* port 0 USER MEM APB0 */ }, + { /* port 1 USER MEM APB0 */ }, + { /* port 2 reserved */ }, + { /* port 3 reserved */ }, + { /* port 4 NPU APB0 */ }, + { /* port 5 NPU APB1 */ }, + { /* port 6 reserved */ }, + { /* port 7 reserved */ }, + { /* port 8 reserved */ }, + { /* port 9 reserved */ }, + { /* port 10 reserved */ }, + { /* port 11 reserved */ }, + { /* port 12 reserved */ }, { "ssram-mpc", make_mpc, &mms->mpc[0], 0x57000000, 0x1000 }, { "qspi-mpc", make_mpc, &mms->mpc[1], 0x57001000, 0x1000 }, { "ddr-mpc", make_mpc, &mms->mpc[2], 0x57002000, 0x1000 }, From f43d9507194c81e76ef2828ef90a3b2102890c20 Mon Sep 17 00:00:00 2001 From: Simon Xu Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 225/627] hw/arm/mps2-tz.c: add AN547 AHB PPC EXP1 DMA ports Page 42 of the AN547 TRM defines the AHB PPC EXP1 ports with DMA 1-3 AN547 TRM: https://developer.arm.com/documentation/dai0547/latest/ Suggested-by: Peter Maydell Signed-off-by: Simon Xu Message-id: 20260805191257.11303-5-simonxhy0404@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2-tz.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 81e64a91de..d6d178642b 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -1113,6 +1113,14 @@ static void mps2tz_common_init(MachineState *machine) { /* port 7 USER AHB interface 3 */ }, { "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 49 } }, }, + }, { + .name = "ahb_ppcexp1", + .ports = { + { /* port 0 reserved */ }, + { "dma1", make_dma, &mms->dma[1], 0x41201000, 0x1000, { 62, 60, 61 } }, + { "dma2", make_dma, &mms->dma[2], 0x41202000, 0x1000, { 65, 63, 64 } }, + { "dma3", make_dma, &mms->dma[3], 0x41203000, 0x1000, { 68, 66, 67 } }, + }, }, }; From 20bf099da7c0dff3494cc36ae43add1ff376be52 Mon Sep 17 00:00:00 2001 From: botszhuang Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 226/627] hw/i2c/bcm2835_i2c: Correct iomem size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last valid register is the Clock Stretch Timeout (CLKT) at offset 0x1c. Since it is a 32-bit register, the total memory region size should be 0x1c + 4 = 0x20. Update the size parameter in memory_region_init_io() from 0x24 to 0x20 to accurately reflect the hardware specification. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: botszhuang Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260804144611.31735-1-huang.botsz@gmail.com Signed-off-by: Peter Maydell --- hw/i2c/bcm2835_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i2c/bcm2835_i2c.c b/hw/i2c/bcm2835_i2c.c index 34de1f36e5..5f6093087d 100644 --- a/hw/i2c/bcm2835_i2c.c +++ b/hw/i2c/bcm2835_i2c.c @@ -222,7 +222,7 @@ static void bcm2835_i2c_realize(DeviceState *dev, Error **errp) s->bus = i2c_init_bus(dev, NULL); memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_i2c_ops, s, - TYPE_BCM2835_I2C, 0x24); + TYPE_BCM2835_I2C, 0x20); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); } From 21fcfb6046082a06b82c17688634a1b769ee63a0 Mon Sep 17 00:00:00 2001 From: Marcelo Manzo Date: Tue, 11 Aug 2026 20:14:11 +0100 Subject: [PATCH 227/627] hw/misc/bcm2835_powermgt: implement a real watchdog timer The RSTC register's write-config bits (0x30) being set to the "full reset" value (0x20) does not mean "reset now" -- it arms the hardware watchdog so that a reset happens if the WDOG countdown register is not refreshed before it expires. The previous implementation treated any such RSTC write as an immediate reset, regardless of the WDOG value. This is dormant on older/lighter userspace (nothing in Bullseye's default boot touches these registers this way), but modern systemd (observed with Debian 13/Trixie's systemd 257) writes to RSTC as part of routine early-boot watchdog probing. With the old code, this fires an immediate reset a few seconds into boot; combined with -no-reboot this looks exactly like a QEMU crash (clean exit, no panic, no guest reboot message) with the last log line being the RSTC/WDOG write. Fix this by actually implementing the watchdog as a QEMUTimer: writes to RSTC/WDOG (re)compute the timeout from the WDOG register (in units of 1/65536 s, per the real hardware) and arm a timer for that many nanoseconds out; only when the timer actually fires do we request a system reset or shutdown, matching real hardware behavior. Clearing the write-config bits or the WDOG value disarms the timer, and reset disarms it too. Verified against real Raspberry Pi OS images under the patched raspi4b machine: Bullseye (5.15) and Bookworm (6.12) never exercised this path either way; Trixie (6.18, systemd 257) no longer crashes at boot and reaches a working login/SSH state. This is a migration compatibility break for the raspi boards. Signed-off-by: Marcelo Manzo [PMM: bump vmstate version IDs, note migration break in commit msg] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/bcm2835_powermgt.c | 53 ++++++++++++++++++++++-------- include/hw/misc/bcm2835_powermgt.h | 2 ++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/hw/misc/bcm2835_powermgt.c b/hw/misc/bcm2835_powermgt.c index 3ec7abad0e..7b01be48bb 100644 --- a/hw/misc/bcm2835_powermgt.c +++ b/hw/misc/bcm2835_powermgt.c @@ -19,10 +19,40 @@ #define PASSWORD_MASK 0xff000000 #define R_RSTC 0x1c -#define V_RSTC_RESET 0x20 +#define V_RSTC_WRCFG_MASK 0x30 +#define V_RSTC_FULL_RESET 0x20 #define R_RSTS 0x20 #define V_RSTS_POWEROFF 0x555 /* Linux uses partition 63 to indicate halt. */ #define R_WDOG 0x24 +#define V_WDOG_TIME_MASK 0xfffff +#define WDOG_TICKS_PER_SECOND 65536 + +static void bcm2835_powermgt_expire(void *opaque) +{ + BCM2835PowerMgtState *s = opaque; + + if ((s->rsts & 0xfff) == V_RSTS_POWEROFF) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } else { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + +static void bcm2835_powermgt_update_wdog(BCM2835PowerMgtState *s) +{ + uint64_t timeout_ns; + + if ((s->rstc & V_RSTC_WRCFG_MASK) != V_RSTC_FULL_RESET || + s->wdog == 0) { + timer_del(s->wdog_timer); + return; + } + + timeout_ns = muldiv64(s->wdog, NANOSECONDS_PER_SECOND, + WDOG_TICKS_PER_SECOND); + timer_mod(s->wdog_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout_ns); +} static uint64_t bcm2835_powermgt_read(void *opaque, hwaddr offset, unsigned size) @@ -70,13 +100,7 @@ static void bcm2835_powermgt_write(void *opaque, hwaddr offset, switch (offset) { case R_RSTC: s->rstc = value; - if (value & V_RSTC_RESET) { - if ((s->rsts & 0xfff) == V_RSTS_POWEROFF) { - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - } else { - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - } - } + bcm2835_powermgt_update_wdog(s); break; case R_RSTS: qemu_log_mask(LOG_UNIMP, @@ -84,9 +108,8 @@ static void bcm2835_powermgt_write(void *opaque, hwaddr offset, s->rsts = value; break; case R_WDOG: - qemu_log_mask(LOG_UNIMP, - "bcm2835_powermgt_write: WDOG\n"); - s->wdog = value; + s->wdog = value & V_WDOG_TIME_MASK; + bcm2835_powermgt_update_wdog(s); break; default: @@ -107,12 +130,13 @@ static const MemoryRegionOps bcm2835_powermgt_ops = { static const VMStateDescription vmstate_bcm2835_powermgt = { .name = TYPE_BCM2835_POWERMGT, - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (const VMStateField[]) { VMSTATE_UINT32(rstc, BCM2835PowerMgtState), VMSTATE_UINT32(rsts, BCM2835PowerMgtState), VMSTATE_UINT32(wdog, BCM2835PowerMgtState), + VMSTATE_TIMER_PTR(wdog_timer, BCM2835PowerMgtState), VMSTATE_END_OF_LIST() } }; @@ -124,6 +148,8 @@ static void bcm2835_powermgt_init(Object *obj) memory_region_init_io(&s->iomem, obj, &bcm2835_powermgt_ops, s, TYPE_BCM2835_POWERMGT, 0x200); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + s->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + bcm2835_powermgt_expire, s); } static void bcm2835_powermgt_reset(DeviceState *dev) @@ -134,6 +160,7 @@ static void bcm2835_powermgt_reset(DeviceState *dev) s->rstc = 0x00000102; s->rsts = 0x00001000; s->wdog = 0x00000000; + timer_del(s->wdog_timer); } static void bcm2835_powermgt_class_init(ObjectClass *klass, const void *data) diff --git a/include/hw/misc/bcm2835_powermgt.h b/include/hw/misc/bcm2835_powermgt.h index fb0740c01e..d1903a9cce 100644 --- a/include/hw/misc/bcm2835_powermgt.h +++ b/include/hw/misc/bcm2835_powermgt.h @@ -12,6 +12,7 @@ #define BCM2835_POWERMGT_H #include "hw/core/sysbus.h" +#include "qemu/timer.h" #include "qom/object.h" #define TYPE_BCM2835_POWERMGT "bcm2835-powermgt" @@ -24,6 +25,7 @@ struct BCM2835PowerMgtState { uint32_t rstc; uint32_t rsts; uint32_t wdog; + QEMUTimer *wdog_timer; }; #endif From c59b6916269d8d813399bfc02c75207b0bef91c6 Mon Sep 17 00:00:00 2001 From: Marcelo Manzo Date: Tue, 11 Aug 2026 10:35:38 -0400 Subject: [PATCH 228/627] hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit raspi4_modify_dtb() decides whether to add a second memory node above the 1 GiB peripheral hole by checking info->ram_size -- but that field is the boot loader's RAM budget for loading the kernel/initrd/dtb image, itself always capped to at most UPPER_RAM_BASE - vcram_size by raspi_base_machine_init(). Since that capped value can never exceed UPPER_RAM_BASE by construction, the condition was never true for any raspi4b configuration, and the second node was never added: the guest never saw more than ~1 GiB of its nominal RAM, regardless of the machine's actual size. board_ram_size(info->board_id), computed one line above in the same function, is the value that was actually needed -- the board's real total RAM, not the boot loader's own budget for where it's allowed to place the kernel image. Confirmed via direct measurement inside the guest ("free -h" / /proc/meminfo) on raspi4b's default 2 GiB configuration, before and after: before: MemTotal: 943524 kB (~921 MiB) after: MemTotal: 1905824 kB (~1861 MiB) Also verified against two real, unmodified Raspberry Pi OS releases (Debian 11/Bullseye and Debian 13/Trixie): both now report ~1.8 GiB of usable RAM instead of ~900 MiB, with clean boots, working SSH, and no kernel errors on either. Signed-off-by: Marcelo Manzo Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260811143539.7835-2-marcelomanzo@gmail.com Signed-off-by: Peter Maydell --- hw/arm/raspi4b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c index 06aeb8db01..e1595a875f 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -85,7 +85,7 @@ static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt) ram_size = board_ram_size(info->board_id); - if (info->ram_size > UPPER_RAM_BASE) { + if (ram_size > UPPER_RAM_BASE) { raspi_add_memory_node(fdt, UPPER_RAM_BASE, ram_size - UPPER_RAM_BASE); } } From 49aecf39008ebeb86127b5055cefa17d68370b20 Mon Sep 17 00:00:00 2001 From: Marcelo Manzo Date: Tue, 11 Aug 2026 10:35:39 -0400 Subject: [PATCH 229/627] tests/functional/aarch64: add raspi4b full-RAM regression test Guards against the bug fixed in the previous commit: boots raspi4b's default 2 GiB configuration and checks that the guest actually sees close to that (>1.9M kB), not the ~921 MiB the bug left it capped at. Deliberately checks a threshold rather than the exact byte count of either figure, since the precise number depends on how this specific pinned kernel accounts for its own early reservations; the threshold is comfortably between the two (943524 kB broken, 1905824 kB fixed, confirmed by hand against this exact kernel/initrd). Folded into the existing test_arm_raspi4_initrd test rather than a new standalone boot, since it needs no machine state that test isn't already setting up, and the functional-test suite is already slow enough from how many separate guest boots it runs. Signed-off-by: Marcelo Manzo Message-id: 20260811143539.7835-3-marcelomanzo@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/functional/aarch64/test_raspi4.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/functional/aarch64/test_raspi4.py b/tests/functional/aarch64/test_raspi4.py index 7a4302b0c5..bacecbbe9c 100755 --- a/tests/functional/aarch64/test_raspi4.py +++ b/tests/functional/aarch64/test_raspi4.py @@ -86,6 +86,23 @@ class Aarch64Raspi4Machine(LinuxKernelTest): 'BCM2835') exec_command_and_wait_for_pattern(self, 'cat /proc/iomem', 'cprman@7e101000') + + # We used to get the RAM size wrong; guard against a regression + # (see git history for details). + mem_total_kb = None + cmd_output = exec_command_and_wait_for_pattern( + self, 'cat /proc/meminfo', 'MemAvailable') + for line in cmd_output.decode('ascii', errors='replace').splitlines(): + if line.startswith('MemTotal:'): + mem_total_kb = int(line.split()[1]) + break + self.assertIsNotNone(mem_total_kb, 'MemTotal line not found') + self.assertGreater(mem_total_kb, 1900000, + 'guest RAM (%d kB) is far below the ~1.9 GiB ' + 'expected for a 2 GiB raspi4b -- the second ' + 'memory node above the 1 GiB peripheral hole ' + 'is probably not being added' % mem_total_kb) + exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted') # TODO: Raspberry Pi4 doesn't shut down properly with recent kernels # Wait for VM to shut down gracefully From ac7fa2e9d457ff9c777be32617f3c46548c4cadf Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 28 Jul 2026 17:04:14 -0400 Subject: [PATCH 230/627] migration/multifd: Validate next_packet_size in zlib/zstd recv The zlib and zstd multifd compression backends read next_packet_size from the incoming migration stream and use it directly as the read length into a fixed-size buffer (MULTIFD_PACKET_SIZE * 2 = 1MB). A malicious migration source can set next_packet_size bigger than allocated, causing a heap buffer overflow write on the destination. Add a check against zbuff_len before reading, matching what the qatzip backend already does. Also replace the assert(in_size == 0) for empty packets with proper error reporting, since the value is wire-controlled, meanwhile assert() stops working with -DNDEBUG builds. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3737 Reported-by: xlabai Reported-by: Jules Denardou Reported-by: Tristan Madani Reported-by: david korczynski (@david1766) Reported-by: huntr bubble (@bubblehuntr) Cc: qemu-stable Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260728210417.1925078-3-peterx@redhat.com Signed-off-by: Peter Xu --- migration/multifd-zlib.c | 11 ++++++++++- migration/multifd-zstd.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c index 8820b2a787..400146566e 100644 --- a/migration/multifd-zlib.c +++ b/migration/multifd-zlib.c @@ -216,10 +216,19 @@ static int multifd_zlib_recv(MultiFDRecvParams *p, Error **errp) return -1; } + if (in_size > z->zbuff_len) { + error_setg(errp, "multifd %u: next_packet_size %"PRIu32 + " exceeds allocated %"PRIu32, p->id, in_size, z->zbuff_len); + return -1; + } + multifd_recv_zero_page_process(p); if (!p->normal_num) { - assert(in_size == 0); + if (in_size != 0) { + error_setg(errp, "multifd %u: expected empty packet", p->id); + return -1; + } return 0; } diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c index 3c2dcf76b0..69ef1a5f38 100644 --- a/migration/multifd-zstd.c +++ b/migration/multifd-zstd.c @@ -210,10 +210,19 @@ static int multifd_zstd_recv(MultiFDRecvParams *p, Error **errp) return -1; } + if (in_size > z->zbuff_len) { + error_setg(errp, "multifd %u: next_packet_size %"PRIu32 + " exceeds allocated %"PRIu32, p->id, in_size, z->zbuff_len); + return -1; + } + multifd_recv_zero_page_process(p); if (!p->normal_num) { - assert(in_size == 0); + if (in_size != 0) { + error_setg(errp, "multifd %u: expected empty packet", p->id); + return -1; + } return 0; } From cf45083edc2b760a952836187aba7ec4139418c0 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 28 Jul 2026 17:04:15 -0400 Subject: [PATCH 231/627] migration/multifd: Replace assert() with error_setg() in recv paths QPL and UADK multifd backends use assert() to validate wire-controlled fields like per-page compressed lengths and packet size consistency. These asserts will stop working with -DNDEBUG builds, so may stop working. Replace all assert() calls in the receive path with proper error_setg() so validation failures are reported gracefully rather than crashing or silently ignored. While at it, touch up an assert() in qatzip recv path too. Cc: qemu-stable Cc: Yuan Liu Cc: Yichen Wang Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260728210417.1925078-4-peterx@redhat.com Signed-off-by: Peter Xu --- migration/multifd-qatzip.c | 5 ++++- migration/multifd-qpl.c | 24 ++++++++++++++++++++---- migration/multifd-uadk.c | 24 ++++++++++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/migration/multifd-qatzip.c b/migration/multifd-qatzip.c index 7419e5dc0d..0262e81eac 100644 --- a/migration/multifd-qatzip.c +++ b/migration/multifd-qatzip.c @@ -348,7 +348,10 @@ static int qatzip_recv(MultiFDRecvParams *p, Error **errp) multifd_recv_zero_page_process(p); if (!p->normal_num) { - assert(in_size == 0); + if (in_size != 0) { + error_setg(errp, "multifd %u: expected empty packet", p->id); + return -1; + } return 0; } diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c index 52902eb00c..3826e7f340 100644 --- a/migration/multifd-qpl.c +++ b/migration/multifd-qpl.c @@ -664,26 +664,42 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp) } multifd_recv_zero_page_process(p); if (!p->normal_num) { - assert(in_size == 0); + if (in_size != 0) { + error_setg(errp, "multifd %u: expected empty packet", p->id); + return -1; + } return 0; } /* read compressed page lengths */ len = p->normal_num * sizeof(uint32_t); - assert(len < in_size); + if (len >= in_size) { + error_setg(errp, "multifd %u: header len %"PRIu32 + " >= packet size %"PRIu32, p->id, len, in_size); + return -1; + } ret = qio_channel_read_all(p->c, (void *) qpl->zlen, len, errp); if (ret != 0) { return ret; } for (int i = 0; i < p->normal_num; i++) { qpl->zlen[i] = be32_to_cpu(qpl->zlen[i]); - assert(qpl->zlen[i] <= multifd_ram_page_size()); + if (qpl->zlen[i] > multifd_ram_page_size()) { + error_setg(errp, "multifd %u: page %d compressed len %" + PRIu32" too large", p->id, i, qpl->zlen[i]); + return -1; + } zbuf_len += qpl->zlen[i]; ramblock_recv_bitmap_set_offset(p->block, p->normal[i]); } /* read compressed pages */ - assert(in_size == len + zbuf_len); + if (in_size != len + zbuf_len) { + error_setg(errp, "multifd %u: packet size %"PRIu32 + " != header %"PRIu32" + data %"PRIu32, + p->id, in_size, len, zbuf_len); + return -1; + } ret = qio_channel_read_all(p->c, (void *) qpl->zbuf, zbuf_len, errp); if (ret != 0) { return ret; diff --git a/migration/multifd-uadk.c b/migration/multifd-uadk.c index fd7cd9b5e8..d373615ba8 100644 --- a/migration/multifd-uadk.c +++ b/migration/multifd-uadk.c @@ -245,12 +245,19 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp) multifd_recv_zero_page_process(p); if (!p->normal_num) { - assert(in_size == 0); + if (in_size != 0) { + error_setg(errp, "multifd %u: expected empty packet", p->id); + return -1; + } return 0; } /* read compressed data lengths */ - assert(hdr_len < in_size); + if (hdr_len >= in_size) { + error_setg(errp, "multifd %u: header len %"PRIu32 + " >= packet size %"PRIu32, p->id, hdr_len, in_size); + return -1; + } ret = qio_channel_read_all(p->c, (void *) uadk_data->buf_hdr, hdr_len, errp); if (ret != 0) { @@ -259,12 +266,21 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp) for (int i = 0; i < p->normal_num; i++) { uadk_data->buf_hdr[i] = be32_to_cpu(uadk_data->buf_hdr[i]); + if (uadk_data->buf_hdr[i] > page_size) { + error_setg(errp, "multifd %u: page %d compressed len %"PRIu32 + " too large", p->id, i, uadk_data->buf_hdr[i]); + return -1; + } data_len += uadk_data->buf_hdr[i]; - assert(uadk_data->buf_hdr[i] <= page_size); } /* read compressed data */ - assert(in_size == hdr_len + data_len); + if (in_size != hdr_len + data_len) { + error_setg(errp, "multifd %u: packet size %"PRIu32 + " != header %"PRIu32" + data %"PRIu32, + p->id, in_size, hdr_len, data_len); + return -1; + } ret = qio_channel_read_all(p->c, (void *)buf, data_len, errp); if (ret != 0) { return ret; From 93676b24721135ae965169dd5797d37a5e022939 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 23 Jul 2026 18:38:06 +0200 Subject: [PATCH 232/627] hw: add compat machines for 11.2 Add 11.2 machine types for arm/i440fx/loongarch/m68k/q35/s390x/spapr. Signed-off-by: Cornelia Huck Reviewed-by: Eric Farman Reviewed-by: Bibo Mao Link: https://lore.kernel.org/qemu-devel/20260723163806.368127-1-cohuck@redhat.com [farman@linux.ibm.com: fixup hw/core/machine.c hunk] Signed-off-by: Eric Farman --- hw/arm/virt.c | 11 +++++++++-- hw/core/machine.c | 3 +++ hw/i386/pc.c | 3 +++ hw/i386/pc_piix.c | 13 +++++++++++-- hw/i386/pc_q35.c | 13 +++++++++++-- hw/loongarch/virt.c | 13 ++++++++++--- hw/m68k/virt.c | 11 +++++++++-- hw/ppc/spapr.c | 17 ++++++++++++++--- hw/s390x/s390-virtio-ccw.c | 14 +++++++++++++- include/hw/core/boards.h | 3 +++ include/hw/i386/pc.h | 3 +++ 11 files changed, 89 insertions(+), 15 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 219597cabd..e7a56e37f7 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -4441,10 +4441,17 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_machine_11_1_options(MachineClass *mc) +static void virt_machine_11_2_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(11, 1) +DEFINE_VIRT_MACHINE_AS_LATEST(11, 2) + +static void virt_machine_11_1_options(MachineClass *mc) +{ + virt_machine_11_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); +} +DEFINE_VIRT_MACHINE(11, 1) static void virt_machine_11_0_options(MachineClass *mc) { diff --git a/hw/core/machine.c b/hw/core/machine.c index 73b4d82b4a..3b15645304 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -40,6 +40,9 @@ #include "qemu/audio.h" #include "hw/arm/smmuv3.h" +GlobalProperty hw_compat_11_1[] = {}; +const size_t hw_compat_11_1_len = G_N_ELEMENTS(hw_compat_11_1); + GlobalProperty hw_compat_11_0[] = { { "virtio-mmio", VIRTIO_QUEUE_SIZE_OVERRIDE, "1024" }, { "chardev-vc", "encoding", "cp437" }, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index f064aa2b3e..e9e4fc262b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -74,6 +74,9 @@ #include "hw/xen/xen-bus.h" #endif +GlobalProperty pc_compat_11_1[] = {}; +const size_t pc_compat_11_1_len = G_N_ELEMENTS(pc_compat_11_1); + GlobalProperty pc_compat_11_0[] = {}; const size_t pc_compat_11_0_len = G_N_ELEMENTS(pc_compat_11_0); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 82457bdb16..223a19cc4b 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -428,12 +428,21 @@ static void pc_i440fx_machine_options(MachineClass *m) pc_piix_compat_defaults, pc_piix_compat_defaults_len); } -static void pc_i440fx_machine_11_1_options(MachineClass *m) +static void pc_i440fx_machine_11_2_options(MachineClass *m) { pc_i440fx_machine_options(m); } -DEFINE_I440FX_MACHINE_AS_LATEST(11, 1); +DEFINE_I440FX_MACHINE_AS_LATEST(11, 2); + +static void pc_i440fx_machine_11_1_options(MachineClass *m) +{ + pc_i440fx_machine_11_2_options(m); + compat_props_add(m->compat_props, hw_compat_11_1, hw_compat_11_1_len); + compat_props_add(m->compat_props, pc_compat_11_1, pc_compat_11_1_len); +} + +DEFINE_I440FX_MACHINE(11, 1); static void pc_i440fx_machine_11_0_options(MachineClass *m) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 6c1e4eff5f..94cd71124b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -383,12 +383,21 @@ static void pc_q35_machine_options(MachineClass *m) pc_q35_compat_defaults, pc_q35_compat_defaults_len); } -static void pc_q35_machine_11_1_options(MachineClass *m) +static void pc_q35_machine_11_2_options(MachineClass *m) { pc_q35_machine_options(m); } -DEFINE_Q35_MACHINE_AS_LATEST(11, 1); +DEFINE_Q35_MACHINE_AS_LATEST(11, 2); + +static void pc_q35_machine_11_1_options(MachineClass *m) +{ + pc_q35_machine_11_2_options(m); + compat_props_add(m->compat_props, hw_compat_11_1, hw_compat_11_1_len); + compat_props_add(m->compat_props, pc_compat_11_1, pc_compat_11_1_len); +} + +DEFINE_Q35_MACHINE(11, 1); static void pc_q35_machine_11_0_options(MachineClass *m) { diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 6693dea647..9cc79929a8 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -1465,7 +1465,6 @@ static void virt_class_init(ObjectClass *oc, const void *data) mc->default_ram_id = "loongarch.ram"; mc->desc = "QEMU LoongArch Virtual Machine"; mc->max_cpus = LOONGARCH_MAX_CPUS; - mc->is_default = 1; mc->default_kernel_irqchip_split = false; mc->block_default_type = IF_VIRTIO; mc->default_boot_order = "c"; @@ -1546,6 +1545,7 @@ static void virt_class_init(ObjectClass *oc, const void *data) MACHINE_VER_DEPRECATION(__VA_ARGS__); \ if (latest) { \ mc->alias = "virt"; \ + mc->is_default = true; \ } \ } \ static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = \ @@ -1600,7 +1600,14 @@ static void machvirt_machine_init(void) type_init(machvirt_machine_init); -static void virt_machine_11_1_options(MachineClass *mc) +static void virt_machine_11_2_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(11, 1) +DEFINE_VIRT_MACHINE_AS_LATEST(11, 2) + +static void virt_machine_11_1_options(MachineClass *mc) +{ + virt_machine_11_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); +} +DEFINE_VIRT_MACHINE(11, 1) diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 51158ce1c0..274970978f 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -367,10 +367,17 @@ type_init(virt_machine_register_types) #define DEFINE_VIRT_MACHINE(major, minor) \ DEFINE_VIRT_MACHINE_IMPL(false, major, minor) -static void virt_machine_11_1_options(MachineClass *mc) +static void virt_machine_11_2_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(11, 1) +DEFINE_VIRT_MACHINE_AS_LATEST(11, 2) + +static void virt_machine_11_1_options(MachineClass *mc) +{ + virt_machine_11_2_options(mc); + compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); +} +DEFINE_VIRT_MACHINE(11, 1) static void virt_machine_11_0_options(MachineClass *mc) { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b79828b4e9..7e284edd7d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4764,14 +4764,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc) DEFINE_SPAPR_MACHINE_IMPL(false, major, minor) /* - * pseries-11.1 + * pseries-11.2 */ -static void spapr_machine_11_1_class_options(MachineClass *mc) +static void spapr_machine_11_2_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE_AS_LATEST(11, 1); +DEFINE_SPAPR_MACHINE_AS_LATEST(11, 2); + +/* + * pseries-11.1 + */ +static void spapr_machine_11_1_class_options(MachineClass *mc) +{ + spapr_machine_11_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); +} + +DEFINE_SPAPR_MACHINE(11, 1); /* * pseries-11.0 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 25a9fa4955..55131c1a44 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -925,14 +925,26 @@ static const TypeInfo ccw_machine_info = { DEFINE_CCW_MACHINE_IMPL(false, major, minor) +static void ccw_machine_11_2_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_11_2_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE_AS_LATEST(11, 2); + static void ccw_machine_11_1_instance_options(MachineState *machine) { + ccw_machine_11_2_instance_options(machine); } static void ccw_machine_11_1_class_options(MachineClass *mc) { + ccw_machine_11_2_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); } -DEFINE_CCW_MACHINE_AS_LATEST(11, 1); +DEFINE_CCW_MACHINE(11, 1); static void ccw_machine_11_0_instance_options(MachineState *machine) { diff --git a/include/hw/core/boards.h b/include/hw/core/boards.h index 29c68931d8..a436d48c8e 100644 --- a/include/hw/core/boards.h +++ b/include/hw/core/boards.h @@ -815,6 +815,9 @@ compat_props_add(GPtrArray *arr, } } +extern GlobalProperty hw_compat_11_1[]; +extern const size_t hw_compat_11_1_len; + extern GlobalProperty hw_compat_11_0[]; extern const size_t hw_compat_11_0_len; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index d4b6d3ed57..ac03da97b6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -209,6 +209,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); +extern GlobalProperty pc_compat_11_1[]; +extern const size_t pc_compat_11_1_len; + extern GlobalProperty pc_compat_11_0[]; extern const size_t pc_compat_11_0_len; From 9b3d68edb24d4e04f49822c6e11641e4eb23dfd5 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Wed, 12 Aug 2026 11:13:28 -0400 Subject: [PATCH 233/627] pc-bios/s390-ccw.img: update s390x bios Update the s390 bios with recent fixes for out-of-bounds accesses. Signed-off-by: Eric Farman --- pc-bios/s390-ccw.img | Bin 104136 -> 104216 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index e24a93e14a880aa3a5d498fc84c7bdd1a0964d7c..291cd77eaff40679d0cc2d5697d0c7b73c493e94 100644 GIT binary patch literal 104216 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 UvU8h)7H+<)GeKI&Z>B%-za>;eNdN!< From 80776c4df92c3d58f89608b61e355092a7d524ed Mon Sep 17 00:00:00 2001 From: Bin Guo Date: Tue, 4 Aug 2026 15:34:45 +0800 Subject: [PATCH 234/627] hw/intc/loongarch_pch_pic: Validate htmsi_vector before indexing parent_irq pch_pic_update_irq() used the guest-writable htmsi_vector[irq] value as an index into parent_irq[] without checking bounds. A value >= irq_num (64 in the array, but only 32 are used by the virt machine) causes an out-of-bounds read and a guest-triggerable QEMU crash. Validate the vector before calling qemu_set_irq() in both the raise and lower paths and log a guest error if it is out of range. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4114 Cc: qemu-stable@nongnu.org Signed-off-by: Bin Guo Signed-off-by: Bibo Mao Reviewed-by: Bibo Mao --- hw/intc/loongarch_pch_pic.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 82e16be391..e87c7497c1 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -19,13 +19,21 @@ static void pch_pic_update_irq(LoongArchPICCommonState *s, uint64_t mask, { uint64_t val; int irq; + uint8_t vector; if (level) { val = mask & s->intirr & ~s->int_mask; if (val) { irq = ctz64(val); + vector = s->htmsi_vector[irq]; + if (vector >= s->irq_num) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: htmsi_vector[%d]=%u out of range\n", + __func__, irq, vector); + return; + } s->intisr |= MAKE_64BIT_MASK(irq, 1); - qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); + qemu_set_irq(s->parent_irq[vector], 1); } } else { /* @@ -35,8 +43,15 @@ static void pch_pic_update_irq(LoongArchPICCommonState *s, uint64_t mask, val = mask & s->intisr & ~s->intirr; if (val) { irq = ctz64(val); + vector = s->htmsi_vector[irq]; + if (vector >= s->irq_num) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: htmsi_vector[%d]=%u out of range\n", + __func__, irq, vector); + return; + } s->intisr &= ~MAKE_64BIT_MASK(irq, 1); - qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); + qemu_set_irq(s->parent_irq[vector], 0); } } } From 181b584b7765fac97a3caac3fe0121fc379d779a Mon Sep 17 00:00:00 2001 From: Dongyan Qian Date: Tue, 4 Aug 2026 11:30:34 +0800 Subject: [PATCH 235/627] tests/acpi: Allow LoongArch virt MADT changes The LoongArch virt MADT revision will be corrected to match the interrupt controller structures it contains. Allow the APIC and APIC.topology test data to change so that the source change can be reviewed separately from the regenerated binary tables. Signed-off-by: Dongyan Qian Signed-off-by: Bibo Mao Reviewed-by: Bibo Mao --- tests/qtest/bios-tables-test-allowed-diff.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..0e18673fcd 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,3 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/loongarch64/virt/APIC", +"tests/data/acpi/loongarch64/virt/APIC.topology", From 9583a9c07d9d91439e5921ae7fb69bd7f69a94f3 Mon Sep 17 00:00:00 2001 From: Dongyan Qian Date: Tue, 4 Aug 2026 11:30:35 +0800 Subject: [PATCH 236/627] hw/loongarch/virt: Set MADT revision to 6 The LoongArch virt machine emits Core PIC, EIO PIC, MSI PIC and BIO PIC subtables, but advertises MADT revision 1. Revision 1 predates these LoongArch interrupt controller structures. ACPI 6.5 introduced the LoongArch interrupt controller structures and defined MADT revision 6. ACPI 6.6 raises the MADT revision to 7 for the additional RISC-V interrupt controller structures, while leaving the LoongArch structures unchanged. Since the virt machine emits only the LoongArch structures defined by ACPI 6.5, set the MADT header revision to 6, the minimum revision that describes the table contents. Fixes: 735143f10d3 ("hw/loongarch: Add acpi ged support") Signed-off-by: Dongyan Qian Signed-off-by: Bibo Mao Reviewed-by: Bibo Mao --- hw/loongarch/virt-acpi-build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c index a0b445f297..600ef60fc5 100644 --- a/hw/loongarch/virt-acpi-build.c +++ b/hw/loongarch/virt-acpi-build.c @@ -128,7 +128,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, MachineClass *mc = MACHINE_GET_CLASS(ms); const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); int i, arch_id, flags; - AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id, + AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = lvms->oem_id, .oem_table_id = lvms->oem_table_id }; acpi_table_begin(&table, table_data); From c94267793c10ef111663d8c2e85e0331ff8a6800 Mon Sep 17 00:00:00 2001 From: Dongyan Qian Date: Tue, 4 Aug 2026 11:30:36 +0800 Subject: [PATCH 237/627] tests/acpi: Update LoongArch virt MADT Regenerate the APIC and APIC.topology test data after correcting the LoongArch virt MADT revision. The generated tables change only Header.Revision from 1 to 6 and the corresponding checksum. Their lengths and interrupt controller subtables remain unchanged. Signed-off-by: Dongyan Qian Signed-off-by: Bibo Mao Reviewed-by: Bibo Mao --- tests/data/acpi/loongarch64/virt/APIC | Bin 108 -> 108 bytes tests/data/acpi/loongarch64/virt/APIC.topology | Bin 153 -> 153 bytes tests/qtest/bios-tables-test-allowed-diff.h | 2 -- 3 files changed, 2 deletions(-) diff --git a/tests/data/acpi/loongarch64/virt/APIC b/tests/data/acpi/loongarch64/virt/APIC index 3477789f422cad54f16734b3ec9ad1ff5135165d..e90c267e1fdd83143edc732df41ca5659415090d 100644 GIT binary patch delta 16 Xcmd1F;c^V{bk1R5U|{<&kt+!RBvAxk delta 16 Xcmd1F;c^V{bk1R5U|{?@kt+!RBuoTf diff --git a/tests/data/acpi/loongarch64/virt/APIC.topology b/tests/data/acpi/loongarch64/virt/APIC.topology index da0089d57f608aca230a76b67e72f9f0ad8e71f2..d00b7241c7ad76867781d5649e2de5fb6a5f45bc 100644 GIT binary patch delta 18 ZcmbQqIFpgfF~HM#CIbTlTi`^legG=>1a<%b delta 18 ZcmbQqIFpgfF~HM#CIbTlW7tHlegG=+1a<%b diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 0e18673fcd..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,3 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/loongarch64/virt/APIC", -"tests/data/acpi/loongarch64/virt/APIC.topology", From 77b91aca6148fafcade41516f12a3309f1e1f552 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 14 Jul 2026 10:55:16 +0800 Subject: [PATCH 238/627] target/loongarch: Set timer tick value even if disabled If constant timer is enabled, its tick value is remained value from the next expired time. However if timer is not enabled, its value should be CONSTANT_TIMER_TICK_MASK or zero. Signed-off-by: Bibo Mao Reviewed-by: Xianglai Li --- target/loongarch/tcg/constant_timer.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/target/loongarch/tcg/constant_timer.c b/target/loongarch/tcg/constant_timer.c index f56e76d482..b91ad1de69 100644 --- a/target/loongarch/tcg/constant_timer.c +++ b/target/loongarch/tcg/constant_timer.c @@ -22,12 +22,18 @@ uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu) uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu) { + CPULoongArchState *env = &cpu->env; + CPUSysState *sys = env_sys(env); uint64_t now, expire; - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - expire = timer_expire_time_ns(&cpu->timer); + if ((sys->CSR_TCFG & CONSTANT_TIMER_ENABLE) && + (sys->CSR_TVAL < sys->CSR_TCFG)) { + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + expire = timer_expire_time_ns(&cpu->timer); + sys->CSR_TVAL = (expire - now) / TIMER_PERIOD; + } - return (expire - now) / TIMER_PERIOD; + return sys->CSR_TVAL; } void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, @@ -42,8 +48,10 @@ void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; timer_mod(&cpu->timer, next); + sys->CSR_TVAL = sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK; } else { timer_del(&cpu->timer); + sys->CSR_TVAL = 0; } } @@ -58,8 +66,9 @@ void loongarch_constant_timer_cb(void *opaque) now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); next = now + (sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD; timer_mod(&cpu->timer, next); + sys->CSR_TVAL = sys->CSR_TCFG & CONSTANT_TIMER_TICK_MASK; } else { - sys->CSR_TCFG = FIELD_DP64(sys->CSR_TCFG, CSR_TCFG, EN, 0); + sys->CSR_TVAL = CONSTANT_TIMER_TICK_MASK; } loongarch_cpu_set_irq(opaque, IRQ_TIMER, 1); From 10dd206e92e0f688b7aa411e57533448c56ab6b8 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 28 Jul 2026 17:04:17 -0400 Subject: [PATCH 239/627] migration/ram: Check for RAMBlock size mismatch when parsing Add an underflow check for the subtract of total RAMBlock size to make sure it won't underflow. It should not happen in production systems but only if the migration stream was hijacked, which is not a real concern since migration channel is trusted. Still protect against it. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4013 Reported-by: Tristan Madani Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/20260728210417.1925078-6-peterx@redhat.com Signed-off-by: Peter Xu --- migration/ram.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 8918b2f03b..b6eb842746 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4263,15 +4263,15 @@ static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) return ret; } -static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes) +static int parse_ramblocks(QEMUFile *f, uint64_t total_ram_bytes) { int ret = 0; /* Synchronize RAM block list */ - while (!ret && total_ram_bytes) { + while (total_ram_bytes) { RAMBlock *block; char id[256]; - ram_addr_t length; + uint64_t length; int len = qemu_get_byte(f); qemu_get_buffer(f, (uint8_t *)id, len); @@ -4285,8 +4285,15 @@ static int parse_ramblocks(QEMUFile *f, ram_addr_t total_ram_bytes) error_report("Unknown ramblock \"%s\", cannot accept " "migration", id); ret = -EINVAL; + break; + } + + if (usub64_overflow(total_ram_bytes, length, &total_ram_bytes)) { + error_report("%s: RAMBlock '%s' size underflow total RAM size", + __func__, block->idstr); + ret = -EFAULT; + break; } - total_ram_bytes -= length; } return ret; From 89f15c1362970150bf5711cdb84b9742c0db0cd8 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 12 Aug 2026 08:43:27 -0400 Subject: [PATCH 240/627] migration: Fix rare hang of migration_channel_read_peek() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In an unlikely case, when a migration stream is attached to the destination QEMU and only send <4 bytes to the channel as magic, it's possible that migration_channel_read_peek() may spin forever. Fix it by adding a manual sleep for partial read. Since the path isn't attached to a coroutine, it means when partial read happens, there's yet not much we can do but hang the main thread, it will happen even for len==0 case. It means monitors can hang due to this, either partial read or no data arrived (but connection established). Leave this for later, the hope is this is extremely rare in production. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3889 Reported-by: Feifan Qian Cc: Daniel P. Berrangé Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20260812124327.2572363-1-peterx@redhat.com Signed-off-by: Peter Xu --- migration/channel.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/migration/channel.c b/migration/channel.c index 1e2935f926..266ae8f776 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -296,9 +296,16 @@ int migration_channel_read_peek(QIOChannel *ioc, if (len == buflen) { break; + } else if (len == QIO_CHANNEL_ERR_BLOCK) { + qio_channel_wait_cond(ioc, G_IO_IN); + } else { + /* + * When partially ready, we can't use qio_channel_wait_cond() + * because it will return immediately. Apply a manual wait. + */ + assert(!qemu_in_coroutine()); + g_usleep(1000); } - - qio_channel_wait_cond(ioc, G_IO_IN); } return 0; From ebec7c73229831c6574c70fec3cc28c778566277 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:25:22 +0200 Subject: [PATCH 241/627] tests/qtest/ide-test: parametrize the ATAPI CD-ROM read test cdrom_pio_impl() and test_cdrom_dma() duplicate the same image setup and data-integrity check around two different transfer mechanisms. Fold them into a single cdrom_read_impl(nblocks, flags) helper, with a CDROM_PIO/CDROM_DMA flag selecting the transfer, so further read coverage can be added once for both paths. No functional change: /ide/cdrom/pio, pio_large and dma run exactly as before. Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 143 +++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 721e78170b..c97bc17b67 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1034,8 +1034,12 @@ static void ide_wait_intr(QTestState *qts, int irq) g_assert_not_reached(); } -static void cdrom_pio_impl(int nblocks) +#define CDROM_PIO 0 +#define CDROM_DMA (1 << 0) + +static void cdrom_read_impl(int nblocks, unsigned flags) { + bool dma = flags & CDROM_DMA; QTestState *qts; QPCIDevice *dev; QPCIBar bmdma_bar, ide_bar; @@ -1063,57 +1067,75 @@ static void cdrom_pio_impl(int nblocks) dev = get_pci_device(qts, &bmdma_bar, &ide_bar); qtest_irq_intercept_in(qts, "ioapic"); - /* PACKET command on device 0 */ - qpci_io_writeb(dev, ide_bar, reg_device, 0); - qpci_io_writeb(dev, ide_bar, reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF); - qpci_io_writeb(dev, ide_bar, reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF)); - qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET); - /* HP0: Check_Status_A State */ - nsleep(qts, 400); - data = ide_wait_clear(qts, BSY); - /* HP1: Send_Packet State */ - assert_bit_set(data, DRQ | DRDY); - assert_bit_clear(data, ERR | DF | BSY); + if (dma) { + uintptr_t guest_buf = guest_alloc(&guest_malloc, rxsize); + PrdtEntry prdt[1]; - /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */ - send_scsi_cdb_read10(dev, ide_bar, 0, nblocks); + prdt[0].addr = cpu_to_le32(guest_buf); + prdt[0].size = cpu_to_le32(rxsize | PRDT_EOT); - /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes. - * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes. - * We allow an odd limit only when the remaining transfer size is - * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only - * request n blocks, so our request size is always even. - * For this reason, we assume there is never a hanging byte to fetch. */ - g_assert(!(rxsize & 1)); - limit = BYTE_COUNT_LIMIT & ~1; - for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) { - size_t offset = i * (limit / 2); - size_t rem = (rxsize / 2) - offset; + send_dma_request_dev(qts, dev, bmdma_bar, ide_bar, CMD_PACKET, 0, + nblocks, prdt, ARRAY_SIZE(prdt), + send_scsi_cdb_read10); - /* HP3: INTRQ_Wait */ - ide_wait_intr(qts, IDE_PRIMARY_IRQ); - - /* HP2: Check_Status_B (and clear IRQ) */ + qtest_memread(qts, guest_buf, rx, rxsize); + } else { + /* PACKET command on device 0 */ + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF); + qpci_io_writeb(dev, ide_bar, reg_lba_high, + (BYTE_COUNT_LIMIT >> 8 & 0xFF)); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_PACKET); + /* HP0: Check_Status_A State */ + nsleep(qts, 400); data = ide_wait_clear(qts, BSY); + /* HP1: Send_Packet State */ assert_bit_set(data, DRQ | DRDY); assert_bit_clear(data, ERR | DF | BSY); - /* HP4: Transfer_Data */ - for (j = 0; j < MIN((limit / 2), rem); j++) { - rx[offset + j] = cpu_to_le16(qpci_io_readw(dev, ide_bar, - reg_data)); + /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */ + send_scsi_cdb_read10(dev, ide_bar, 0, nblocks); + + /* + * Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes. + * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes. + * We allow an odd limit only when the remaining transfer size is + * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only + * request n blocks, so our request size is always even. + * For this reason, we assume there is never a hanging byte to fetch. + */ + g_assert(!(rxsize & 1)); + limit = BYTE_COUNT_LIMIT & ~1; + for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) { + size_t offset = i * (limit / 2); + size_t rem = (rxsize / 2) - offset; + + /* HP3: INTRQ_Wait */ + ide_wait_intr(qts, IDE_PRIMARY_IRQ); + + /* HP2: Check_Status_B (and clear IRQ) */ + data = ide_wait_clear(qts, BSY); + assert_bit_set(data, DRQ | DRDY); + assert_bit_clear(data, ERR | DF | BSY); + + /* HP4: Transfer_Data */ + for (j = 0; j < MIN((limit / 2), rem); j++) { + rx[offset + j] = cpu_to_le16(qpci_io_readw(dev, ide_bar, + reg_data)); + } } + + /* Check for final completion IRQ */ + ide_wait_intr(qts, IDE_PRIMARY_IRQ); + + /* Sanity check final state */ + data = ide_wait_clear(qts, DRQ); + assert_bit_set(data, DRDY); + assert_bit_clear(data, DRQ | ERR | DF | BSY); } - /* Check for final completion IRQ */ - ide_wait_intr(qts, IDE_PRIMARY_IRQ); - - /* Sanity check final state */ - data = ide_wait_clear(qts, DRQ); - assert_bit_set(data, DRDY); - assert_bit_clear(data, DRQ | ERR | DF | BSY); - g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0); + g_free(pattern); g_free(rx); test_bmdma_teardown(qts); @@ -1122,51 +1144,18 @@ static void cdrom_pio_impl(int nblocks) static void test_cdrom_pio(void) { - cdrom_pio_impl(1); + cdrom_read_impl(1, CDROM_PIO); } static void test_cdrom_pio_large(void) { /* Test a few loops of the PIO DRQ mechanism. */ - cdrom_pio_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE); + cdrom_read_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE, CDROM_PIO); } - static void test_cdrom_dma(void) { - QTestState *qts; - static const size_t len = ATAPI_BLOCK_SIZE; - size_t ret; - char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16); - char *rx = g_malloc0(len); - uintptr_t guest_buf; - PrdtEntry prdt[1]; - FILE *fh; - - qts = ide_test_start( - "-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 " - "-device ide-cd,drive=sr0,bus=ide.0", tmp_path[0]); - qtest_irq_intercept_in(qts, "ioapic"); - - guest_buf = guest_alloc(&guest_malloc, len); - prdt[0].addr = cpu_to_le32(guest_buf); - prdt[0].size = cpu_to_le32(len | PRDT_EOT); - - generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE); - fh = fopen(tmp_path[0], "wb+"); - ret = fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh); - g_assert_cmpint(ret, ==, 16); - fclose(fh); - - send_dma_request(qts, CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10); - - /* Read back data from guest memory into local qtest memory */ - qtest_memread(qts, guest_buf, rx, len); - g_assert_cmpint(memcmp(pattern, rx, len), ==, 0); - - g_free(pattern); - g_free(rx); - test_bmdma_teardown(qts); + cdrom_read_impl(1, CDROM_DMA); } int main(int argc, char **argv) From fe543c2d787a611f1efa34107818a8eee90bb5dc Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:28:51 +0200 Subject: [PATCH 242/627] tests/qtest/ide-test: add a multi-sector ATAPI DMA read test test_cdrom_pio_large() already exercises a multi-sector PIO read. Add the DMA counterpart through the same cdrom_read_impl() helper so the multi-block ATAPI DMA read path gets equivalent coverage. Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index c97bc17b67..6e59197566 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1158,6 +1158,11 @@ static void test_cdrom_dma(void) cdrom_read_impl(1, CDROM_DMA); } +static void test_cdrom_dma_large(void) +{ + cdrom_read_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE, CDROM_DMA); +} + int main(int argc, char **argv) { const char *base; @@ -1217,6 +1222,7 @@ int main(int argc, char **argv) qtest_add_func("/ide/cdrom/pio", test_cdrom_pio); qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large); qtest_add_func("/ide/cdrom/dma", test_cdrom_dma); + qtest_add_func("/ide/cdrom/dma_large", test_cdrom_dma_large); ret = g_test_run(); From 502dbdfd9687e967dfe5eefce7123ecf9baa798c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:29:11 +0200 Subject: [PATCH 243/627] tests/qtest/ide-test: cover raw (2352-byte) ATAPI CD reads READ CD with the field-selector set to 0xf8 returns full 2352-byte raw sectors (sync + header + 2048 data + EDC/ECC), driving the ATAPI raw read path that READ10 never touches. Add a send_scsi_cdb_read_cd() helper and a CDROM_RAW flag to cdrom_read_impl(), then exercise both PIO and DMA. The PIO case uses a byte-count limit spanning several raw sectors so the device must rebuffer mid-burst, and each sector's 2048-byte payload is verified at its in-sector offset. Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 76 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 6e59197566..b36b0f8875 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -48,6 +48,10 @@ #define ATAPI_BLOCK_SIZE 2048 +/* Raw READ CD sector: 12 sync + 4 header + 2048 data + 288 EDC/ECC. */ +#define ATAPI_RAW_SIZE 2352 +#define ATAPI_RAW_DATA 16 + /* How many bytes to receive via ATAPI PIO at one time. * Must be less than 0xFFFF. */ #define BYTE_COUNT_LIMIT 5120 @@ -982,6 +986,41 @@ static void send_scsi_cdb_read10(QPCIDevice *dev, QPCIBar ide_bar, } } +typedef struct ReadCDCDB { + uint8_t opcode; + uint8_t sector_type; + uint32_t lba; + uint8_t length[3]; + uint8_t main_channel; + uint8_t sub_channel; + uint8_t control; +} __attribute__((__packed__)) ReadCDCDB; + +static void send_scsi_cdb_read_cd(QPCIDevice *dev, QPCIBar ide_bar, + uint64_t lba, int nblocks) +{ + ReadCDCDB pkt = { }; + int i; + + g_assert_cmpint(lba, <=, UINT32_MAX); + g_assert_cmpint(nblocks, >=, 0); + g_assert_cmpint(nblocks, <=, 0xffffff); + + /* Construct SCSI CDB packet */ + pkt.opcode = 0xbe; + pkt.lba = cpu_to_be32(lba); + pkt.length[0] = (nblocks >> 16) & 0xff; + pkt.length[1] = (nblocks >> 8) & 0xff; + pkt.length[2] = nblocks & 0xff; + pkt.main_channel = 0xf8; /* sync + headers + user data + EDC/ECC: 2352 */ + + /* Send Packet */ + for (i = 0; i < sizeof(ReadCDCDB) / 2; i++) { + qpci_io_writew(dev, ide_bar, reg_data, + le16_to_cpu(((uint16_t *)&pkt)[i])); + } +} + static void nsleep(QTestState *qts, int64_t nsecs) { const struct timespec val = { .tv_nsec = nsecs }; @@ -1036,10 +1075,12 @@ static void ide_wait_intr(QTestState *qts, int irq) #define CDROM_PIO 0 #define CDROM_DMA (1 << 0) +#define CDROM_RAW (1 << 1) static void cdrom_read_impl(int nblocks, unsigned flags) { bool dma = flags & CDROM_DMA; + bool raw = flags & CDROM_RAW; QTestState *qts; QPCIDevice *dev; QPCIBar bmdma_bar, ide_bar; @@ -1047,8 +1088,11 @@ static void cdrom_read_impl(int nblocks, unsigned flags) int patt_blocks = MAX(16, nblocks); size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks; char *pattern = g_malloc(patt_len); - size_t rxsize = ATAPI_BLOCK_SIZE * nblocks; + unsigned xfer = raw ? ATAPI_RAW_SIZE : ATAPI_BLOCK_SIZE; + size_t rxsize = xfer * nblocks; uint16_t *rx = g_malloc0(rxsize); + void (*send_cdb)(QPCIDevice *, QPCIBar, uint64_t, int) = + raw ? send_scsi_cdb_read_cd : send_scsi_cdb_read10; int i, j; uint8_t data; uint16_t limit; @@ -1075,8 +1119,7 @@ static void cdrom_read_impl(int nblocks, unsigned flags) prdt[0].size = cpu_to_le32(rxsize | PRDT_EOT); send_dma_request_dev(qts, dev, bmdma_bar, ide_bar, CMD_PACKET, 0, - nblocks, prdt, ARRAY_SIZE(prdt), - send_scsi_cdb_read10); + nblocks, prdt, ARRAY_SIZE(prdt), send_cdb); qtest_memread(qts, guest_buf, rx, rxsize); } else { @@ -1093,8 +1136,7 @@ static void cdrom_read_impl(int nblocks, unsigned flags) assert_bit_set(data, DRQ | DRDY); assert_bit_clear(data, ERR | DF | BSY); - /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */ - send_scsi_cdb_read10(dev, ide_bar, 0, nblocks); + send_cdb(dev, ide_bar, 0, nblocks); /* * Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes. @@ -1134,7 +1176,17 @@ static void cdrom_read_impl(int nblocks, unsigned flags) assert_bit_clear(data, DRQ | ERR | DF | BSY); } - g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0); + if (raw) { + /* The 2048-byte payload of each raw sector sits past its header. */ + for (i = 0; i < nblocks; i++) { + uint8_t *sec = (uint8_t *)rx + i * ATAPI_RAW_SIZE + ATAPI_RAW_DATA; + + g_assert_cmpint(memcmp(sec, pattern + i * ATAPI_BLOCK_SIZE, + ATAPI_BLOCK_SIZE), ==, 0); + } + } else { + g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0); + } g_free(pattern); g_free(rx); @@ -1163,6 +1215,16 @@ static void test_cdrom_dma_large(void) cdrom_read_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE, CDROM_DMA); } +static void test_cdrom_pio_raw(void) +{ + cdrom_read_impl(4, CDROM_RAW); +} + +static void test_cdrom_dma_raw(void) +{ + cdrom_read_impl(4, CDROM_DMA | CDROM_RAW); +} + int main(int argc, char **argv) { const char *base; @@ -1223,6 +1285,8 @@ int main(int argc, char **argv) qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large); qtest_add_func("/ide/cdrom/dma", test_cdrom_dma); qtest_add_func("/ide/cdrom/dma_large", test_cdrom_dma_large); + qtest_add_func("/ide/cdrom/pio_raw", test_cdrom_pio_raw); + qtest_add_func("/ide/cdrom/dma_raw", test_cdrom_dma_raw); ret = g_test_run(); From de86ef3dfd337ec5a74b43d7d042ab937d0166bf Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:29:11 +0200 Subject: [PATCH 244/627] tests/qtest/libqos/ahci: support raw (2352-byte) READ CD ahci_exec() always builds ATAPI commands with a 2048-byte logical sector size, so it cannot drive a READ CD that returns full 2352-byte raw sectors. Add an atapi_raw option that sets the READ CD field-selector to 0xf8 and the command's sector size to 2352 before the transfer is sized, so the derived block count stays correct while the buffer and byte counts cover the raw sectors. Signed-off-by: Denis V. Lunev --- tests/qtest/libqos/ahci.c | 5 +++++ tests/qtest/libqos/ahci.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/tests/qtest/libqos/ahci.c b/tests/qtest/libqos/ahci.c index 0621a6c477..e3019a1eca 100644 --- a/tests/qtest/libqos/ahci.c +++ b/tests/qtest/libqos/ahci.c @@ -707,6 +707,11 @@ void ahci_exec(AHCIQState *ahci, uint8_t port, if (opts->atapi) { uint16_t bcl = opts->set_bcl ? opts->bcl : ATAPI_SECTOR_SIZE; cmd = ahci_atapi_command_create(op, bcl, opts->atapi_dma); + if (opts->atapi_raw) { + /* request full 2352-byte raw sectors; sector_size must match */ + cmd->atapi_cmd[9] = 0xf8; + cmd->sector_size = ATAPI_RAW_SECTOR_SIZE; + } } else { cmd = ahci_command_create(op); } diff --git a/tests/qtest/libqos/ahci.h b/tests/qtest/libqos/ahci.h index a0487a1557..2a48a7523d 100644 --- a/tests/qtest/libqos/ahci.h +++ b/tests/qtest/libqos/ahci.h @@ -242,6 +242,7 @@ #define AHCI_SECTOR_SIZE (512) #define ATAPI_SECTOR_SIZE (2048) +#define ATAPI_RAW_SECTOR_SIZE (2352) #define AHCI_SIGNATURE_CDROM (0xeb140101) #define AHCI_SIGNATURE_DISK (0x00000101) @@ -485,6 +486,7 @@ typedef struct AHCIOpts { uint64_t buffer; /* Pointer to source or destination guest buffer */ bool atapi; /* ATAPI command? */ bool atapi_dma; /* Use DMA for ATAPI? */ + bool atapi_raw; /* READ CD returning 2352-byte raw sectors */ bool error; int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); From 31f13e71afd1cfb55b02c6977c829f0813ab439c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:29:12 +0200 Subject: [PATCH 245/627] tests/qtest/ahci: cover raw (2352-byte) ATAPI CD reads Add /ahci/cdrom/{pio,dma}/raw: read several sectors with READ CD in raw mode (atapi_raw), so the ATAPI 2352-byte unpack path is exercised through the AHCI delivery, which IDE coverage does not reach. Each sector's 2048-byte payload is verified at its in-sector offset. The PIO case uses a byte-count limit of one raw sector per DRQ burst: libqos asserts a one-sector PIO transfer, and the multi-sector unpack loop is already covered by the IDE raw test. Signed-off-by: Denis V. Lunev --- tests/qtest/ahci-test.c | 68 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 44799eea15..58bc04b3ef 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1565,6 +1565,31 @@ static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd, return 0; } +static int ahci_cb_cmp_raw(AHCIQState *ahci, AHCICommand *cmd, + const AHCIOpts *opts) +{ + unsigned char *tx = opts->opaque; + unsigned char *rx; + unsigned i, nsectors; + + if (!opts->size) { + return 0; + } + + nsectors = opts->size / ATAPI_RAW_SECTOR_SIZE; + rx = g_malloc0(opts->size); + qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size); + /* Each raw sector carries its 2048-byte payload past a 16-byte header. */ + for (i = 0; i < nsectors; i++) { + g_assert_cmphex(memcmp(rx + i * ATAPI_RAW_SECTOR_SIZE + 16, + tx + i * ATAPI_SECTOR_SIZE, + ATAPI_SECTOR_SIZE), ==, 0); + } + g_free(rx); + + return 0; +} + static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd, bool override_bcl, uint16_t bcl) { @@ -1625,6 +1650,47 @@ static void test_cdrom_pio_multi(void) ahci_test_cdrom_read10(3, false); } +static void ahci_test_cdrom_raw(int nsectors, bool dma) +{ + AHCIQState *ahci; + unsigned char *tx; + char *iso; + int fd; + AHCIOpts opts = { + .size = (uint64_t)ATAPI_RAW_SECTOR_SIZE * nsectors, + .atapi = true, + .atapi_dma = dma, + .atapi_raw = true, + .set_bcl = true, + .bcl = ATAPI_RAW_SECTOR_SIZE, /* one raw sector per DRQ burst */ + .post_cb = ahci_cb_cmp_raw, + }; + uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * (nsectors + 1); + + fd = prepare_iso(iso_size, &tx, &iso); + opts.opaque = tx; + + ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw " + "-M q35 " + "-device ide-cd,drive=drive0 ", iso); + + ahci_exec(ahci, ahci_port_select(ahci), CMD_ATAPI_READ_CD, &opts); + + g_free(tx); + ahci_shutdown(ahci); + remove_iso(fd, iso); +} + +static void test_cdrom_dma_raw(void) +{ + ahci_test_cdrom_raw(3, true); +} + +static void test_cdrom_pio_raw(void) +{ + ahci_test_cdrom_raw(3, false); +} + /* * Regression test: a buffered ATAPI read completing after a command * engine restart must not dereference the cleared cur_cmd. Cover both @@ -2100,8 +2166,10 @@ int main(int argc, char **argv) qtest_add_func("/ahci/cdrom/dma/single", test_cdrom_dma); qtest_add_func("/ahci/cdrom/dma/multi", test_cdrom_dma_multi); + qtest_add_func("/ahci/cdrom/dma/raw", test_cdrom_dma_raw); qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio); qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi); + qtest_add_func("/ahci/cdrom/pio/raw", test_cdrom_pio_raw); qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl); qtest_add_func("/ahci/cdrom/eject", test_atapi_tray); From 12289dc700d910bca4b79bb8de71acff06097489 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:29:48 +0200 Subject: [PATCH 246/627] hw/ide/atapi: read the whole elementary transfer asynchronously An ATAPI PIO read whose byte-count limit spans more than one CD sector must fetch the later sectors of a DRQ burst from inside the completion of the first, asynchronous read. cd_read_sector_sync() did this with a synchronous blk_pread(), which runs blk_wait_while_drained() before issuing the request. If a drain is in progress when that completion runs -- as happens when a guest reset reaches virtio_blk_stop_ioeventfd() -> bdrv_drain_all_begin() while an ATAPI read is in flight on the same QEMU -- the nested read is queued until the drained section ends while the outer completion still holds blk->in_flight. bdrv_drain_all_begin() then waits forever for that in_flight count to drop: the main loop is wedged in the drain with the BQL held, and every other QMP/monitor operation blocks behind it. Read the whole elementary transfer in a single asynchronous request up front instead, so no read is ever issued in the middle of a burst. cd_read_sector() now reads all the sectors a burst spans (the raw 2352-byte case is unpacked in place on completion) and cd_read_sector_sync() is removed. The DMA path already batched its reads and is unchanged. Signed-off-by: Denis V. Lunev --- hw/ide/atapi.c | 180 +++++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 96 deletions(-) diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index a42b748521..0ea149ad8c 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -88,46 +88,14 @@ static void cd_data_to_raw(uint8_t *buf, int lba) memset(buf, 0, 288); } -static int -cd_read_sector_sync(IDEState *s) -{ - int ret; - block_acct_start(blk_get_stats(s->blk), &s->acct, - ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); - - trace_cd_read_sector_sync(s->lba); - - switch (s->cd_sector_size) { - case 2048: - ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - ATAPI_SECTOR_SIZE, s->io_buffer, 0); - break; - case 2352: - ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - ATAPI_SECTOR_SIZE, s->io_buffer + 16, 0); - if (ret >= 0) { - cd_data_to_raw(s->io_buffer, s->lba); - } - break; - default: - block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ); - return -EIO; - } - - if (ret < 0) { - block_acct_failed(blk_get_stats(s->blk), &s->acct); - } else { - block_acct_done(blk_get_stats(s->blk), &s->acct); - s->lba++; - s->io_buffer_index = 0; - } - - return ret; -} - static void cd_read_sector_cb(void *opaque, int ret) { IDEState *s = opaque; + int et = s->elementary_transfer_size; + int skip = s->io_buffer_index; + int nsec = DIV_ROUND_UP(skip + et, s->cd_sector_size); + uint8_t *buf; + int i; trace_cd_read_sector_cb(s->lba, ret); @@ -140,34 +108,64 @@ static void cd_read_sector_cb(void *opaque, int ret) block_acct_done(blk_get_stats(s->blk), &s->acct); if (s->cd_sector_size == 2352) { - cd_data_to_raw(s->io_buffer, s->lba); + /* unpack back-to-front so a sector never clobbers an unmoved one */ + for (i = nsec - 1; i >= 0; i--) { + memmove(s->io_buffer + i * 2352 + 16, s->io_buffer + i * 2048, + ATAPI_SECTOR_SIZE); + cd_data_to_raw(s->io_buffer + i * 2352, s->lba + i); + } } - s->lba++; - s->io_buffer_index = 0; s->status &= ~BUSY_STAT; - ide_atapi_cmd_reply_end(s); + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + s->lcyl = et & 0xff; + s->hcyl = (et >> 8) & 0xff; + ide_bus_set_irq(s->bus); + + /* a boundary sector shared with the next burst is re-read there */ + buf = s->io_buffer + skip; + s->packet_transfer_size -= et; + s->lba += (skip + et) / s->cd_sector_size; + s->io_buffer_index = (skip + et) % s->cd_sector_size; + s->elementary_transfer_size = 0; + + if (ide_transfer_start_norecurse(s, buf, et, ide_atapi_cmd_reply_end)) { + ide_atapi_cmd_reply_end(s); + } } +/* + * Read the whole elementary transfer (one DRQ burst) in a single async + * request. No read is issued mid-burst, so unlike the old synchronous + * rebuffer it cannot deadlock against a concurrent drain. + */ static int cd_read_sector(IDEState *s) { - void *buf; + int et = s->elementary_transfer_size; + int skip = s->io_buffer_index; + int nsec = DIV_ROUND_UP(skip + et, s->cd_sector_size); if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) { block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ); return -EINVAL; } - buf = (s->cd_sector_size == 2352) ? s->io_buffer + 16 : s->io_buffer; - qemu_iovec_init_buf(&s->qiov, buf, ATAPI_SECTOR_SIZE); + /* a burst is bounded by the byte count limit, so it fits io_buffer */ + assert(nsec * s->cd_sector_size <= s->io_buffer_total_len); + + /* + * Read the payload packed at the front of io_buffer; the 2352 raw case is + * unpacked into place on completion. + */ + qemu_iovec_init_buf(&s->qiov, s->io_buffer, nsec * ATAPI_SECTOR_SIZE); trace_cd_read_sector(s->lba); block_acct_start(blk_get_stats(s->blk), &s->acct, - ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); + nsec * ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); - ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, 4, + ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, nsec * 4, cd_read_sector_cb, s); s->status |= BUSY_STAT; @@ -222,59 +220,49 @@ static uint16_t atapi_byte_count_limit(IDEState *s) void ide_atapi_cmd_reply_end(IDEState *s) { int byte_count_limit, size, ret; - while (s->packet_transfer_size > 0) { - trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size, - s->elementary_transfer_size, - s->io_buffer_index); - /* see if a new sector must be read */ - if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { - if (!s->elementary_transfer_size) { - ret = cd_read_sector(s); - if (ret < 0) { - ide_atapi_io_error(s, ret); - } - return; - } else { - /* rebuffering within an elementary transfer is - * only possible with a sync request because we - * end up with a race condition otherwise */ - ret = cd_read_sector_sync(s); - if (ret < 0) { - ide_atapi_io_error(s, ret); - return; - } + trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); + + if (s->lba != -1 && s->packet_transfer_size > 0) { + byte_count_limit = atapi_byte_count_limit(s); + trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit); + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) { + byte_count_limit--; } + size = byte_count_limit; } - if (s->elementary_transfer_size > 0) { - /* there are some data left to transmit in this elementary - transfer */ - size = s->cd_sector_size - s->io_buffer_index; - if (size > s->elementary_transfer_size) - size = s->elementary_transfer_size; - } else { - /* a new transfer is needed */ - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; - ide_bus_set_irq(s->bus); - byte_count_limit = atapi_byte_count_limit(s); - trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit); - size = s->packet_transfer_size; - if (size > byte_count_limit) { - /* byte count limit must be even if this case */ - if (byte_count_limit & 1) - byte_count_limit--; - size = byte_count_limit; - } - s->lcyl = size & 0xff; - s->hcyl = size >> 8; - s->elementary_transfer_size = size; - /* we cannot transmit more than one sector at a time */ - if (s->lba != -1) { - if (size > (s->cd_sector_size - s->io_buffer_index)) - size = (s->cd_sector_size - s->io_buffer_index); - } - trace_ide_atapi_cmd_reply_end_new(s, s->status); + s->elementary_transfer_size = size; + ret = cd_read_sector(s); + if (ret < 0) { + ide_atapi_io_error(s, ret); } + return; + } + + while (s->packet_transfer_size > 0) { + /* a new transfer is needed */ + s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; + ide_bus_set_irq(s->bus); + byte_count_limit = atapi_byte_count_limit(s); + trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit); + size = s->packet_transfer_size; + if (size > byte_count_limit) { + /* byte count limit must be even if this case */ + if (byte_count_limit & 1) { + byte_count_limit--; + } + size = byte_count_limit; + } + s->lcyl = size & 0xff; + s->hcyl = size >> 8; + s->elementary_transfer_size = size; + trace_ide_atapi_cmd_reply_end_new(s, s->status); + s->packet_transfer_size -= size; s->elementary_transfer_size -= size; s->io_buffer_index += size; @@ -329,7 +317,7 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, s->lba = lba; s->packet_transfer_size = nb_sectors * sector_size; s->elementary_transfer_size = 0; - s->io_buffer_index = sector_size; + s->io_buffer_index = 0; s->cd_sector_size = sector_size; ide_atapi_cmd_reply_end(s); From be1ee6a8f6e3b7192d57e900497b81a048f8d193 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 19 Jun 2026 02:31:11 +0200 Subject: [PATCH 247/627] tests/qtest/ahci: regression test for ATAPI read vs. drain Add /ahci/cdrom/drain/{pio,dma}: issue a multi-sector ATAPI read whose byte-count limit spans two sectors so the device must rebuffer in the middle of the DRQ burst, hold the backend read in flight with a blkdebug delay, and fire x-blockdev-set-iothread -- which runs bdrv_drain_all_begin() exactly like a guest reset does through virtio_blk_stop_ioeventfd(). On the unfixed PIO path the nested sector fetch is queued behind the drain and the main loop wedges, so the test hangs. The DMA variant never rebuffers and serves as a sanity twin. Signed-off-by: Denis V. Lunev --- tests/qtest/ahci-test.c | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 58bc04b3ef..71d23fe56a 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1754,6 +1754,70 @@ static void test_atapi_engine_restart_dma(void) test_atapi_engine_restart_in_flight(true); } +/* + * Regression test: a multi-sector ATAPI read fetches its later sectors from + * inside the first read's completion; a concurrent drain (as a guest reset + * triggers via bdrv_drain_all_begin) must not wedge on that nested read. + * blkdebug keeps the read in flight across x-blockdev-set-iothread. + */ +static void test_atapi_drain_in_flight(bool dma) +{ + AHCIQState *ahci; + AHCICommand *cmd; + unsigned char *tx; + char *iso; + int fd; + uint8_t port; + uint64_t buffer; + uint16_t bcl = ATAPI_SECTOR_SIZE * 2; + uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * 3; + + fd = prepare_iso(iso_size, &tx, &iso); + + /* 1s read delay: a wide margin so the drain starts before it completes */ + ahci = ahci_boot_and_enable( + "-blockdev driver=file,node-name=file0,filename=%s,read-only=on " + "-blockdev driver=blkdebug,node-name=cd0,image=file0,read-only=on," + "inject-error.0.event=none,inject-error.0.iotype=read," + "inject-error.0.errno=0,inject-error.0.delay-ns=1000000000 " + "-M q35 " + "-device ide-cd,drive=cd0 ", iso); + port = ahci_port_select(ahci); + + buffer = ahci_alloc(ahci, bcl); + qtest_memset(ahci->parent->qts, buffer, 0x00, bcl); + + cmd = ahci_atapi_command_create(CMD_ATAPI_READ_10, bcl, dma); + ahci_command_adjust(cmd, 0, buffer, bcl, 0); + ahci_command_commit(ahci, cmd, port); + ahci_command_issue_async(ahci, cmd); + + /* Drain (all nodes) while the delayed read is still in flight. */ + qtest_qmp_assert_success(ahci->parent->qts, + "{ 'execute': 'x-blockdev-set-iothread'," + " 'arguments': { 'node-name': 'cd0', 'iothread': null," + " 'force': true } }"); + + /* Round-trip through the device to confirm qemu is still alive. */ + ahci_px_rreg(ahci, port, AHCI_PX_TFD); + + ahci_command_free(cmd); + ahci_free(ahci, buffer); + g_free(tx); + ahci_shutdown(ahci); + remove_iso(fd, iso); +} + +static void test_atapi_drain_pio(void) +{ + test_atapi_drain_in_flight(false); +} + +static void test_atapi_drain_dma(void) +{ + test_atapi_drain_in_flight(true); +} + /* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0 * completes as a NOP instead of erroring out. */ static void test_atapi_bcl(void) @@ -2177,6 +2241,8 @@ int main(int argc, char **argv) test_atapi_engine_restart_pio); qtest_add_func("/ahci/cdrom/engine_restart/dma", test_atapi_engine_restart_dma); + qtest_add_func("/ahci/cdrom/drain/pio", test_atapi_drain_pio); + qtest_add_func("/ahci/cdrom/drain/dma", test_atapi_drain_dma); ret = g_test_run(); From ac84b9ec9604db04a5c3a5935eff8caf85d01597 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Jul 2026 12:12:52 +0300 Subject: [PATCH 248/627] tests/functional: add skipWithoutSudo() decorator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To be used in the next commit: that would be a test for TAP networking, and it will need to setup TAP device. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Tested-by: Lei Yang Reviewed-by: Maksim Davydov Reviewed-by: Ben Chaney Message-ID: <20260729091334.1863155-15-vsementsov@yandex-team.ru> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/decorators.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py index fcf236ecfd..aa135acc78 100644 --- a/tests/functional/qemu_test/decorators.py +++ b/tests/functional/qemu_test/decorators.py @@ -6,6 +6,7 @@ import importlib import os import platform import resource +import subprocess from unittest import skipIf, skipUnless from .cmd import which @@ -177,3 +178,18 @@ def skipLockedMemoryTest(locked_memory): ulimit_memory == resource.RLIM_INFINITY or ulimit_memory >= locked_memory * 1024, f'Test required {locked_memory} kB of available locked memory', ) + +''' +Decorator to skip execution of a test if passwordless +sudo command is not available. +''' +def skipWithoutSudo(): + proc = subprocess.run(["sudo", "-n", "/bin/true"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + check=False) + + return skipUnless(proc.returncode == 0, + f'requires password-less sudo access: {proc.stdout}') From c347711ea7f5b9cbcd558ecfaa81988e0baff359 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Jul 2026 12:31:42 +0300 Subject: [PATCH 249/627] tests/functional/qemu_test: drop *args argument from .get_vm() It's redundant. Only one caller use it, and it may be simply substituted by .add_args(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Thomas Huth Message-ID: <20260729093146.1893719-3-vsementsov@yandex-team.ru> Signed-off-by: Thomas Huth --- tests/functional/migration.py | 3 ++- tests/functional/qemu_test/testcase.py | 9 +++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/functional/migration.py b/tests/functional/migration.py index 4344e03be4..8d2428efc2 100644 --- a/tests/functional/migration.py +++ b/tests/functional/migration.py @@ -63,7 +63,8 @@ class MigrationTest(QemuSystemTest): self.assert_dest_vm(dst_vm) def migrate(self, dst_uri, src_uri=None): - dst_vm = self.get_vm('-incoming', 'defer', name="dst-qemu") + dst_vm = self.get_vm("dst-qemu") + dst_vm.add_args('-incoming', 'defer') self.configure_machine(dst_vm) dst_vm.launch() diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index e4179d165c..12ef84281c 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -381,7 +381,7 @@ class QemuSystemTest(QemuBaseTest): if helptxt.find(devicename) < 0: self.skipTest('no support for device ' + devicename) - def _new_vm(self, name, *args): + def _new_vm(self, name): vm = QEMUMachine(self.qemu_bin, name=name, base_temp_dir=self.workdir, @@ -394,20 +394,17 @@ class QemuSystemTest(QemuBaseTest): vm.add_args("-chardev", f"socket,id=backdoor,path={sockpath},server=on,wait=off", "-mon", "chardev=backdoor,mode=control") - - if args: - vm.add_args(*args) return vm @property def vm(self): return self.get_vm(name='default') - def get_vm(self, *args, name=None): + def get_vm(self, name=None): if not name: name = str(uuid.uuid4()) if self._vms.get(name) is None: - self._vms[name] = self._new_vm(name, *args) + self._vms[name] = self._new_vm(name) if self.cpu is not None: self._vms[name].add_args('-cpu', self.cpu) if self.machine is not None: From ba6741f63da565c739c038d267fd6d9132266597 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 29 Jul 2026 12:31:44 +0300 Subject: [PATCH 250/627] tests/testcase.py: passthrough monitor_address We'll need it soon to implement test for cpr-exec mode of tap-fd-migration. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Thomas Huth Message-ID: <20260729093146.1893719-5-vsementsov@yandex-team.ru> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/testcase.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 12ef84281c..69d3d06cc0 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -381,11 +381,12 @@ class QemuSystemTest(QemuBaseTest): if helptxt.find(devicename) < 0: self.skipTest('no support for device ' + devicename) - def _new_vm(self, name): + def _new_vm(self, name, monitor_address): vm = QEMUMachine(self.qemu_bin, name=name, base_temp_dir=self.workdir, - log_dir=self.log_file()) + log_dir=self.log_file(), + monitor_address=monitor_address) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) @@ -400,11 +401,11 @@ class QemuSystemTest(QemuBaseTest): def vm(self): return self.get_vm(name='default') - def get_vm(self, name=None): + def get_vm(self, name=None, monitor_address=None): if not name: name = str(uuid.uuid4()) if self._vms.get(name) is None: - self._vms[name] = self._new_vm(name) + self._vms[name] = self._new_vm(name, monitor_address) if self.cpu is not None: self._vms[name].add_args('-cpu', self.cpu) if self.machine is not None: From 15700a66ecb53c52717c913c2c4501372c0115ab Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Jul 2026 18:39:01 +0200 Subject: [PATCH 251/627] hw/usb/dev-uas: Don't abort if guest provided an undersized buffer for status QEMU currently aborts if the guest provides an undersized buffer for the status packet (8 bytes): hw/usb/core.c:623: usb_packet_copy: Assertion `p->actual_length + bytes <= iov->size' failed. If we hit this situation, log a guest error and continue by simply only providing the bytes that the guest asked for. (Note: This is e.g. similar to the UAS_PIPE_ID_COMMAND case that also clamps the length with: length = MIN(sizeof(iu), p->iov.size)) Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3900 Reported-by: Feifan Qian Signed-off-by: Thomas Huth Message-ID: <20260730163901.1154791-1-thuth@redhat.com> --- hw/usb/dev-uas.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 963c0433b3..be8c3667e8 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -359,6 +359,7 @@ static void usb_uas_send_status_bh(void *opaque) UASDevice *uas = opaque; UASStatus *st; USBPacket *p; + uint32_t length; while ((st = QTAILQ_FIRST(&uas->results)) != NULL) { if (uas_using_streams(uas)) { @@ -373,7 +374,14 @@ static void usb_uas_send_status_bh(void *opaque) break; } - usb_packet_copy(p, &st->status, st->length); + length = st->length; + if (length > p->iov.size) { + qemu_log_mask(LOG_GUEST_ERROR, + "usb uas: packet (%zd) too small for status (%d)\n", + p->iov.size, length); + length = p->iov.size; + } + usb_packet_copy(p, &st->status, length); QTAILQ_REMOVE(&uas->results, st, next); g_free(st); @@ -875,7 +883,14 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) break; } } - usb_packet_copy(p, &st->status, st->length); + length = st->length; + if (length > p->iov.size) { + qemu_log_mask(LOG_GUEST_ERROR, + "usb uas: packet (%zd) too small for status (%d)\n", + p->iov.size, length); + length = p->iov.size; + } + usb_packet_copy(p, &st->status, length); QTAILQ_REMOVE(&uas->results, st, next); g_free(st); break; From 46099d99005588b25eb07957cd9cdd688c4fc476 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 31 Jul 2026 13:33:52 +0200 Subject: [PATCH 252/627] hw/net/vmxnet3: Do not abort if guest provides bad interrupt numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vmxnet3_validate_interrupts() currently aborts via hw_error() if the guest provided bad interrupt numbers. This should not happen, QEMU should rather refuse to activate the device in this case instead. Thus propagate the error to the callers to handle it more gracefully there. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/539 Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20260731113352.189066-1-thuth@redhat.com> --- hw/net/vmxnet3.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 8569484b2f..24c551a054 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1336,32 +1336,46 @@ static bool vmxnet3_verify_intx(VMXNET3State *s, int intx) || intx == pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1; } -static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx) +static bool vmxnet3_validate_irq_idx(const char *type, bool is_msix, int idx) { int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS; + if (idx >= max_ints) { - hw_error("Bad interrupt index: %d\n", idx); + qemu_log_mask(LOG_GUEST_ERROR, + "vmxnet3: Bad %s queue interrupt index: %d\n", + type, idx); + return false; } + + return true; } -static void vmxnet3_validate_interrupts(VMXNET3State *s) +static bool vmxnet3_validate_interrupts(VMXNET3State *s) { int i; VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx); - vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx); + if (!vmxnet3_validate_irq_idx("event", s->msix_used, s->event_int_idx)) { + return false; + } for (i = 0; i < s->txq_num; i++) { int idx = s->txq_descr[i].intr_idx; VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx); - vmxnet3_validate_interrupt_idx(s->msix_used, idx); + if (!vmxnet3_validate_irq_idx("TX", s->msix_used, idx)) { + return false; + } } for (i = 0; i < s->rxq_num; i++) { int idx = s->rxq_descr[i].intr_idx; VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx); - vmxnet3_validate_interrupt_idx(s->msix_used, idx); + if (!vmxnet3_validate_irq_idx("RX", s->msix_used, idx)) { + return false; + } } + + return true; } static bool vmxnet3_validate_queues(VMXNET3State *s) @@ -1554,7 +1568,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) sizeof(s->rxq_descr[i].rxq_stats)); } - vmxnet3_validate_interrupts(s); + if (!vmxnet3_validate_interrupts(s)) { + return; + } /* Make sure everything is in place before device activation */ smp_wmb(); @@ -2392,7 +2408,9 @@ static int vmxnet3_post_load(void *opaque, int version_id) if (!vmxnet3_validate_queues(s)) { return -1; } - vmxnet3_validate_interrupts(s); + if (!vmxnet3_validate_interrupts(s)) { + return -1; + } return 0; } From 4adfb431c0c3abd84909d1228b4954bfd68a1dbc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 31 Jul 2026 16:02:29 +0200 Subject: [PATCH 253/627] hw/i386/amd_iommu: Avoid undefined behavior in amdvi_setevent_bits() The code in amdvi_encode_event() calls amdvi_setevent_bits() with start = 64: amdvi_setevent_bits(evt, addr, 64, 64); and amdvi_setevent_bits() then calculates: uint64_t mask = MAKE_64BIT_MASK(start, length); but this MAKE_64BIT_MASK() macro shifts a value left by "start" bit positions. Shifting left by more than 63 is undefined behavior and could have unexpected results with different compilers / architectures. Fix it by using "bitpos" instead, which was likely the original intended behavior anyway. (bitpos is calculated as bitpos = start % 64). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3633 Fixes: 1d5b128cbeea ("hw/iommu: Fix problems reported by Coverity scan") Reviewed-by: Alejandro Jimenez Signed-off-by: Thomas Huth Message-ID: <20260731140229.259272-1-thuth@redhat.com> --- hw/i386/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 90252c52af..578c27ccbe 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -323,7 +323,7 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start, int length) { int index = start / 64, bitpos = start % 64; - uint64_t mask = MAKE_64BIT_MASK(start, length); + uint64_t mask = MAKE_64BIT_MASK(bitpos, length); buffer[index] &= ~mask; buffer[index] |= (value << bitpos) & mask; } From 167882fe86d7b266bc7df27c58428ea40e10245d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:41 +0100 Subject: [PATCH 254/627] qom/object.c: introduce OBJECT_PROPERTY_SCALAR_GETTER(type) macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This macro can be used to generate the boilerplate property_get_type_ptr() QOM get function for the specified scalar type. Replace the existing scaler get functions with the new macro. Signed-off-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrangé Message-Id: <20260717135254.508701-2-mark.caveayland@nutanix.com> --- qom/object.c | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/qom/object.c b/qom/object.c index f79b2cf361..34aef7ca9f 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2661,12 +2661,20 @@ static char *object_get_type(Object *obj, Error **errp) return g_strdup(object_get_typename(obj)); } -static void property_get_uint8_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint8_t value = *(uint8_t *)opaque; - visit_type_uint8(v, name, &value, errp); -} + +#define OBJECT_PROPERTY_SCALAR_GETTER(type) \ + static void property_get_##type##_ptr(Object *obj, Visitor *v, \ + const char *name, \ + void *opaque, Error **errp) \ + { \ + type##_t value = *(type##_t *)opaque; \ + visit_type_##type(v, name, &value, errp); \ + } + +OBJECT_PROPERTY_SCALAR_GETTER(uint8) +OBJECT_PROPERTY_SCALAR_GETTER(uint16) +OBJECT_PROPERTY_SCALAR_GETTER(uint32) +OBJECT_PROPERTY_SCALAR_GETTER(uint64) static void property_set_uint8_ptr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -2681,13 +2689,6 @@ static void property_set_uint8_ptr(Object *obj, Visitor *v, const char *name, *field = value; } -static void property_get_uint16_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint16_t value = *(uint16_t *)opaque; - visit_type_uint16(v, name, &value, errp); -} - static void property_set_uint16_ptr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -2701,13 +2702,6 @@ static void property_set_uint16_ptr(Object *obj, Visitor *v, const char *name, *field = value; } -static void property_get_uint32_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint32_t value = *(uint32_t *)opaque; - visit_type_uint32(v, name, &value, errp); -} - static void property_set_uint32_ptr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -2721,13 +2715,6 @@ static void property_set_uint32_ptr(Object *obj, Visitor *v, const char *name, *field = value; } -static void property_get_uint64_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint64_t value = *(uint64_t *)opaque; - visit_type_uint64(v, name, &value, errp); -} - static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { From 5f8edcbc3ca0371b1ed0b38f7191ca91ef3cf7e4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:42 +0100 Subject: [PATCH 255/627] qom/object.c: introduce OBJECT_PROPERTY_SCALAR_SETTER(type) macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This macro can be used to generate the boilerplate property_set_type_ptr() QOM set function for the specified scalar type. Replace the existing scaler set functions with the new macro. Signed-off-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrangé Message-Id: <20260717135254.508701-3-mark.caveayland@nutanix.com> --- qom/object.c | 72 ++++++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 50 deletions(-) diff --git a/qom/object.c b/qom/object.c index 34aef7ca9f..8a1f80f613 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2671,62 +2671,34 @@ static char *object_get_type(Object *obj, Error **errp) visit_type_##type(v, name, &value, errp); \ } + +#define OBJECT_PROPERTY_SCALAR_SETTER(type) \ + static void property_set_##type##_ptr(Object *obj, Visitor *v, \ + const char *name, \ + void *opaque, Error **errp) \ + { \ + type##_t *field = opaque; \ + type##_t value; \ + \ + if (!visit_type_##type(v, name, &value, errp)) { \ + return; \ + } \ + \ + *field = value; \ + } + OBJECT_PROPERTY_SCALAR_GETTER(uint8) +OBJECT_PROPERTY_SCALAR_SETTER(uint8) OBJECT_PROPERTY_SCALAR_GETTER(uint16) +OBJECT_PROPERTY_SCALAR_SETTER(uint16) OBJECT_PROPERTY_SCALAR_GETTER(uint32) +OBJECT_PROPERTY_SCALAR_SETTER(uint32) OBJECT_PROPERTY_SCALAR_GETTER(uint64) +OBJECT_PROPERTY_SCALAR_SETTER(uint64) -static void property_set_uint8_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint8_t *field = opaque; - uint8_t value; +#undef OBJECT_PROPERTY_SCALAR_GETTER +#undef OBJECT_PROPERTY_SCALAR_SETTER - if (!visit_type_uint8(v, name, &value, errp)) { - return; - } - - *field = value; -} - -static void property_set_uint16_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint16_t *field = opaque; - uint16_t value; - - if (!visit_type_uint16(v, name, &value, errp)) { - return; - } - - *field = value; -} - -static void property_set_uint32_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint32_t *field = opaque; - uint32_t value; - - if (!visit_type_uint32(v, name, &value, errp)) { - return; - } - - *field = value; -} - -static void property_set_uint64_ptr(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - uint64_t *field = opaque; - uint64_t value; - - if (!visit_type_uint64(v, name, &value, errp)) { - return; - } - - *field = value; -} ObjectProperty * object_property_add_uint8_ptr(Object *obj, const char *name, From 361a15cff8ce13566d06c5954a92dbda1d24eb36 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:43 +0100 Subject: [PATCH 256/627] qom/object.c: introduce DEFINE_OBJECT_PROPERTY_SCALAR_METHODS() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This macro defines both the QOM get and set functions for the given scaler type. Replace the combined use of OBJECT_PROPERTY_SCALAR_GETTER() and OBJECT_PROPERTY_SCALAR_SETTER() with the new macro. Signed-off-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20260717135254.508701-4-mark.caveayland@nutanix.com> --- qom/object.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/qom/object.c b/qom/object.c index 8a1f80f613..622840f9f8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2687,17 +2687,20 @@ static char *object_get_type(Object *obj, Error **errp) *field = value; \ } -OBJECT_PROPERTY_SCALAR_GETTER(uint8) -OBJECT_PROPERTY_SCALAR_SETTER(uint8) -OBJECT_PROPERTY_SCALAR_GETTER(uint16) -OBJECT_PROPERTY_SCALAR_SETTER(uint16) -OBJECT_PROPERTY_SCALAR_GETTER(uint32) -OBJECT_PROPERTY_SCALAR_SETTER(uint32) -OBJECT_PROPERTY_SCALAR_GETTER(uint64) -OBJECT_PROPERTY_SCALAR_SETTER(uint64) + +#define DEFINE_OBJECT_PROPERTY_SCALAR_METHODS(type) \ + OBJECT_PROPERTY_SCALAR_GETTER(type) \ + OBJECT_PROPERTY_SCALAR_SETTER(type) + + +DEFINE_OBJECT_PROPERTY_SCALAR_METHODS(uint8) +DEFINE_OBJECT_PROPERTY_SCALAR_METHODS(uint16) +DEFINE_OBJECT_PROPERTY_SCALAR_METHODS(uint32) +DEFINE_OBJECT_PROPERTY_SCALAR_METHODS(uint64) #undef OBJECT_PROPERTY_SCALAR_GETTER #undef OBJECT_PROPERTY_SCALAR_SETTER +#undef DEFINE_OBJECT_PROPERTY_SCALAR_METHODS ObjectProperty * From 504be94fe34262fe04d5e36333432169741a740c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:44 +0100 Subject: [PATCH 257/627] qom/object.h: rename @child to @targetp in object_property_add_link() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was missed when updating the parameter name in commit 36854207f0 ("object: rename link "child" to "target""). Signed-off-by: Mark Cave-Ayland Fixes: 36854207f0 ("object: rename link "child" to "target"") Reviewed-by: Daniel P. Berrangé Message-Id: <20260717135254.508701-5-mark.caveayland@nutanix.com> --- include/qom/object.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 11f55613fc..4e7fe2af7c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1802,8 +1802,8 @@ void object_property_allow_set_link(const Object *obj, const char *name, * property is read-only and cannot be set. Care must be taken to handle NULL * values for @val. * - * Ownership of the pointer that @child points to is transferred to the - * link property. The reference count for *@child is + * Ownership of the pointer that @targetp points to is transferred to the + * link property. The reference count for *@targetp is * managed by the property from after the function returns till the * property is deleted with object_property_del(). If the * @flags %OBJ_PROP_LINK_STRONG bit is set, From 478542dd83ad805e1f7c9676a91541bf4aa9fd5d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:45 +0100 Subject: [PATCH 258/627] qom/object.h: add missing documentation for object_class_* property functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is so that the object_class_* property functions appear in the generated QOM documentation at devel/qom-api.html. Signed-off-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrangé Message-Id: <20260717135254.508701-6-mark.caveayland@nutanix.com> --- include/qom/object.h | 136 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 4e7fe2af7c..272c41cac7 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1818,6 +1818,33 @@ ObjectProperty *object_property_add_link(Object *obj, const char *name, Object *val, Error **errp), ObjectPropertyLinkFlags flags); +/** + * object_class_property_add_link: + * @oc: the object class to add a property to + * @name: the name of the property + * @type: the qobj type of the link + * @offset: the offset from the object instance where the link object reference + * is stored + * @check: callback to veto setting or NULL if the property is read-only + * @flags: additional options for the link + * + * Links establish relationships between objects. Links are unidirectional + * although two links can be combined to form a bidirectional relationship + * between objects. + * + * Links form the graph in the object model. + * + * The @check() callback is invoked when object_property_set_link() is called + * and can raise an error to prevent the link being set. If @check is NULL, the + * property is read-only and cannot be set. Care must be taken to handle NULL + * values for @val. + * + * If the @flags %OBJ_PROP_LINK_STRONG bit is set, the reference count of the + * linked object is incremented when the property is set, and decremented again + * when the property is modified. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_link(ObjectClass *oc, const char *name, const char *type, ptrdiff_t offset, @@ -1859,6 +1886,19 @@ ObjectProperty *object_property_add_str(Object *obj, const char *name, char *(*get)(Object *, Error **), void (*set)(Object *, const char *, Error **)); +/** + * object_class_property_add_str: + * @klass: the object class to add a property to + * @name: the name of the property + * @get: the getter or NULL if the property is write-only. This function must + * return a string to be freed by g_free(). + * @set: the setter or NULL if the property is read-only + * + * Add a string property using getters/setters. This function will add a + * property of type 'string'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_str(ObjectClass *klass, const char *name, char *(*get)(Object *, Error **), @@ -1881,6 +1921,18 @@ ObjectProperty *object_property_add_bool(Object *obj, const char *name, bool (*get)(Object *, Error **), void (*set)(Object *, bool, Error **)); +/** + * object_class_property_add_bool: + * @klass: the object class to add a property to + * @name: the name of the property + * @get: the getter or NULL if the property is write-only. + * @set: the setter or NULL if the property is read-only + * + * Add a bool property using getters/setters. This function will add a + * property of type 'bool'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_bool(ObjectClass *klass, const char *name, bool (*get)(Object *, Error **), @@ -1906,6 +1958,20 @@ ObjectProperty *object_property_add_enum(Object *obj, const char *name, int (*get)(Object *, Error **), void (*set)(Object *, int, Error **)); +/** + * object_class_property_add_enum: + * @klass: the object class to add a property to + * @name: the name of the property + * @typename: the name of the enum data type + * @lookup: enum value namelookup table + * @get: the getter or %NULL if the property is write-only. + * @set: the setter or %NULL if the property is read-only + * + * Add an enum property using getters/setters. This function will add a + * property of type '@typename'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_enum(ObjectClass *klass, const char *name, const char *typename, @@ -1927,6 +1993,17 @@ ObjectProperty *object_class_property_add_enum(ObjectClass *klass, ObjectProperty *object_property_add_tm(Object *obj, const char *name, void (*get)(Object *, struct tm *, Error **)); +/** + * object_class_property_add_tm: + * @klass: the object class to add a property to + * @name: the name of the property + * @get: the getter or NULL if the property is write-only. + * + * Add a read-only struct tm valued property using a getter function. + * This function will add a property of type 'struct tm'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_tm(ObjectClass *klass, const char *name, void (*get)(Object *, struct tm *, Error **)); @@ -1956,6 +2033,18 @@ ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, const uint8_t *v, ObjectPropertyFlags flags); +/** + * object_class_property_add_uint8_ptr: + * @klass: the object class to add a property to + * @name: the name of the property + * @v: pointer to value + * @flags: bitwise-or'd ObjectPropertyFlags + * + * Add an integer property in memory. This function will add a + * property of type 'uint8'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, @@ -1977,6 +2066,18 @@ ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, const uint16_t *v, ObjectPropertyFlags flags); +/** + * object_class_property_add_uint16_ptr: + * @klass: the object class to add a property to + * @name: the name of the property + * @v: pointer to value + * @flags: bitwise-or'd ObjectPropertyFlags + * + * Add an integer property in memory. This function will add a + * property of type 'uint16'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, @@ -1998,6 +2099,18 @@ ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, const uint32_t *v, ObjectPropertyFlags flags); +/** + * object_class_property_add_uint32_ptr: + * @klass: the object class to add a property to + * @name: the name of the property + * @v: pointer to value + * @flags: bitwise-or'd ObjectPropertyFlags + * + * Add an integer property in memory. This function will add a + * property of type 'uint32'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, @@ -2019,6 +2132,18 @@ ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, const uint64_t *v, ObjectPropertyFlags flags); +/** + * object_class_property_add_uint64_ptr: + * @klass: the object class to add a property to + * @name: the name of the property + * @v: pointer to value + * @flags: bitwise-or'd ObjectPropertyFlags + * + * Add an integer property in memory. This function will add a + * property of type 'uint64'. + * + * Returns: The newly added property on success, or %NULL on failure. + */ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, @@ -2075,6 +2200,17 @@ ObjectProperty *object_property_add_const_link(Object *obj, const char *name, */ void object_property_set_description(Object *obj, const char *name, const char *description); + +/** + * object_class_property_set_description: + * @klass: the object class owning the property + * @name: the name of the property + * @description: the description of the property on the object + * + * Set an object property's description. + * + * Returns: %true on success, %false on failure. + */ void object_class_property_set_description(ObjectClass *klass, const char *name, const char *description); From 6b97f3d4d6a5c3017f6f7655019097c777f5eb86 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 17 Jul 2026 14:51:46 +0100 Subject: [PATCH 259/627] qom/object.c: rename object_class_property_uint*_ptr() to object_class_static_property_uint*_ptr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This more accurately reflects that these properties are held within the class and not the object. Update the documentation to describe the few cases where static properties should be used. Signed-off-by: Mark Cave-Ayland Reviewed-by: Daniel P. Berrangé Message-Id: <20260717135254.508701-7-mark.caveayland@nutanix.com> --- hw/riscv/spike.c | 5 ++-- include/qom/object.h | 56 +++++++++++++++++++++++++++++++------------- qom/object.c | 28 ++++++++++++---------- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 9fde0faf39..630b65f569 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -278,8 +278,9 @@ static void spike_machine_class_init(ObjectClass *oc, const void *data) object_class_property_add_str(oc, "signature", NULL, spike_set_signature); object_class_property_set_description(oc, "signature", "File to write ACT test signature"); - object_class_property_add_uint8_ptr(oc, "signature-granularity", - &line_size, OBJ_PROP_FLAG_WRITE); + object_class_static_property_add_uint8_ptr(oc, "signature-granularity", + &line_size, + OBJ_PROP_FLAG_WRITE); object_class_property_set_description(oc, "signature-granularity", "Size of each line in ACT signature " "file"); diff --git a/include/qom/object.h b/include/qom/object.h index 272c41cac7..11b1c9d2dc 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -2034,18 +2034,24 @@ ObjectProperty *object_property_add_uint8_ptr(Object *obj, const char *name, ObjectPropertyFlags flags); /** - * object_class_property_add_uint8_ptr: - * @klass: the object class to add a property to + * object_class_static_property_add_uint8_ptr: + * @klass: the object class to add a static property to * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags * - * Add an integer property in memory. This function will add a + * Add a static integer property in memory. This function will add a * property of type 'uint8'. * + * A static property is one which is stored outside of the object instance, + * typically in global variables. It is only appropriate to use static + * properties when the class is designed as a singleton. If there is a + * possibility of multiple instances, then properties must be stored + * per-instance. + * * Returns: The newly added property on success, or %NULL on failure. */ -ObjectProperty *object_class_property_add_uint8_ptr(ObjectClass *klass, +ObjectProperty *object_class_static_property_add_uint8_ptr(ObjectClass *klass, const char *name, const uint8_t *v, ObjectPropertyFlags flags); @@ -2067,18 +2073,24 @@ ObjectProperty *object_property_add_uint16_ptr(Object *obj, const char *name, ObjectPropertyFlags flags); /** - * object_class_property_add_uint16_ptr: - * @klass: the object class to add a property to + * object_class_static_property_add_uint16_ptr: + * @klass: the object class to add a static property to * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags * - * Add an integer property in memory. This function will add a + * Add a static integer property in memory. This function will add a * property of type 'uint16'. * + * A static property is one which is stored outside of the object instance, + * typically in global variables. It is only appropriate to use static + * properties when the class is designed as a singleton. If there is a + * possibility of multiple instances, then properties must be stored + * per-instance. + * * Returns: The newly added property on success, or %NULL on failure. */ -ObjectProperty *object_class_property_add_uint16_ptr(ObjectClass *klass, +ObjectProperty *object_class_static_property_add_uint16_ptr(ObjectClass *klass, const char *name, const uint16_t *v, ObjectPropertyFlags flags); @@ -2100,18 +2112,24 @@ ObjectProperty *object_property_add_uint32_ptr(Object *obj, const char *name, ObjectPropertyFlags flags); /** - * object_class_property_add_uint32_ptr: - * @klass: the object class to add a property to + * object_class_static_property_add_uint32_ptr: + * @klass: the object class to add a static property to * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags * - * Add an integer property in memory. This function will add a + * Add a static integer property in memory. This function will add a * property of type 'uint32'. * + * A static property is one which is stored outside of the object instance, + * typically in global variables. It is only appropriate to use static + * properties when the class is designed as a singleton. If there is a + * possibility of multiple instances, then properties must be stored + * per-instance. + * * Returns: The newly added property on success, or %NULL on failure. */ -ObjectProperty *object_class_property_add_uint32_ptr(ObjectClass *klass, +ObjectProperty *object_class_static_property_add_uint32_ptr(ObjectClass *klass, const char *name, const uint32_t *v, ObjectPropertyFlags flags); @@ -2133,18 +2151,24 @@ ObjectProperty *object_property_add_uint64_ptr(Object *obj, const char *name, ObjectPropertyFlags flags); /** - * object_class_property_add_uint64_ptr: - * @klass: the object class to add a property to + * object_class_static_property_add_uint64_ptr: + * @klass: the object class to add a static property to * @name: the name of the property * @v: pointer to value * @flags: bitwise-or'd ObjectPropertyFlags * - * Add an integer property in memory. This function will add a + * Add a static integer property in memory. This function will add a * property of type 'uint64'. * + * A static property is one which is stored outside of the object instance, + * typically in global variables. It is only appropriate to use static + * properties when the class is designed as a singleton. If there is a + * possibility of multiple instances, then properties must be stored + * per-instance. + * * Returns: The newly added property on success, or %NULL on failure. */ -ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass, +ObjectProperty *object_class_static_property_add_uint64_ptr(ObjectClass *klass, const char *name, const uint64_t *v, ObjectPropertyFlags flags); diff --git a/qom/object.c b/qom/object.c index 622840f9f8..47977b1f44 100644 --- a/qom/object.c +++ b/qom/object.c @@ -2724,9 +2724,10 @@ object_property_add_uint8_ptr(Object *obj, const char *name, } ObjectProperty * -object_class_property_add_uint8_ptr(ObjectClass *klass, const char *name, - const uint8_t *v, - ObjectPropertyFlags flags) +object_class_static_property_add_uint8_ptr(ObjectClass *klass, + const char *name, + const uint8_t *v, + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2764,9 +2765,10 @@ object_property_add_uint16_ptr(Object *obj, const char *name, } ObjectProperty * -object_class_property_add_uint16_ptr(ObjectClass *klass, const char *name, - const uint16_t *v, - ObjectPropertyFlags flags) +object_class_static_property_add_uint16_ptr(ObjectClass *klass, + const char *name, + const uint16_t *v, + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2804,9 +2806,10 @@ object_property_add_uint32_ptr(Object *obj, const char *name, } ObjectProperty * -object_class_property_add_uint32_ptr(ObjectClass *klass, const char *name, - const uint32_t *v, - ObjectPropertyFlags flags) +object_class_static_property_add_uint32_ptr(ObjectClass *klass, + const char *name, + const uint32_t *v, + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; @@ -2844,9 +2847,10 @@ object_property_add_uint64_ptr(Object *obj, const char *name, } ObjectProperty * -object_class_property_add_uint64_ptr(ObjectClass *klass, const char *name, - const uint64_t *v, - ObjectPropertyFlags flags) +object_class_static_property_add_uint64_ptr(ObjectClass *klass, + const char *name, + const uint64_t *v, + ObjectPropertyFlags flags) { ObjectPropertyAccessor *getter = NULL; ObjectPropertyAccessor *setter = NULL; From a2deb54e7efc94ddb609c66f90bcaed5f9fbf6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 3 Feb 2023 10:55:51 +0100 Subject: [PATCH 260/627] hw/qdev: Remove DEFINE_PROP_DMAADDR() and 'hw/qdev-dma.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DEFINE_PROP_DMAADDR() is only used once. Since it doesn't add much value, simply remove it, along with the header defining it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Markus Armbruster Message-Id: <20230203145536.17585-14-philmd@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/usb/hcd-ohci-pci.c | 1 - hw/usb/hcd-ohci-sysbus.c | 3 +-- hw/usb/hcd-ohci.c | 1 - include/hw/core/qdev-dma.h | 16 ---------------- 4 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 include/hw/core/qdev-dma.h diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c index 18b58f5fcb..70c9e9ac4f 100644 --- a/hw/usb/hcd-ohci-pci.c +++ b/hw/usb/hcd-ohci-pci.c @@ -25,7 +25,6 @@ #include "migration/vmstate.h" #include "hw/pci/pci_device.h" #include "hw/core/sysbus.h" -#include "hw/core/qdev-dma.h" #include "hw/core/qdev-properties.h" #include "trace.h" #include "hcd-ohci.h" diff --git a/hw/usb/hcd-ohci-sysbus.c b/hw/usb/hcd-ohci-sysbus.c index 1a2cf29bed..4f51eebccb 100644 --- a/hw/usb/hcd-ohci-sysbus.c +++ b/hw/usb/hcd-ohci-sysbus.c @@ -26,7 +26,6 @@ #include "hw/usb/usb.h" #include "migration/vmstate.h" #include "hw/core/sysbus.h" -#include "hw/core/qdev-dma.h" #include "hw/core/qdev-properties.h" #include "trace.h" #include "hcd-ohci.h" @@ -61,7 +60,7 @@ static const Property ohci_sysbus_properties[] = { DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0), - DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), + DEFINE_PROP_UINT64("dma-offset", OHCISysBusState, dma_offset, 0), }; static void ohci_sysbus_class_init(ObjectClass *klass, const void *data) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index c4a9741bd4..23990115ab 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -34,7 +34,6 @@ #include "hw/usb/usb.h" #include "migration/vmstate.h" #include "hw/core/sysbus.h" -#include "hw/core/qdev-dma.h" #include "hw/core/qdev-properties.h" #include "trace.h" #include "hcd-ohci.h" diff --git a/include/hw/core/qdev-dma.h b/include/hw/core/qdev-dma.h deleted file mode 100644 index b00391aa0c..0000000000 --- a/include/hw/core/qdev-dma.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Support for dma_addr_t typed properties - * - * Copyright (C) 2012 David Gibson, IBM Corporation. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef HW_QDEV_DMA_H -#define HW_QDEV_DMA_H - -#define DEFINE_PROP_DMAADDR(_n, _s, _f, _d) \ - DEFINE_PROP_UINT64(_n, _s, _f, _d) - -#endif From d6c6d5500c998d3db83b334c95a3efb4eef905ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 16 Jun 2026 00:37:56 +0400 Subject: [PATCH 261/627] hw/mem/nvdimm: fix "size" property typename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The getter/setter use visit_type_size(). Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260616-qom-qapi-v2-30-cc9396b9c18c@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/mem/nvdimm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index b703252527..cf8a4d8c5f 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -99,7 +99,7 @@ static void nvdimm_set_uuid(Object *obj, Visitor *v, const char *name, static void nvdimm_init(Object *obj) { - object_property_add(obj, NVDIMM_LABEL_SIZE_PROP, "int", + object_property_add(obj, NVDIMM_LABEL_SIZE_PROP, "size", nvdimm_get_label_size, nvdimm_set_label_size, NULL, NULL); From f9aea61a19ee54be962daafdd10da2ea8f5f1aa8 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:52 +0900 Subject: [PATCH 262/627] qdev: Make qdev_is_realized() take a const DeviceState * MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qdev_is_realized() only reads DeviceState. Make its parameter const so a later caller with a const DeviceState * can use it. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-2-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- include/hw/core/qdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index e147622341..37f7d33551 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -437,7 +437,7 @@ DeviceState *qdev_try_new(const char *name); * Context: May be called outside big qemu lock. * Return: true if the device has been fully constructed, false otherwise. */ -static inline bool qdev_is_realized(DeviceState *dev) +static inline bool qdev_is_realized(const DeviceState *dev) { return qatomic_load_acquire(&dev->realized); } From 1fbfec36db010b43fa36dba4c90db48752965eaa Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:53 +0900 Subject: [PATCH 263/627] hw/hyperv/balloon: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-3-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/hyperv/hv-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c index 9dd759f11e..b8664a246b 100644 --- a/hw/hyperv/hv-balloon.c +++ b/hw/hyperv/hv-balloon.c @@ -197,7 +197,7 @@ static int build_dimm_list(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_PC_DIMM)) { DeviceState *dev = DEVICE(obj); - if (dev->realized) { /* only realized DIMMs matter */ + if (qdev_is_realized(dev)) { /* only realized DIMMs matter */ *list = g_slist_prepend(*list, dev); } } From b341bc3be85c06af6de56153d59381dcaf2e5b2e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:54 +0900 Subject: [PATCH 264/627] hw/intc/apic: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-4-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/intc/apic_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 49c03a5bce..0f0f37d457 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -424,7 +424,7 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name, DeviceState *dev = DEVICE(obj); uint32_t value; - if (dev->realized) { + if (qdev_is_realized(dev)) { qdev_prop_set_after_realize(dev, name, errp); return; } From 9cc59476bbbf4b4b32ad32fe4b396059d7a7cdf6 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:55 +0900 Subject: [PATCH 265/627] hw/mem/memory-device: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-5-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/mem/memory-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 9cf82b84cf..24bebfb6b3 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -59,7 +59,7 @@ static int memory_device_build_list(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { DeviceState *dev = DEVICE(obj); - if (dev->realized) { /* only realized memory devices matter */ + if (qdev_is_realized(dev)) { *list = g_slist_insert_sorted(*list, dev, memory_device_addr_sort); } } @@ -326,7 +326,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque) const MemoryDeviceState *md = MEMORY_DEVICE(obj); const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); - if (dev->realized && !memory_device_is_empty(md)) { + if (qdev_is_realized(dev) && !memory_device_is_empty(md)) { *size += mdc->get_plugged_size(md, &error_abort); } } From 4ef1d02325e131bde790a710925b974378e7072f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:56 +0900 Subject: [PATCH 266/627] hw/mem/pc-dimm: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-6-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/mem/pc-dimm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 3efe47f499..68862926ee 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -103,7 +103,7 @@ static int pc_dimm_slot2bitmap(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_PC_DIMM)) { DeviceState *dev = DEVICE(obj); - if (dev->realized) { /* count only realized DIMMs */ + if (qdev_is_realized(dev)) { /* count only realized DIMMs */ PCDIMMDevice *d = PC_DIMM(obj); set_bit(d->slot, bitmap); } From 56258e616f0e45bed3e1346f32c7472f7d550d2e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:57 +0900 Subject: [PATCH 267/627] hw/nvram: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-7-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/nvram/xlnx-bbram.c | 2 +- hw/nvram/xlnx-efuse.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c index edfb592a5e..e336874bde 100644 --- a/hw/nvram/xlnx-bbram.c +++ b/hw/nvram/xlnx-bbram.c @@ -468,7 +468,7 @@ static void bbram_prop_set_drive(Object *obj, Visitor *v, const char *name, qdev_prop_drive.set(obj, v, name, opaque, errp); /* Fill initial data if backend is attached after realized */ - if (dev->realized) { + if (qdev_is_realized(dev)) { bbram_bdrv_read(XLNX_BBRAM(obj), errp); } } diff --git a/hw/nvram/xlnx-efuse.c b/hw/nvram/xlnx-efuse.c index 1a9650ba12..03c9fbc0d0 100644 --- a/hw/nvram/xlnx-efuse.c +++ b/hw/nvram/xlnx-efuse.c @@ -233,7 +233,7 @@ static void efuse_prop_set_drive(Object *obj, Visitor *v, const char *name, qdev_prop_drive.set(obj, v, name, opaque, errp); /* Fill initial data if backend is attached after realized */ - if (dev->realized) { + if (qdev_is_realized(dev)) { efuse_bdrv_read(XLNX_EFUSE(obj), errp); } } From f80ce4a6541b406a896410af12690b2b3148badc Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:58 +0900 Subject: [PATCH 268/627] hw/ppc/pnv_xscom: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-8-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/ppc/pnv_xscom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index dc1ffc6c01..7af722584e 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -253,7 +253,7 @@ static int xscom_dt_child(Object *child, void *opaque) /* * Only "realized" devices should be configured in the DT */ - if (xc->dt_xscom && DEVICE(child)->realized) { + if (xc->dt_xscom && qdev_is_realized(DEVICE(child))) { _FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset))); } } From 30068ef7467ef51becbb4dce946bdf917f0f0981 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:16:59 +0900 Subject: [PATCH 269/627] hw/vfio: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-9-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/vfio/container-legacy.c | 4 ++-- hw/vfio/device.c | 4 ++-- hw/vfio/iommufd.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/vfio/container-legacy.c b/hw/vfio/container-legacy.c index d301b27aa6..7ac7b37214 100644 --- a/hw/vfio/container-legacy.c +++ b/hw/vfio/container-legacy.c @@ -1075,7 +1075,7 @@ static int vfio_legacy_pci_hot_reset(VFIODevice *vbasedev, bool single) /* Prep dependent devices for reset and clear our marker. */ QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (!vbasedev_iter->dev->realized || + if (!qdev_is_realized(vbasedev_iter->dev) || !vfio_pci_from_vfio_device(vbasedev_iter)) { continue; } @@ -1160,7 +1160,7 @@ out: } QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { - if (!vbasedev_iter->dev->realized || + if (!qdev_is_realized(vbasedev_iter->dev) || !vfio_pci_from_vfio_device(vbasedev_iter)) { continue; } diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 1a7f8088aa..4f11959633 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -59,13 +59,13 @@ void vfio_device_reset_handler(void *opaque) trace_vfio_device_reset_handler(); QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->dev->realized) { + if (qdev_is_realized(vbasedev->dev)) { vbasedev->ops->vfio_compute_needs_reset(vbasedev); } } QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->dev->realized && vbasedev->needs_reset) { + if (qdev_is_realized(vbasedev->dev) && vbasedev->needs_reset) { vbasedev->ops->vfio_hot_reset_multi(vbasedev); } } diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 6ff668d259..242644aa00 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -829,7 +829,7 @@ iommufd_cdev_dep_get_realized_vpdev(struct vfio_pci_dependent_device *dep_dev, vbasedev_tmp = iommufd_cdev_pci_find_by_devid(dep_dev->devid); if (!vfio_pci_from_vfio_device(vbasedev_tmp) || - !vbasedev_tmp->dev->realized) { + !qdev_is_realized(vbasedev_tmp->dev)) { return NULL; } From a3413cc176a7d453b0a75791df99b67b7027355f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:17:00 +0900 Subject: [PATCH 270/627] hw/virtio/virtio-mem: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-10-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/virtio/virtio-mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 35e03ed759..7130ed852d 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -1453,7 +1453,7 @@ static void virtio_mem_set_requested_size(Object *obj, Visitor *v, * The block size and memory backend are not fixed until the device was * realized. realize() will verify these properties then. */ - if (DEVICE(obj)->realized) { + if (qdev_is_realized(DEVICE(obj))) { if (!QEMU_IS_ALIGNED(value, vmem->block_size)) { error_setg(errp, "'%s' has to be multiples of '%s' (0x%" PRIx64 ")", name, VIRTIO_MEM_BLOCK_SIZE_PROP, @@ -1507,7 +1507,7 @@ static void virtio_mem_set_block_size(Object *obj, Visitor *v, const char *name, VirtIOMEM *vmem = VIRTIO_MEM(obj); uint64_t value; - if (DEVICE(obj)->realized) { + if (qdev_is_realized(DEVICE(obj))) { error_setg(errp, "'%s' cannot be changed", name); return; } From 2c69525a8d70117748353341a64093a96faaa467 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:17:01 +0900 Subject: [PATCH 271/627] hw/virtio/virtio-qmp: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-11-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/virtio/virtio-qmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c index 57cc03828c..5aaeebdd96 100644 --- a/hw/virtio/virtio-qmp.c +++ b/hw/virtio/virtio-qmp.c @@ -659,7 +659,7 @@ static int query_dev_child(Object *child, void *opaque) { VirtioInfoList **vdevs = opaque; Object *dev = object_dynamic_cast(child, TYPE_VIRTIO_DEVICE); - if (dev != NULL && DEVICE(dev)->realized) { + if (dev != NULL && qdev_is_realized(DEVICE(dev))) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtioInfo *info = g_new(VirtioInfo, 1); @@ -688,7 +688,7 @@ VirtIODevice *qmp_find_virtio_device(const char *path) /* Verify the canonical path is a realized virtio device */ Object *dev = object_dynamic_cast(object_resolve_path(path, NULL), TYPE_VIRTIO_DEVICE); - if (!dev || !DEVICE(dev)->realized) { + if (!dev || !qdev_is_realized(DEVICE(dev))) { return NULL; } return VIRTIO_DEVICE(dev); From 58c4aeacfa5d4e911b1b63f738295f7b637da9d4 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:17:02 +0900 Subject: [PATCH 272/627] target/i386/cpu: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-12-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- target/i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5805d33ab9..7a2c3cf358 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10387,7 +10387,7 @@ static void x86_cpu_set_bit_prop(Object *obj, Visitor *v, const char *name, BitProperty *fp = opaque; bool value; - if (dev->realized) { + if (qdev_is_realized(dev)) { qdev_prop_set_after_realize(dev, name, errp); return; } From 72422beb01001241e8425677e455c4a4c8274549 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:17:03 +0900 Subject: [PATCH 273/627] target/s390x: Use qdev_is_realized() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState fields should be accessed through qdev helpers rather than directly. Use qdev_is_realized() instead of reading DeviceState::realized directly. Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-13-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- target/s390x/cpu_models.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 2dd9aac807..f292af7ad0 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -714,7 +714,7 @@ static void set_feature(Object *obj, Visitor *v, const char *name, S390CPU *cpu = S390_CPU(obj); bool value; - if (dev->realized) { + if (qdev_is_realized(dev)) { error_setg(errp, "Attempt to set property '%s' on '%s' after " "it was realized", name, object_get_typename(obj)); return; @@ -770,7 +770,7 @@ static void set_feature_group(Object *obj, Visitor *v, const char *name, S390CPU *cpu = S390_CPU(obj); bool value; - if (dev->realized) { + if (qdev_is_realized(dev)) { error_setg(errp, "Attempt to set property '%s' on '%s' after " "it was realized", name, object_get_typename(obj)); return; From c38575a1265cb219230e75ede8e1750b6a269709 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 21 Jul 2026 17:17:04 +0900 Subject: [PATCH 274/627] hw/qdev: Parent device before setting parent bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 9940b2cfbc05 ("qdev: New qdev_new(), qdev_realize(), etc.") says "device state 'no QOM parent, but plugged into bus' is dangerous". In such a case, unrealizing the bus will hang in bus_unparent(): while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { DeviceState *dev = kid->child; object_unparent(OBJECT(dev)); } object_unparent() does nothing when its argument has no QOM parent, and the loop spins forever. However, that commit did not completely eliminate such a situation. When the device is not parented, device_set_realized() lets /machine/unattached parent it, but it happens after setting parent bus. Therefore, any failure between the two operations can leave the device in a dangerous state. qdev_realize() at least asserts that the device is not already realized and prevents one realization failure pattern, but it is not comprehensive. Besides, it will trip with a command line like the following: qemu-system-x86_64 -M none -nodefaults -nographic \ -device ipmi-bmc-sim,realized=on Eliminate the dangerous state by ensuring that the device is parented before calling qdev_set_parent_bus(). Also, stop asserting that the device is not already realized in qdev_realize(); it is broken and no longer serves any purpose. Fixes: 9940b2cfbc05 ("qdev: New qdev_new(), qdev_realize(), etc.") Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20260721-qdev-v3-14-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp> --- hw/core/qdev.c | 51 ++++++++++++++++++++++++------------------ tests/unit/test-qdev.c | 13 +++++++++++ 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index e2aab3d1fc..0b0f2f47fa 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -264,17 +264,43 @@ static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) { - assert(!dev->realized && !dev->parent_bus); + static int unattached_count; + bool unattached_parent = false; + + assert(!dev->parent_bus); + + if (!OBJECT(dev)->parent) { + gchar *name = g_strdup_printf("device[%d]", unattached_count++); + + object_property_add_child(machine_get_container("unattached"), + name, OBJECT(dev)); + unattached_parent = true; + g_free(name); + } if (bus) { if (!qdev_set_parent_bus(dev, bus, errp)) { - return false; + goto fail; } } else { assert(!DEVICE_GET_CLASS(dev)->bus_type); } - return object_property_set_bool(OBJECT(dev), "realized", true, errp); + if (object_property_set_bool(OBJECT(dev), "realized", true, errp)) { + return true; + } + +fail: + if (unattached_parent) { + /* + * Beware, this doesn't just revert + * object_property_add_child(), it also runs bus_remove()! + */ + object_unparent(OBJECT(dev)); + unattached_count--; + } + + return false; } bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) @@ -479,8 +505,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) BusState *bus; NamedClockList *ncl; Error *local_err = NULL; - bool unattached_parent = false; - static int unattached_count; if (dev->hotplugged && !dc->hotpluggable) { error_setg(errp, "Device '%s' does not support hotplugging", @@ -493,15 +517,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) goto fail; } - if (!obj->parent) { - gchar *name = g_strdup_printf("device[%d]", unattached_count++); - - object_property_add_child(machine_get_container("unattached"), - name, obj); - unattached_parent = true; - g_free(name); - } - hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); @@ -627,14 +642,6 @@ post_realize_fail: fail: error_propagate(errp, local_err); - if (unattached_parent) { - /* - * Beware, this doesn't just revert - * object_property_add_child(), it also runs bus_remove()! - */ - object_unparent(OBJECT(dev)); - unattached_count--; - } } static bool device_get_hotpluggable(Object *obj, Error **errp) diff --git a/tests/unit/test-qdev.c b/tests/unit/test-qdev.c index 20eae38e03..77c3eee717 100644 --- a/tests/unit/test-qdev.c +++ b/tests/unit/test-qdev.c @@ -78,6 +78,16 @@ static void test_qdev_free_properties(void) object_unref(mt); } +static void test_qdev_double_realization(void) +{ + MyDev *mt = STATIC_TYPE(object_new(TYPE_MY_DEV)); + + qdev_realize(DEVICE(mt), NULL, &error_fatal); + qdev_realize(DEVICE(mt), NULL, &error_fatal); + object_unparent(OBJECT(mt)); + object_unref(OBJECT(mt)); +} + int main(int argc, char **argv) { @@ -90,6 +100,9 @@ int main(int argc, char **argv) g_test_add_func("/qdev/free-properties", test_qdev_free_properties); + g_test_add_func("/qdev/double-realization", + test_qdev_double_realization); + g_test_run(); return 0; From 6ccf1e73fc65a7ad52eca1f8ecfa925a03acd987 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Thu, 30 Jul 2026 18:22:38 +0200 Subject: [PATCH 275/627] hw/i386/pc: xen: reinstate the "xenfv" machine alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7d2778dea32a4924a469f1cc5767042c8f5b4eea ("hw/i386/pc: Remove deprecated pc-q35/pc-i440fx/xenfv 3.1 machines") removed the Xen machine type that was providing the "xenfv" alias. As a consequence, since the tools are apparently relying on such alias, we're getting this, as soon as one tries to start a Xen (HVM) VM: qemu-system-i386: unsupported machine type: "xenfv" Use -machine help to list supported machines Reinstate the alias and let it point to the only Xen machine we still have. Cc: qemu-stable@nongnu.org Fixes: 7d2778dea3 Remove deprecated pc-q35/pc-i440fx/xenfv 3.1 machines Signed-off-by: Dario Faggioli Reviewed-by: Daniel P. Berrangé Acked-by: Stefano Stabellini Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260730162238.3308286-1-dfaggioli@suse.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/i386/pc_piix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 223a19cc4b..a929cc4dec 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -667,6 +667,7 @@ static void xenfv_machine_4_2_options(MachineClass *m) { pc_i440fx_machine_4_2_options(m); m->desc = "Xen Fully-virtualized PC"; + m->alias = "xenfv"; m->max_cpus = HVM_MAX_VCPUS; m->default_machine_opts = "accel=xen,suppress-vmdesc=on"; } From 59fc7b747d56652e09708adff3afaca326e85a2a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 31 Jul 2026 10:36:17 +0100 Subject: [PATCH 276/627] hw/net/rtl8139: Fix handling of VLAN tags on incoming short packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtl8139 receive code handles VLAN tags in incoming packets by copying the VLAN tag to a special field in the receive descriptor, and copying only the actual payload data to the receive buffer. This code tries to ensure that it pads out the payload to at least MIN_BUF_SIZE bytes. In commit 63b901bfd30 we removed the main "pad short frames" code from this device because we switched to requiring net backends to do the padding. However we didn't notice that this broke the VLAN tag handling, which relied on the old code making the buffer at least MIN_BUF_SIZE + VLAN_HLEN bytes so that it could copy MIN_BUF_SIZE bytes into the receive buffer even after removing the VLAN tag. The result is that the guest can make us read 4 bytes off the end of a buffer by feeding itself a suitable short packet in loopback mode. The old behaviour is actually not correct, because the IEEE802.1Q standard says that the minimum ethernet frame size remains 64 bytes including the 4 checksum bytes, and so when a tag is present the payload data only needs to be 56 bytes. (A bridge implementation can choose to pad tagged frames out to 68 bytes, but it doesn't have to, and so all devices have to correctly handle incoming tagged frames that are 64 bytes long.) The RTL8139 datasheet isn't very communicative on this topic, but there's nothing that suggests it adds extra padding on receive that didn't exist in the incoming packet. Drop the last remnants of the padding handling from this device; this avoids overcopying into the guest when we receive a short VLAN tagged packet. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3518 Signed-off-by: Peter Maydell Reviewed-by: Bin Meng Message-ID: <20260731093618.2961031-2-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/rtl8139.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 424af73a18..2b61c171f2 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -778,7 +778,6 @@ static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) s->RxBufAddr += size; } -#define MIN_BUF_SIZE 60 static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high) { return low | ((uint64_t)high << 32); @@ -1007,10 +1006,6 @@ static ssize_t rtl8139_receive(NetClientState *nc, lduw_be_p(&buf[ETH_ALEN * 2]) == ETH_P_VLAN) { dot1q_buf = &buf[ETH_ALEN * 2]; size -= VLAN_HLEN; - /* if too small buffer, use the tailroom added duing expansion */ - if (size < MIN_BUF_SIZE) { - size = MIN_BUF_SIZE; - } rxdw1 &= ~CP_RX_VLAN_TAG_MASK; /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */ From f3a10c1c454789ad6bb0633118019f4c6544b4b3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 31 Jul 2026 10:36:18 +0100 Subject: [PATCH 277/627] hw/net/rtl8139: Send whole of vlan-tagged packet when doing loopback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rtl8139_transfer_frame(), if we are transmitting a frame over loopback then we do this by calling qemu_receive_packet(). If we have an iovec rather than a simple buffer (which happens only when we're sending a packet where we are inserting a vlan tag), we have to convert this into a simple buffer first using iov_to_buf(). However, when we do this we forget to also update the 'size' local variable to the size of the new simple buffer, so we will truncate the packet by 4 bytes (the size of the vlan tag). Correct the logic so we don't truncate vlan-tagged packets when sending them over loopback. Cc: qemu-stable@nongnu.org Reported-by: Bin Meng Signed-off-by: Peter Maydell Reviewed-by: Bin Meng Message-ID: <20260731093618.2961031-3-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/rtl8139.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 2b61c171f2..16479284ee 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -1765,6 +1765,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, buf2 = g_malloc(buf2_size); iov_to_buf(iov, 3, 0, buf2, buf2_size); buf = buf2; + size = buf2_size; } DPRINTF("+++ transmit loopback mode\n"); From 60d010f66f2ad7c15388a605e6f1a2114dc60185 Mon Sep 17 00:00:00 2001 From: Bin Guo Date: Mon, 3 Aug 2026 12:18:08 +0800 Subject: [PATCH 278/627] hw/block/pflash_cfi01: Restore ROMD mode after migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pflash_post_load() did not restore the ROMD mode of the memory region. Although cmd and wcycle are migrated, the destination retains the default ROMD = true from realize. When the source was in a non-array mode (e.g. ID read, cmd = 0x90), reads on the destination bypass pflash_read() via the ROM fast path and return raw storage bytes instead of the command-specific response. Derive ROMD from the migrated cmd/wcycle in pflash_post_load. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4042 Cc: qemu-stable@nongnu.org Signed-off-by: Bin Guo Reviewed-by: Peter Maydell [PMD: Including review comments from https://lore.kernel.org/qemu-devel/CAFEAcA-P6RH7nJK0KQ1H8576ULFA7nocB0EkhhZf6Rw3g0WCag@mail.gmail.com/ Confirming that this is correct is a bit tricky. It relies on: * when we set romd mode to true we also set wcycle = 0, cmd = 0 (which we do, in reset and in the mode_read_array code) * when we set romd mode to false at the top of pflash_write(), all paths out of that function either go through the mode_read_array path, or else update pfl->cmd to something non-zero * nowhere outside pflash_write() udpates cmd or wcycle except for the "clear them to 0 and set romd mode" places This is almost but not quite true. In pflash_read(), the default case for the pfl->cmd switch sets wcycle = 0 cmd = 0 but doesn't change the romd state. Luckily the "this should never happen" comment is true -- there's no way to get a pfl->cmd that falls into the default (except for being deliberately fed a bogus value via inbound migration). ] Message-ID: <20260803041808.58174-1-guobin@linux.alibaba.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 5b9ddb20b1..a13b91967e 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -1030,6 +1030,16 @@ static int pflash_post_load(void *opaque, int version_id) { PFlashCFI01 *pfl = opaque; + /* + * ROMD mode is not in the VMState; derive it from the migrated + * cmd and wcycle. Only (wcycle == 0, cmd == 0x00) is read-array. + */ + if (pfl->wcycle == 0 && pfl->cmd == 0x00) { + memory_region_rom_device_set_romd(&pfl->mem, true); + } else { + memory_region_rom_device_set_romd(&pfl->mem, false); + } + if (!pfl->ro) { pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, pfl); From 6dab35f5492b04083f70726a3048d89d8deb4a32 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 10 Aug 2026 17:48:46 -0400 Subject: [PATCH 279/627] hw/nvme: add SPDM_SOCKET Kconfig dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NVMe emulation code unconditionally calls spdm_socket_*() APIs. Add a Kconfig dependency to avoid build errors when NVME_PCI is enabled without SPDM_SOCKET. Fixes: 4f947b10d52 ("hw/nvme: Add SPDM over DOE support") Signed-off-by: Stefan Hajnoczi Reviewed-by: Klaus Jensen Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260810214846.76805-1-stefanha@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/nvme/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/nvme/Kconfig b/hw/nvme/Kconfig index cfa2ab0f9d..cfeeed64cd 100644 --- a/hw/nvme/Kconfig +++ b/hw/nvme/Kconfig @@ -2,3 +2,4 @@ config NVME_PCI bool default y if PCI_DEVICES || PCIE_DEVICES depends on PCI + select SPDM_SOCKET From 5147e585e7002a3c4dbdad3ca85c716925831541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 07:43:49 +0200 Subject: [PATCH 280/627] hw/cpu: Correct CPU_GET_CLASS() comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0e86d7a71e8 ("cpus: Cache CPUClass early in instance_init() handler") renamed cpu_exec_realizefn() -> cpu_common_initfn(); update the comment. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-2-philmd@oss.qualcomm.com> --- include/hw/core/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index b54035fb13..c5064a5449 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -60,7 +60,7 @@ typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, * expensive given the eventual call to * object_class_dynamic_cast_assert(). Because of this the CPUState * has a cached value for the class in cs->cc which is set up in - * cpu_exec_realizefn() for use in hot code paths. + * cpu_common_initfn() for use in hot code paths. */ typedef struct CPUClass CPUClass; DECLARE_CLASS_CHECKERS(CPUClass, CPU, From fec261633c55d6ee50d812da7c84fb2de7eb60d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Aug 2026 16:46:15 +0200 Subject: [PATCH 281/627] hw/cpu: Include missing 'qemu/accel.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_common_realize() calls accel_cpu_common_realize(), itself declared in "qemu/accel.h". Include the latter, otherwise we get when refactoring unrelated headers: hw/core/cpu-common.c:233:10: error: implicit declaration of function ‘accel_cpu_common_realize’ 233 | if (!accel_cpu_common_realize(cpu, errp)) { | ^~~~~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-3-philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/cpu-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index e314f916f8..8c9ff25e04 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -23,6 +23,7 @@ #include "qapi/error.h" #include "hw/core/cpu.h" #include "system/hw_accel.h" +#include "qemu/accel.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/lockcnt.h" From a2d626371dfc08e63009bbc73a9f3e5ae37b63ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 08:00:49 +0200 Subject: [PATCH 282/627] hw/cpu: Move internal declarations to new 'cpu-internal.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some declarations are only used within hw/core/, in particular by the 3 cpu-{common,user,system}.c. Restrict the declarations scope by moving them to a new "cpu-internal.h" local header. Rename cpu_exec_initfn() -> cpu_exec_init() because we usually have the 'fn' suffix for handler, not API entry point methods. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-4-philmd@oss.qualcomm.com> --- MAINTAINERS | 1 + hw/core/cpu-common.c | 3 ++- hw/core/cpu-internal.h | 22 ++++++++++++++++++++++ hw/core/cpu-system.c | 3 ++- hw/core/cpu-user.c | 3 ++- include/hw/core/cpu.h | 6 ------ 6 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 hw/core/cpu-internal.h diff --git a/MAINTAINERS b/MAINTAINERS index f249be744e..c296dd5abf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2093,6 +2093,7 @@ Machine core M: Philippe Mathieu-Daudé R: Zhao Liu S: Maintained +F: hw/core/cpu-internal.h F: hw/core/cpu-common.c F: hw/core/cpu-system.c F: hw/core/machine-qmp-cmds.c diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 8c9ff25e04..17d7658093 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -39,6 +39,7 @@ #ifdef CONFIG_PLUGIN #include "qemu/plugin.h" #endif +#include "cpu-internal.h" CPUState *cpu_by_arch_id(int64_t id) { @@ -326,7 +327,7 @@ static void cpu_common_initfn(Object *obj) QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); - cpu_exec_initfn(cpu); + cpu_exec_init(cpu); /* * Plugin initialization must wait until the cpu start executing diff --git a/hw/core/cpu-internal.h b/hw/core/cpu-internal.h new file mode 100644 index 0000000000..ae6a31bca2 --- /dev/null +++ b/hw/core/cpu-internal.h @@ -0,0 +1,22 @@ +/* + * QEMU private CPU interface between user / system modes) + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_CORE_CPU_INTERNAL_H +#define HW_CORE_CPU_INTERNAL_H + +#include "hw/core/qdev.h" +#include "hw/core/cpu.h" + +void cpu_class_init_props(DeviceClass *dc); +void cpu_exec_class_post_init(CPUClass *cc); + +void cpu_exec_init(CPUState *cpu); + +void cpu_vmstate_register(CPUState *cpu); +void cpu_vmstate_unregister(CPUState *cpu); + +#endif diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 14eb4ed87f..8a9f2fcea8 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -30,6 +30,7 @@ #include "hw/core/sysemu-cpu-ops.h" #include "migration/vmstate.h" #include "system/tcg.h" +#include "cpu-internal.h" bool cpu_has_work(CPUState *cpu) { @@ -188,7 +189,7 @@ void cpu_exec_class_post_init(CPUClass *cc) g_assert(cc->sysemu_ops->has_work); } -void cpu_exec_initfn(CPUState *cpu) +void cpu_exec_init(CPUState *cpu) { cpu->memory = get_system_memory(); object_ref(OBJECT(cpu->memory)); diff --git a/hw/core/cpu-user.c b/hw/core/cpu-user.c index 25aa25ad24..c2cb00a85d 100644 --- a/hw/core/cpu-user.c +++ b/hw/core/cpu-user.c @@ -11,6 +11,7 @@ #include "hw/core/qdev-properties.h" #include "hw/core/cpu.h" #include "migration/vmstate.h" +#include "cpu-internal.h" static const Property cpu_user_props[] = { /* @@ -32,7 +33,7 @@ void cpu_exec_class_post_init(CPUClass *cc) /* nothing to do */ } -void cpu_exec_initfn(CPUState *cpu) +void cpu_exec_init(CPUState *cpu) { /* nothing to do */ } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c5064a5449..6490fb070f 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1178,12 +1178,6 @@ G_NORETURN void cpu_abort(CPUState *cpu, const char *fmt, ...) */ void qemu_process_cpu_events(CPUState *cpu); -/* $(top_srcdir)/cpu.c */ -void cpu_class_init_props(DeviceClass *dc); -void cpu_exec_class_post_init(CPUClass *cc); -void cpu_exec_initfn(CPUState *cpu); -void cpu_vmstate_register(CPUState *cpu); -void cpu_vmstate_unregister(CPUState *cpu); bool cpu_exec_realizefn(CPUState *cpu, Error **errp); void cpu_exec_unrealizefn(CPUState *cpu); void cpu_exec_reset_hold(CPUState *cpu); From dc6c2e66727fbd8a670ba821f75f82e80d7b9216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Aug 2026 16:34:57 +0200 Subject: [PATCH 283/627] hw/cpu: Rename cpu_common_realizefn() -> cpu_exec_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep cpu_common_*() pattern for publicly exposed common methods used by target code. Use cpu_exec_*() pattern for internal ones, mostly to distinct between system / user mode. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-5-philmd@oss.qualcomm.com> --- hw/core/cpu-common.c | 4 ++-- target/i386/kvm/kvm-cpu.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 17d7658093..33e349d440 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -246,7 +246,7 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp) return true; } -static void cpu_common_realizefn(DeviceState *dev, Error **errp) +static void cpu_exec_realize(DeviceState *dev, Error **errp) { CPUState *cpu = CPU(dev); Object *machine = qdev_get_machine(); @@ -379,7 +379,7 @@ static void cpu_common_class_init(ObjectClass *klass, const void *data) k->gdb_read_register = cpu_common_gdb_read_register; k->gdb_write_register = cpu_common_gdb_write_register; set_bit(DEVICE_CATEGORY_CPU, dc->categories); - dc->realize = cpu_common_realizefn; + dc->realize = cpu_exec_realize; dc->unrealize = cpu_common_unrealizefn; rc->phases.hold = cpu_common_reset_hold; rc->phases.exit = cpu_common_reset_exit; diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index c34d9f15c7..e164cef203 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -63,7 +63,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) * host_cpu_realizefn() * kvm_set_guest_phys_bits() * check/update ucode_rev, phys_bits, guest_phys_bits, mwait - * cpu_common_realizefn() (via xcc->parent_realize) + * cpu_exec_realize() (via xcc->parent_realize) */ if (xcc->max_features) { if (enable_cpu_pm) { From abf1023d639ccc19f452e92e40a8b3e90e222958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 07:55:51 +0200 Subject: [PATCH 284/627] hw/cpu: Rename cpu_exec_realizefn() -> cpu_common_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep cpu_common_*() pattern for publicly exposed common methods used by target code. Use cpu_exec_*() pattern for internal ones, mostly to distinct between system / user mode. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-6-philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/cpu-common.c | 2 +- include/hw/core/cpu.h | 3 ++- target/alpha/cpu.c | 2 +- target/arm/cpu.c | 2 +- target/avr/cpu.c | 2 +- target/hexagon/cpu.c | 2 +- target/hppa/cpu.c | 2 +- target/i386/cpu.c | 10 +++++----- target/i386/kvm/kvm-cpu.c | 2 +- target/loongarch/cpu.c | 2 +- target/m68k/cpu.c | 2 +- target/microblaze/cpu.c | 2 +- target/mips/cpu.c | 2 +- target/or1k/cpu.c | 2 +- target/ppc/cpu_init.c | 2 +- target/riscv/cpu.c | 2 +- target/riscv/kvm/kvm-cpu.c | 2 +- target/riscv/tcg/tcg-cpu.c | 2 +- target/rx/cpu.c | 2 +- target/s390x/cpu.c | 2 +- target/sh4/cpu.c | 2 +- target/sparc/cpu.c | 2 +- target/tricore/cpu.c | 2 +- target/xtensa/cpu.c | 2 +- 24 files changed, 29 insertions(+), 28 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 33e349d440..732e32fade 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -230,7 +230,7 @@ const char *parse_cpu_option(const char *cpu_option) return cpu_type; } -bool cpu_exec_realizefn(CPUState *cpu, Error **errp) +bool cpu_common_realize(CPUState *cpu, Error **errp) { if (!accel_cpu_common_realize(cpu, errp)) { return false; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 6490fb070f..7b7cf330cd 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1178,7 +1178,8 @@ G_NORETURN void cpu_abort(CPUState *cpu, const char *fmt, ...) */ void qemu_process_cpu_events(CPUState *cpu); -bool cpu_exec_realizefn(CPUState *cpu, Error **errp); +/** cpu_common_realize: CPU DeviceRealize common handler */ +bool cpu_common_realize(CPUState *cpu, Error **errp); void cpu_exec_unrealizefn(CPUState *cpu); void cpu_exec_reset_hold(CPUState *cpu); diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 0c35067b20..12e8602166 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -117,7 +117,7 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) cs->tcg_cflags |= CF_PCREL; #endif - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 787e4dc7ab..77aa78f00e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1891,7 +1891,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } #endif - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 3591219212..f8409f32ab 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -131,7 +131,7 @@ static void avr_cpu_realizefn(DeviceState *dev, Error **errp) AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 0ddd898e6e..7067e5b70f 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -457,7 +457,7 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index a68152f968..07b49e5132 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -181,7 +181,7 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp) HPPACPUClass *acc = HPPA_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 7a2c3cf358..e5ffb10d15 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -10164,7 +10164,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * These may be set by the accel-specific code, * and the results are subsequently checked / assumed in this function. */ - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; @@ -10179,7 +10179,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) if (cpu->guest_phys_bits == -1) { /* * If it was not set by the user, or by the accelerator via - * cpu_exec_realizefn, clear. + * cpu_common_realize, clear. */ cpu->guest_phys_bits = 0; } @@ -10188,7 +10188,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) /* * The default is the same as KVM's. Note that this check * needs to happen after the evenual setting of ucode_rev in - * accel-specific code in cpu_exec_realizefn. + * accel-specific code in cpu_common_realize. */ if (IS_AMD_CPU(env)) { cpu->ucode_rev = 0x01000065; @@ -10201,7 +10201,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * mwait extended info: needed for Core compatibility * We always wake on interrupt even if host does not have the capability. * - * requires the accel-specific code in cpu_exec_realizefn to + * requires the accel-specific code in cpu_common_realize to * have already acquired the CPUID data into cpu->mwait. */ cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; @@ -10230,7 +10230,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * Note that this code assumes features expansion has already been done * (as it checks for CPUID_EXT2_LM), and also assumes that potential * phys_bits adjustments to match the host have been already done in - * accel-specific code in cpu_exec_realizefn. + * accel-specific code in cpu_common_realize. */ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { if (cpu->phys_bits && cpu->phys_bits < 32) { diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index e164cef203..da8d77ade0 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -57,7 +57,7 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) * * x86_cpu_realizefn(): * x86_cpu_expand_features() - * cpu_exec_realizefn(): + * cpu_common_realize(): * accel_cpu_common_realize() * kvm_cpu_realizefn() * host_cpu_realizefn() diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index fb03424ffa..cb07f15110 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -704,7 +704,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 9ad3057d91..ce2707dee5 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -389,7 +389,7 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) register_m68k_insns(&cpu->env); - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index a97c92a7b6..389a5124b1 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -251,7 +251,7 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) int i = 0; Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/mips/cpu.c b/target/mips/cpu.c index d72044aef6..669c7d99bb 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -544,7 +544,7 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) } mips_cp0_period_set(cpu); - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/or1k/cpu.c b/target/or1k/cpu.c index ea29b2e01f..66c00c0930 100644 --- a/target/or1k/cpu.c +++ b/target/or1k/cpu.c @@ -170,7 +170,7 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index f404c7e549..b07e9c3ff9 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6921,7 +6921,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5a82e6563b..23b5023dd3 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1226,7 +1226,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 495cb42dc8..97069bf597 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -2006,7 +2006,7 @@ static void kvm_cpu_instance_init(CPUState *cs) * We'll get here via the following path: * * riscv_cpu_realize() - * -> cpu_exec_realizefn() + * -> cpu_common_realize() * -> kvm_cpu_realize() (via accel_cpu_common_realize()) */ static bool kvm_cpu_realize(CPUState *cs, Error **errp) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 4af5cd9c73..9e3cc87f8a 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1304,7 +1304,7 @@ static void riscv_cpu_set_profile(RISCVCPU *cpu, * We'll get here via the following path: * * riscv_cpu_realize() - * -> cpu_exec_realizefn() + * -> cpu_common_realize() * -> tcg_cpu_realize() (via accel_cpu_common_realize()) */ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 20b188c24c..9b8473d71c 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -147,7 +147,7 @@ static void rx_cpu_realize(DeviceState *dev, Error **errp) RXCPUClass *rcc = RX_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index c074e12ba2..641ea96c8e 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -249,7 +249,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) } #endif - cpu_exec_realizefn(cs, &err); + cpu_common_realize(cs, &err); if (err != NULL) { goto out; } diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 763424695c..ad2ec28c1b 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -250,7 +250,7 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 13ebb122a3..1bc14b586b 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -892,7 +892,7 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) /* Default NaN value: sign bit clear, all frac bits set */ set_float_default_nan_pattern(0b01111111, &env->fp_status); - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 472c24ae32..96e2817dee 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -99,7 +99,7 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp) CPUTriCoreState *env = &cpu->env; Error *local_err = NULL; - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 2015a4e3d0..7c25b9ab70 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -257,7 +257,7 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) xtensa_irq_init(&XTENSA_CPU(dev)->env); #endif - cpu_exec_realizefn(cs, &local_err); + cpu_common_realize(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; From 5293cecb8921aef335471d3649013567daaa0378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 08:11:46 +0200 Subject: [PATCH 285/627] hw/cpu: Rename cpu_exec_unrealizefn() -> cpu_common_unrealize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep cpu_common_*() pattern for publicly exposed common methods used by target code. Use cpu_exec_*() pattern for internal ones, mostly to distinct between system / user mode. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-7-philmd@oss.qualcomm.com> --- hw/core/cpu-common.c | 4 ++-- include/hw/core/cpu.h | 4 +++- target/ppc/cpu_init.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 732e32fade..59cd489b71 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -284,10 +284,10 @@ static void cpu_common_unrealizefn(DeviceState *dev) #endif /* NOTE: latest generic point before the cpu is fully unrealized */ - cpu_exec_unrealizefn(cpu); + cpu_common_unrealize(cpu); } -void cpu_exec_unrealizefn(CPUState *cpu) +void cpu_common_unrealize(CPUState *cpu) { cpu_vmstate_unregister(cpu); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 7b7cf330cd..81af7b9ee1 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1180,7 +1180,9 @@ void qemu_process_cpu_events(CPUState *cpu); /** cpu_common_realize: CPU DeviceRealize common handler */ bool cpu_common_realize(CPUState *cpu, Error **errp); -void cpu_exec_unrealizefn(CPUState *cpu); +/** cpu_common_realize: CPU DeviceUnrealize common handler */ +void cpu_common_unrealize(CPUState *cpu); + void cpu_exec_reset_hold(CPUState *cpu); extern const VMStateDescription vmstate_cpu_common; diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index b07e9c3ff9..e3a1075aad 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6956,7 +6956,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) return; unrealize: - cpu_exec_unrealizefn(cs); + cpu_common_unrealize(cs); } static void ppc_cpu_unrealize(DeviceState *dev) From 721c189cb60b08bacff2b9adeb6e595d04a23975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Aug 2026 16:40:51 +0200 Subject: [PATCH 286/627] hw/cpu: Extract cpu_exec_realize() out of cpu_common_realizefn() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_common_realizefn() contains code only used by system mode emulation. Extract it to a new cpu_exec_realize() helper. In the next commit this helper will be moved to cpu-system.c where it belongs. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-8-philmd@oss.qualcomm.com> --- hw/core/cpu-common.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 59cd489b71..cd7c8763cf 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -246,9 +246,8 @@ bool cpu_common_realize(CPUState *cpu, Error **errp) return true; } -static void cpu_exec_realize(DeviceState *dev, Error **errp) +static void cpu_exec_realize(CPUState *cpu, Error **errp) { - CPUState *cpu = CPU(dev); Object *machine = qdev_get_machine(); /* qdev_get_machine() can return something that's not TYPE_MACHINE @@ -264,10 +263,15 @@ static void cpu_exec_realize(DeviceState *dev, Error **errp) } } - if (dev->hotplugged) { + if (DEVICE(cpu)->hotplugged) { cpu_synchronize_post_init(cpu); cpu_resume(cpu); } +} + +static void cpu_common_realizefn(DeviceState *dev, Error **errp) +{ + cpu_exec_realize(CPU(dev), errp); /* NOTE: latest generic point where the cpu is fully realized */ } @@ -379,7 +383,7 @@ static void cpu_common_class_init(ObjectClass *klass, const void *data) k->gdb_read_register = cpu_common_gdb_read_register; k->gdb_write_register = cpu_common_gdb_write_register; set_bit(DEVICE_CATEGORY_CPU, dc->categories); - dc->realize = cpu_exec_realize; + dc->realize = cpu_common_realizefn; dc->unrealize = cpu_common_unrealizefn; rc->phases.hold = cpu_common_reset_hold; rc->phases.exit = cpu_common_reset_exit; From 398913c47b334d174f235983e002a4bdf6d3d409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Aug 2026 16:48:01 +0200 Subject: [PATCH 287/627] hw/cpu: Move system-specific cpu_exec_realize() to cpu-system.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current cpu_exec_realize() body only contains system-mode related code. Move that method out of cpu-common.c to cpu-system.c, removing the system / machine mentions in this common file. Add an empty stub for user-mode. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20260811183410.22428-9-philmd@oss.qualcomm.com> --- hw/core/cpu-common.c | 24 ------------------------ hw/core/cpu-internal.h | 1 + hw/core/cpu-system.c | 27 +++++++++++++++++++++++++++ hw/core/cpu-user.c | 5 +++++ 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index cd7c8763cf..4f4c87f33a 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -33,7 +33,6 @@ #include "exec/log.h" #include "exec/gdbstub.h" #include "system/tcg.h" -#include "hw/core/boards.h" #include "hw/core/qdev-properties.h" #include "trace.h" #ifdef CONFIG_PLUGIN @@ -246,29 +245,6 @@ bool cpu_common_realize(CPUState *cpu, Error **errp) return true; } -static void cpu_exec_realize(CPUState *cpu, Error **errp) -{ - Object *machine = qdev_get_machine(); - - /* qdev_get_machine() can return something that's not TYPE_MACHINE - * if this is one of the user-only emulators; in that case there's - * no need to check the ignore_memory_transaction_failures board flag. - */ - if (object_dynamic_cast(machine, TYPE_MACHINE)) { - MachineClass *mc = MACHINE_GET_CLASS(machine); - - if (mc) { - cpu->ignore_memory_transaction_failures = - mc->ignore_memory_transaction_failures; - } - } - - if (DEVICE(cpu)->hotplugged) { - cpu_synchronize_post_init(cpu); - cpu_resume(cpu); - } -} - static void cpu_common_realizefn(DeviceState *dev, Error **errp) { cpu_exec_realize(CPU(dev), errp); diff --git a/hw/core/cpu-internal.h b/hw/core/cpu-internal.h index ae6a31bca2..44715b4432 100644 --- a/hw/core/cpu-internal.h +++ b/hw/core/cpu-internal.h @@ -15,6 +15,7 @@ void cpu_class_init_props(DeviceClass *dc); void cpu_exec_class_post_init(CPUClass *cc); void cpu_exec_init(CPUState *cpu); +void cpu_exec_realize(CPUState *cpu, Error **errp); void cpu_vmstate_register(CPUState *cpu); void cpu_vmstate_unregister(CPUState *cpu); diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 8a9f2fcea8..a64e8c2b68 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -25,10 +25,12 @@ #include "exec/target_page.h" #include "system/memory.h" #include "qemu/target-info.h" +#include "hw/core/boards.h" #include "hw/core/qdev.h" #include "hw/core/qdev-properties.h" #include "hw/core/sysemu-cpu-ops.h" #include "migration/vmstate.h" +#include "system/hw_accel.h" #include "system/tcg.h" #include "cpu-internal.h" @@ -221,6 +223,31 @@ static int cpu_common_pre_load(void *opaque) return 0; } +void cpu_exec_realize(CPUState *cpu, Error **errp) +{ + Object *machine = qdev_get_machine(); + + /* + * qdev_get_machine() can return something that's not TYPE_MACHINE + * if this is one of the user-only emulators; in that case there's + * no need to check the ignore_memory_transaction_failures board flag. + */ + if (object_dynamic_cast(machine, TYPE_MACHINE)) { + MachineClass *mc = MACHINE_GET_CLASS(machine); + + if (mc) { + cpu->ignore_memory_transaction_failures = + mc->ignore_memory_transaction_failures; + } + } + + if (DEVICE(cpu)->hotplugged) { + cpu_synchronize_post_init(cpu); + cpu_resume(cpu); + } + +} + static bool cpu_common_exception_index_needed(void *opaque) { CPUState *cpu = opaque; diff --git a/hw/core/cpu-user.c b/hw/core/cpu-user.c index c2cb00a85d..1e38c88f9b 100644 --- a/hw/core/cpu-user.c +++ b/hw/core/cpu-user.c @@ -38,6 +38,11 @@ void cpu_exec_init(CPUState *cpu) /* nothing to do */ } +void cpu_exec_realize(CPUState *cpu, Error **errp) +{ + /* nothing to do */ +} + void cpu_vmstate_register(CPUState *cpu) { assert(qdev_get_vmsd(DEVICE(cpu)) == NULL || From f37b245e564d7004f6a5f61a44cc021dda45f13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Feb 2024 14:38:31 +0100 Subject: [PATCH 288/627] hw/nmi: Use object_child_foreach_recursive() in nmi_children() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace object_child_foreach() and recursion by a single object_child_foreach_recursive() call. Propagate the returned value so callers can check it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-2-philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/nmi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index 4b447e126b..2272404657 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -31,8 +31,6 @@ struct do_nmi_s { bool handled; }; -static void nmi_children(Object *o, struct do_nmi_s *ns); - static int do_nmi(Object *o, void *opaque) { struct do_nmi_s *ns = opaque; @@ -47,14 +45,13 @@ static int do_nmi(Object *o, void *opaque) return -1; } } - nmi_children(o, ns); return 0; } -static void nmi_children(Object *o, struct do_nmi_s *ns) +static int nmi_children(Object *o, struct do_nmi_s *ns) { - object_child_foreach(o, do_nmi, ns); + return object_child_foreach_recursive(o, do_nmi, ns); } void nmi_monitor_handle(int cpu_index, Error **errp) @@ -65,10 +62,9 @@ void nmi_monitor_handle(int cpu_index, Error **errp) .handled = false }; - nmi_children(object_get_root(), &ns); - if (ns.handled) { + if (nmi_children(object_get_root(), &ns)) { error_propagate(errp, ns.err); - } else { + } else if (!ns.handled) { error_setg(errp, "machine does not provide NMIs"); } } From c489b04fbc94e7f738704b2b85e88d92ecf5cc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Feb 2024 14:28:25 +0100 Subject: [PATCH 289/627] hw/s390x/virtio-ccw: Always inject NMI to first CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can trigger NMI from HMP or QMP. QEMU maps the NMI to the s390x per-CPU 'RESTART' interrupt. Linux guests usually setup this interrupt to trigger kdump or crash. Such crashdump can be triggered in QEMU by HMP "nmi" or QMP "inject-nmi" commands. Using QMP, since we can not select a particular CPU, the first CPU is used (CPU#0). See the documentation from commit 795dc6e4 ("watchdog: Add new Virtual Watchdog action INJECT-NMI"): @inject-nmi: a non-maskable interrupt is injected into the first VCPU (all VCPUS on x86) (since 2.4) While we can select a particular CPU on HMP, the guest behavior is expected to be the same if using CPU #N or CPU #0. Since always using CPU#0 simplifies API maintenance , update s390_nmi() to inject NMI to the first CPU. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: David Hildenbrand Reviewed-by: Eric Farman Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-3-philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé --- hmp-commands.hx | 5 +++-- hw/s390x/s390-virtio-ccw.c | 4 +--- qapi/machine.json | 7 ++++--- qapi/run-state.json | 6 ++++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 7f43cf537f..a29f02b623 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -865,12 +865,13 @@ ERST .name = "nmi", .args_type = "", .params = "", - .help = "inject an NMI", + .help = "Inject an NMI, in a machine-specific way", .cmd = hmp_nmi, }, SRST ``nmi`` *cpu* - Inject an NMI on the default CPU (x86/s390) or all CPUs (ppc64). + Inject an NMI, in a machine-specific way. + Not all machines implement NMI handling. ERST { diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 55131c1a44..a2f373b119 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -727,9 +727,7 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, static void s390_nmi(NMIState *n, int cpu_index, Error **errp) { - CPUState *cs = qemu_get_cpu(cpu_index); - - s390_cpu_restart(S390_CPU(cs)); + s390_cpu_restart(S390_CPU(first_cpu)); } static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) diff --git a/qapi/machine.json b/qapi/machine.json index 9b2248038f..2d63c1bac3 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -432,9 +432,10 @@ ## # @inject-nmi: # -# Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or -# all CPUs (ppc64). The command fails when the guest doesn't support -# injecting. +# Injects a Non-Maskable Interrupt (machine specific: for example on +# s390x CCW only the first vCPU receives the NMI, but on x86 machines +# all vCPUs receive it). The command fails when the guest doesn't +# support injecting. # # Since: 0.14 # diff --git a/qapi/run-state.json b/qapi/run-state.json index a5771ad468..e4fdead1e0 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -317,8 +317,10 @@ # # @none: nothing is done # -# @inject-nmi: a non-maskable interrupt is injected into the first -# VCPU (all VCPUS on x86) (since 2.4) +# @inject-nmi: a non-maskable interrupt is injected (machine +# specific: for example on s390x CCW only the first vCPU +# receives the NMI, but on x86 machines all vCPUs receive +# it). (since 2.4) # # Since: 2.1 ## From 9dad341a527a8fea796ba07803f41819addbceec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Feb 2024 14:30:43 +0100 Subject: [PATCH 290/627] hw/nmi: Remove @cpu_index argument from NMIClass::nmi_monitor_handler() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only s390x was using the 'cpu_index' argument, but since the previous commit it isn't anymore (it use the first cpu). Since this argument is now completely unused, remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-4-philmd@oss.qualcomm.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/nmi.c | 2 +- hw/hppa/machine.c | 2 +- hw/i386/x86.c | 2 +- hw/intc/m68k_irqc.c | 2 +- hw/m68k/q800-glue.c | 2 +- hw/misc/macio/gpio.c | 2 +- hw/ppc/pnv.c | 2 +- hw/ppc/spapr.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- include/hw/core/nmi.h | 8 +++++++- 10 files changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index 2272404657..ff6454437c 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -40,7 +40,7 @@ static int do_nmi(Object *o, void *opaque) NMIClass *nc = NMI_GET_CLASS(n); ns->handled = true; - nc->nmi_monitor_handler(n, ns->cpu_index, &ns->err); + nc->nmi_monitor_handler(n, &ns->err); if (ns->err) { return -1; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index d762163ddf..2b44debc38 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -829,7 +829,7 @@ static void hppa_machine_reset(MachineState *ms, ResetType type) cpu[0]->env.cmdline_or_bootorder = 'c'; } -static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) +static void hppa_nmi(NMIState *ns, Error **errp) { CPUState *cs; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index dc7f0d56b0..0ea5453403 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -147,7 +147,7 @@ static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms) return ms->possible_cpus; } -static void x86_nmi(NMIState *n, int cpu_index, Error **errp) +static void x86_nmi(NMIState *ns, Error **errp) { /* cpu index isn't used */ CPUState *cs; diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c index 68ddb5351b..bc41b44d45 100644 --- a/hw/intc/m68k_irqc.c +++ b/hw/intc/m68k_irqc.c @@ -70,7 +70,7 @@ static void m68k_irqc_instance_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); } -static void m68k_nmi(NMIState *n, int cpu_index, Error **errp) +static void m68k_nmi(NMIState *n, Error **errp) { m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); } diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index ac9062c648..b13e5ef95f 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -159,7 +159,7 @@ static void glue_auxmode_set_irq(void *opaque, int irq, int level) s->auxmode = level; } -static void glue_nmi(NMIState *n, int cpu_index, Error **errp) +static void glue_nmi(NMIState *n, Error **errp) { GLUEState *s = GLUE(n); diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index 1a7c534d65..1bdca728f9 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -188,7 +188,7 @@ static void macio_gpio_reset(DeviceState *dev) macio_set_gpio(s, 1, true); } -static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp) +static void macio_gpio_nmi(NMIState *n, Error **errp) { macio_set_gpio(MACIO_GPIO(n), 9, true); macio_set_gpio(MACIO_GPIO(n), 9, false); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index c0cb45dbfb..8676be7bbb 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -3552,7 +3552,7 @@ static void pnv_cpu_do_nmi(PnvChip *chip, PowerPCCPU *cpu, void *opaque) async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(0)); } -static void pnv_nmi(NMIState *n, int cpu_index, Error **errp) +static void pnv_nmi(NMIState *ns, Error **errp) { PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7e284edd7d..c376a58872 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3550,7 +3550,7 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) } } -static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) +static void spapr_nmi(NMIState *ns, Error **errp) { CPUState *cs; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a2f373b119..ac04245d65 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -725,7 +725,7 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, return NULL; } -static void s390_nmi(NMIState *n, int cpu_index, Error **errp) +static void s390_nmi(NMIState *ns, Error **errp) { s390_cpu_restart(S390_CPU(first_cpu)); } diff --git a/include/hw/core/nmi.h b/include/hw/core/nmi.h index fff41bebc6..4c4ce79071 100644 --- a/include/hw/core/nmi.h +++ b/include/hw/core/nmi.h @@ -37,7 +37,13 @@ typedef struct NMIState NMIState; struct NMIClass { InterfaceClass parent_class; - void (*nmi_monitor_handler)(NMIState *n, int cpu_index, Error **errp); + /** + * nmi_monitor_handler: Callback to handle NMI notifications. + * + * @ns: Class #NMIState state + * @errp: pointer to error object + */ + void (*nmi_monitor_handler)(NMIState *ns, Error **errp); }; void nmi_monitor_handle(int cpu_index, Error **errp); From 64011ef0d93fa892333782643ec544cc10504651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Feb 2024 14:31:25 +0100 Subject: [PATCH 291/627] hw/nmi: Remove @cpu_index argument from nmi_inject() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nmi_monitor_handle() is not related to the monitor, rename it as nmi_inject(). Return a boolean value indicating success / failure as recommended by the Error API since commit e3fe3988d7 ("error: Document Error API usage rules"). The 'cpu_index' argument is not used, remove it. This officially drops the current CPU for HMP command. Document nmi_inject() as suggested by Peter Maydell in https://lore.kernel.org/qemu-devel/CAFEAcA-yALySmCJLbitCmYpiZKUXJNOavGJG9RYeo8fKqz7gcw@mail.gmail.com/. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Marc-André Lureau Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20260812121232.71958-5-philmd@oss.qualcomm.com> --- hmp-commands.hx | 2 +- hw/core/nmi.c | 9 ++++----- hw/ipmi/ipmi.c | 3 +-- hw/watchdog/watchdog.c | 2 +- include/hw/core/nmi.h | 24 +++++++++++++++++++++++- system/cpus.c | 3 +-- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index a29f02b623..43ff220b5f 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -869,7 +869,7 @@ ERST .cmd = hmp_nmi, }, SRST -``nmi`` *cpu* +``nmi`` Inject an NMI, in a machine-specific way. Not all machines implement NMI handling. ERST diff --git a/hw/core/nmi.c b/hw/core/nmi.c index ff6454437c..2d890f2995 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -22,11 +22,8 @@ #include "qemu/osdep.h" #include "hw/core/nmi.h" #include "qapi/error.h" -#include "qemu/module.h" -#include "monitor/monitor.h" struct do_nmi_s { - int cpu_index; Error *err; bool handled; }; @@ -54,19 +51,21 @@ static int nmi_children(Object *o, struct do_nmi_s *ns) return object_child_foreach_recursive(o, do_nmi, ns); } -void nmi_monitor_handle(int cpu_index, Error **errp) +bool nmi_inject(Error **errp) { struct do_nmi_s ns = { - .cpu_index = cpu_index, .err = NULL, .handled = false }; if (nmi_children(object_get_root(), &ns)) { error_propagate(errp, ns.err); + return false; } else if (!ns.handled) { error_setg(errp, "machine does not provide NMIs"); + return false; } + return true; } static const TypeInfo nmi_info = { diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index 74818ff3ce..dedf23cb99 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -59,8 +59,7 @@ static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly) if (checkonly) { return 0; } - /* We don't care what CPU we use. */ - nmi_monitor_handle(0, NULL); + nmi_inject(NULL); return 0; case IPMI_SHUTDOWN_VIA_ACPI_OVERTEMP: diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 0842fe373a..5f764a0c1b 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -81,7 +81,7 @@ void watchdog_perform_action(void) case WATCHDOG_ACTION_INJECT_NMI: qapi_event_send_watchdog(WATCHDOG_ACTION_INJECT_NMI); - nmi_monitor_handle(0, NULL); + nmi_inject(NULL); break; default: diff --git a/include/hw/core/nmi.h b/include/hw/core/nmi.h index 4c4ce79071..851be28257 100644 --- a/include/hw/core/nmi.h +++ b/include/hw/core/nmi.h @@ -46,6 +46,28 @@ struct NMIClass { void (*nmi_monitor_handler)(NMIState *ns, Error **errp); }; -void nmi_monitor_handle(int cpu_index, Error **errp); +/** + * nmi_inject: Inject an NMI, in a machine-specific way + * @errp: pointer to error object + * + * This function injects an NMI, in a machine-specific way. The + * intention is that this should typically trigger a guest kernel + * dump or reboot, and might happen as a result of user request + * from the monitor, watchdog timeouts, and similar events. + * (For example on the x86 PC it triggers an NMI on all CPUs, + * and on s390 it triggers the RESTART interrupt on the first CPU.) + * + * The NMI is injected by looking for a QOM object which implements + * the TYPE_NMI interface, and calling its nmi_monitor_handler method. Usually + * it is the machine model class that implements this interface. + * + * Not all machines implement NMI handling; this function + * will return an error if used on a machine which does not + * implement NMIs. + * + * On success, return %true. + * On failure, store an error through @errp and return %false. + */ +bool nmi_inject(Error **errp); #endif /* NMI_H */ diff --git a/system/cpus.c b/system/cpus.c index 97e5a5edee..9758cda463 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "monitor/monitor.h" #include "qemu/coroutine-tls.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" @@ -926,6 +925,6 @@ exit: void qmp_inject_nmi(Error **errp) { - nmi_monitor_handle(monitor_get_cpu_index(monitor_cur()), errp); + nmi_inject(errp); } From caabebf76b0203e37108c3c6902cc146bb7dd0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 12:20:36 +0200 Subject: [PATCH 292/627] hw/nmi: Rename nmi_monitor_handler() -> raise_nmi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nmi_monitor_handler() is not related to the monitor, rename it as raise_nmi(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-6-philmd@oss.qualcomm.com> --- hw/core/nmi.c | 2 +- hw/hppa/machine.c | 2 +- hw/i386/x86.c | 2 +- hw/intc/m68k_irqc.c | 2 +- hw/m68k/q800-glue.c | 2 +- hw/misc/macio/gpio.c | 2 +- hw/ppc/pnv.c | 2 +- hw/ppc/spapr.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- include/hw/core/nmi.h | 10 ++++++---- 10 files changed, 15 insertions(+), 13 deletions(-) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index 2d890f2995..a6edf4fbf0 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -37,7 +37,7 @@ static int do_nmi(Object *o, void *opaque) NMIClass *nc = NMI_GET_CLASS(n); ns->handled = true; - nc->nmi_monitor_handler(n, &ns->err); + nc->raise_nmi(n, &ns->err); if (ns->err) { return -1; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2b44debc38..717cfde61d 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -851,7 +851,7 @@ static void hppa_machine_common_class_init(ObjectClass *oc, const void *data) mc->default_ram_id = "hppa.ram"; mc->default_nic = "tulip"; - nc->nmi_monitor_handler = hppa_nmi; + nc->raise_nmi = hppa_nmi; } static void HP_B160L_machine_init_class_init(ObjectClass *oc, const void *data) diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 0ea5453403..d1414ff63d 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -389,7 +389,7 @@ static void x86_machine_class_init(ObjectClass *oc, const void *data) mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->kvm_type = x86_kvm_type; - nc->nmi_monitor_handler = x86_nmi; + nc->raise_nmi = x86_nmi; object_class_property_add(oc, X86_MACHINE_SMM, "OnOffAuto", x86_machine_get_smm, x86_machine_set_smm, diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c index bc41b44d45..29f758dafd 100644 --- a/hw/intc/m68k_irqc.c +++ b/hw/intc/m68k_irqc.c @@ -97,7 +97,7 @@ static void m68k_irqc_class_init(ObjectClass *oc, const void *data) InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); device_class_set_props(dc, m68k_irqc_properties); - nc->nmi_monitor_handler = m68k_nmi; + nc->raise_nmi = m68k_nmi; device_class_set_legacy_reset(dc, m68k_irqc_reset); dc->vmsd = &vmstate_m68k_irqc; ic->get_statistics = m68k_irqc_get_statistics; diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index b13e5ef95f..265af90a8e 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -237,7 +237,7 @@ static void glue_class_init(ObjectClass *klass, const void *data) dc->vmsd = &vmstate_glue; device_class_set_props(dc, glue_properties); rc->phases.hold = glue_reset_hold; - nc->nmi_monitor_handler = glue_nmi; + nc->raise_nmi = glue_nmi; } static const TypeInfo glue_info_types[] = { diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index 1bdca728f9..db0c4ecb3c 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -201,7 +201,7 @@ static void macio_gpio_class_init(ObjectClass *oc, const void *data) device_class_set_legacy_reset(dc, macio_gpio_reset); dc->vmsd = &vmstate_macio_gpio; - nc->nmi_monitor_handler = macio_gpio_nmi; + nc->raise_nmi = macio_gpio_nmi; } static const TypeInfo macio_gpio_init_info = { diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 8676be7bbb..a9f7424586 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -3583,7 +3583,7 @@ static void pnv_machine_class_init(ObjectClass *oc, const void *data) mc->default_ram_size = 1 * GiB; mc->default_ram_id = "pnv.ram"; ispc->print_info = pnv_pic_print_info; - nc->nmi_monitor_handler = pnv_nmi; + nc->raise_nmi = pnv_nmi; object_class_property_add_bool(oc, "hb-mode", pnv_machine_get_hb, pnv_machine_set_hb); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c376a58872..1bc90ceed3 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4652,7 +4652,7 @@ static void spapr_machine_class_init(ObjectClass *oc, const void *data) mc->nvdimm_supported = true; smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED; fwc->get_dev_path = spapr_get_fw_dev_path; - nc->nmi_monitor_handler = spapr_nmi; + nc->raise_nmi = spapr_nmi; vhc->cpu_in_nested = spapr_cpu_in_nested; vhc->deliver_hv_excp = spapr_exit_nested; vhc->hypercall = emulate_spapr_hypercall; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index ac04245d65..21d9f51ddc 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -830,7 +830,7 @@ static void ccw_machine_class_init(ObjectClass *oc, const void *data) hc->plug = s390_machine_device_plug; hc->unplug_request = s390_machine_device_unplug_request; hc->unplug = s390_machine_device_unplug; - nc->nmi_monitor_handler = s390_nmi; + nc->raise_nmi = s390_nmi; mc->default_ram_id = "s390.ram"; mc->default_nic = "virtio-net-ccw"; dsi->qmp_dump_skeys = s390_qmp_dump_skeys; diff --git a/include/hw/core/nmi.h b/include/hw/core/nmi.h index 851be28257..a8feac3b67 100644 --- a/include/hw/core/nmi.h +++ b/include/hw/core/nmi.h @@ -38,12 +38,14 @@ struct NMIClass { InterfaceClass parent_class; /** - * nmi_monitor_handler: Callback to handle NMI notifications. - * + * raise_nmi: Callback to handle NMI notifications. * @ns: Class #NMIState state * @errp: pointer to error object + * + * Called by nmi_inject() to perform the machine-specific + * action when a NMI is requested. */ - void (*nmi_monitor_handler)(NMIState *ns, Error **errp); + void (*raise_nmi)(NMIState *ns, Error **errp); }; /** @@ -58,7 +60,7 @@ struct NMIClass { * and on s390 it triggers the RESTART interrupt on the first CPU.) * * The NMI is injected by looking for a QOM object which implements - * the TYPE_NMI interface, and calling its nmi_monitor_handler method. Usually + * the TYPE_NMI interface, and calling its raise_nmi method. Usually * it is the machine model class that implements this interface. * * Not all machines implement NMI handling; this function From acfbe07619b533238a376ee1dc4cdced56cb3a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 12:24:19 +0200 Subject: [PATCH 293/627] hw/nmi: Remove unused @errp argument from raise_nmi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not a single handler update @errp. The single user is nmi_inject() filling with "machine does not provide NMIs". Remove the unused argument from the raise_nmi() callback, simplifying the methods in hw/core/nmi.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-7-philmd@oss.qualcomm.com> --- hw/core/nmi.c | 32 ++++++-------------------------- hw/hppa/machine.c | 2 +- hw/i386/x86.c | 2 +- hw/intc/m68k_irqc.c | 2 +- hw/m68k/q800-glue.c | 2 +- hw/misc/macio/gpio.c | 2 +- hw/ppc/pnv.c | 2 +- hw/ppc/spapr.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- include/hw/core/nmi.h | 3 +-- 10 files changed, 15 insertions(+), 36 deletions(-) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index a6edf4fbf0..c44b0cf892 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -23,45 +23,25 @@ #include "hw/core/nmi.h" #include "qapi/error.h" -struct do_nmi_s { - Error *err; - bool handled; -}; - static int do_nmi(Object *o, void *opaque) { - struct do_nmi_s *ns = opaque; + bool *handled = opaque; NMIState *n = (NMIState *) object_dynamic_cast(o, TYPE_NMI); if (n) { - NMIClass *nc = NMI_GET_CLASS(n); - - ns->handled = true; - nc->raise_nmi(n, &ns->err); - if (ns->err) { - return -1; - } + *handled = true; + NMI_GET_CLASS(n)->raise_nmi(n); } return 0; } -static int nmi_children(Object *o, struct do_nmi_s *ns) -{ - return object_child_foreach_recursive(o, do_nmi, ns); -} - bool nmi_inject(Error **errp) { - struct do_nmi_s ns = { - .err = NULL, - .handled = false - }; + bool handled = false; - if (nmi_children(object_get_root(), &ns)) { - error_propagate(errp, ns.err); - return false; - } else if (!ns.handled) { + object_child_foreach_recursive(object_get_root(), do_nmi, &handled); + if (!handled) { error_setg(errp, "machine does not provide NMIs"); return false; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 717cfde61d..98931481b2 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -829,7 +829,7 @@ static void hppa_machine_reset(MachineState *ms, ResetType type) cpu[0]->env.cmdline_or_bootorder = 'c'; } -static void hppa_nmi(NMIState *ns, Error **errp) +static void hppa_nmi(NMIState *ns) { CPUState *cs; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index d1414ff63d..f8ba3244e2 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -147,7 +147,7 @@ static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms) return ms->possible_cpus; } -static void x86_nmi(NMIState *ns, Error **errp) +static void x86_nmi(NMIState *ns) { /* cpu index isn't used */ CPUState *cs; diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c index 29f758dafd..47f626c0fa 100644 --- a/hw/intc/m68k_irqc.c +++ b/hw/intc/m68k_irqc.c @@ -70,7 +70,7 @@ static void m68k_irqc_instance_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); } -static void m68k_nmi(NMIState *n, Error **errp) +static void m68k_nmi(NMIState *n) { m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); } diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index 265af90a8e..223e7d9019 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -159,7 +159,7 @@ static void glue_auxmode_set_irq(void *opaque, int irq, int level) s->auxmode = level; } -static void glue_nmi(NMIState *n, Error **errp) +static void glue_nmi(NMIState *n) { GLUEState *s = GLUE(n); diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index db0c4ecb3c..ba001f7b20 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -188,7 +188,7 @@ static void macio_gpio_reset(DeviceState *dev) macio_set_gpio(s, 1, true); } -static void macio_gpio_nmi(NMIState *n, Error **errp) +static void macio_gpio_nmi(NMIState *n) { macio_set_gpio(MACIO_GPIO(n), 9, true); macio_set_gpio(MACIO_GPIO(n), 9, false); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index a9f7424586..f0413639f9 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -3552,7 +3552,7 @@ static void pnv_cpu_do_nmi(PnvChip *chip, PowerPCCPU *cpu, void *opaque) async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(0)); } -static void pnv_nmi(NMIState *ns, Error **errp) +static void pnv_nmi(NMIState *ns) { PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1bc90ceed3..20e024907b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3550,7 +3550,7 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg) } } -static void spapr_nmi(NMIState *ns, Error **errp) +static void spapr_nmi(NMIState *ns) { CPUState *cs; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 21d9f51ddc..06e5def909 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -725,7 +725,7 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, return NULL; } -static void s390_nmi(NMIState *ns, Error **errp) +static void s390_nmi(NMIState *ns) { s390_cpu_restart(S390_CPU(first_cpu)); } diff --git a/include/hw/core/nmi.h b/include/hw/core/nmi.h index a8feac3b67..d71d92dfbb 100644 --- a/include/hw/core/nmi.h +++ b/include/hw/core/nmi.h @@ -40,12 +40,11 @@ struct NMIClass { /** * raise_nmi: Callback to handle NMI notifications. * @ns: Class #NMIState state - * @errp: pointer to error object * * Called by nmi_inject() to perform the machine-specific * action when a NMI is requested. */ - void (*raise_nmi)(NMIState *ns, Error **errp); + void (*raise_nmi)(NMIState *ns); }; /** From c6f9b1dc9564760959e915665d1b4f5d61105be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 Aug 2026 12:43:06 +0200 Subject: [PATCH 294/627] hw/nmi: Raise NMI line only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only expect one device in the system to implement the TYPE_NMI interface (typically the machine, but in a few cases for e.g. m68k and ppc this is an interrupt controller or similar device); so we don't need to keep walking the whole QOM tree once we've found it. As no machine type creates more than one object implementing TYPE_NMI, this is not a behaviour change. Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Marc-André Lureau Message-Id: <20260812121232.71958-8-philmd@oss.qualcomm.com> --- hw/core/nmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index c44b0cf892..84f2166598 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -31,6 +31,11 @@ static int do_nmi(Object *o, void *opaque) if (n) { *handled = true; NMI_GET_CLASS(n)->raise_nmi(n); + /* + * We expect only one object to implement TYPE_NMI, so once + * we've asked it to deliver the NMI we can stop looking. + */ + return 1; } return 0; From 561710e5d2356ed10456e36224a8f4ce9592afa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:58:40 +0200 Subject: [PATCH 295/627] hexagon: Remove unnecessary 'monitor/monitor.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Monitor type is used in these 2 files, as a pointer. Since the type is forward-declared in "qemu/typedefs.h", which all source files include via "qemu/osdep.h", we do not need to include it. Do however include "exec/hwaddr.h" and "exec/mmu-access-type.h" which declare the types used by hex_tlb_find_match prototype: extern bool hex_tlb_find_match(CPUHexagonState *env, uint32_t VA, MMUAccessType access_type, hwaddr *PA, int *prot, ^^^^^^^^^^^^^ ^^^^^^ uint64_t *size, int32_t *excp, int mmu_idx); Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-2-philmd@oss.qualcomm.com> --- include/hw/hexagon/hexagon_tlb.h | 2 +- target/hexagon/hex_mmu.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/hw/hexagon/hexagon_tlb.h b/include/hw/hexagon/hexagon_tlb.h index 90d9ed8404..760dc1ea81 100644 --- a/include/hw/hexagon/hexagon_tlb.h +++ b/include/hw/hexagon/hexagon_tlb.h @@ -12,7 +12,7 @@ #include "qom/object.h" #include "exec/hwaddr.h" #include "exec/mmu-access-type.h" -#include "monitor/monitor.h" + #define TYPE_HEXAGON_TLB "hexagon-tlb" OBJECT_DECLARE_SIMPLE_TYPE(HexagonTLBState, HEXAGON_TLB) diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h index 4f556c715a..6aa450b941 100644 --- a/target/hexagon/hex_mmu.h +++ b/target/hexagon/hex_mmu.h @@ -7,8 +7,9 @@ #ifndef HEXAGON_MMU_H #define HEXAGON_MMU_H +#include "exec/hwaddr.h" +#include "exec/mmu-access-type.h" #include "cpu.h" -#include "monitor/monitor.h" extern void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value); extern uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t VA); From c5162b8423cc96afa46d2a9ac9cc3adba9436e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 18:03:10 +0200 Subject: [PATCH 296/627] net/vhost-vdpa: Include missing 'qemu/iov.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost-vdpa.c uses methods declared in the "qemu/iov." header. Include it otherwise we get when refactoring unrelated headers: ../net/vhost-vdpa.c: In function ‘vhost_vdpa_net_load_cmd’: ../net/vhost-vdpa.c:714:24: error: implicit declaration of function ‘iov_size’ 714 | size_t data_size = iov_size(data_sg, data_num), cmd_size; | ^~~~~~~~ ../net/vhost-vdpa.c:714:24: error: nested extern declaration of ‘iov_size’ ../net/vhost-vdpa.c:742:5: error: implicit declaration of function ‘iov_from_buf’ 742 | iov_from_buf(out_cursor, 1, 0, &ctrl, sizeof(ctrl)); | ^~~~~~~~~~~~ ../net/vhost-vdpa.c:742:5: error: nested extern declaration of ‘iov_from_buf’ ../net/vhost-vdpa.c:744:5: error: implicit declaration of function ‘iov_to_buf’ 744 | iov_to_buf(data_sg, data_num, 0, | ^~~~~~~~~~ ../net/vhost-vdpa.c:744:5: error: nested extern declaration of ‘iov_to_buf’ ../net/vhost-vdpa.c:748:5: error: implicit declaration of function ‘iov_copy’ 748 | iov_copy(&out, 1, out_cursor, 1, 0, cmd_size); | ^~~~~~~~ Fixes: bd907ae4b00 ("vdpa: manual forward CVQ buffers") Signed-off-by: Philippe Mathieu-Daudé Acked-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-3-philmd@oss.qualcomm.com> --- net/vhost-vdpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index c526c2b2dc..1052361a4a 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -17,6 +17,7 @@ #include "hw/virtio/vhost-vdpa.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include "qemu/log.h" #include "qemu/memalign.h" #include "qemu/option.h" From 69cf1ebaf569ee2c7df21153ac8b2f14e65710d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:19:55 +0200 Subject: [PATCH 297/627] tests/unit: Include 'qemu/main-loop.h' header in test-util-sockets.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test-util-sockets.c calls qemu_init_main_loop(), itself declared in the "qemu/main-loop.h" header. Include the latter to avoid when refactoring unrelated headers: ../tests/unit/test-util-sockets.c:553:5: error: call to undeclared function 'qemu_init_main_loop' 553 | qemu_init_main_loop(&error_abort); | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-4-philmd@oss.qualcomm.com> --- tests/unit/test-util-sockets.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index ee66d727c3..ab3f39c3ef 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "qemu/sockets.h" #include "qapi/error.h" #include "socket-helpers.h" From 977d5b5018f13f2a488c0420755f612fc8faf1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:57:02 +0200 Subject: [PATCH 298/627] qapi/qmp-dispatch: Include 'qemu/aio-wait.h' and 'monitor/monitor.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qmp-dispatch.c calls aio_wait_kick() and monitor_cur(). Include the header declaring them in order to avoid the following build failure when refactoring unrelated headers: ../qapi/qmp-dispatch.c:126:12: error: call to undeclared function 'monitor_cur' 126 | assert(monitor_cur() == NULL); | ^ ../qapi/qmp-dispatch.c:141:5: error: call to undeclared function 'aio_wait_kick' 141 | aio_wait_kick(); | ^ Fixes: 41725fa7eda ("qmp: Call monitor_set_cur() only in qmp_dispatch()") Fixes: fc1a2ec7da5 ("monitor: Fix deadlock in monitor_cleanup") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-5-philmd@oss.qualcomm.com> --- qapi/qmp-dispatch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index e3897d5197..965cad6499 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qemu/aio.h" +#include "qemu/aio-wait.h" #include "qapi/compat-policy.h" #include "qapi/error.h" #include "qapi/qmp-registry.h" @@ -24,6 +25,7 @@ #include "qobject/qbool.h" #include "qemu/coroutine.h" #include "qemu/main-loop.h" +#include "monitor/monitor.h" Visitor *qobject_input_visitor_new_qmp(QObject *obj) { From 9829b98dd1ccf3a5e8e4145c50e2853d13802b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:58:04 +0200 Subject: [PATCH 299/627] qapi/qmp-registry: Remove unnecessary 'monitor/monitor.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-6-philmd@oss.qualcomm.com> --- include/qapi/qmp-registry.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/qapi/qmp-registry.h b/include/qapi/qmp-registry.h index e0ee1ad3ac..6146306a3a 100644 --- a/include/qapi/qmp-registry.h +++ b/include/qapi/qmp-registry.h @@ -14,7 +14,6 @@ #ifndef QAPI_QMP_DISPATCH_H #define QAPI_QMP_DISPATCH_H -#include "monitor/monitor.h" #include "qemu/queue.h" typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); From cca454be70f02ee1f77474d444e38620bf60c446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:09:41 +0200 Subject: [PATCH 300/627] migration/hmp-cmds: Include 'block/block-global-state.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit migration-hmp-cmds.c uses types / methods declared in "block/block-global-state.h". Include the latter otherwise we get when refactoring unrelated headers: ../migration/migration-hmp-cmds.c:911:5: error: use of undeclared identifier 'BdrvNextIterator' 911 | BdrvNextIterator it; | ^ ../migration/migration-hmp-cmds.c:918:15: error: call to undeclared function 'bdrv_first' 918 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Reviewed-by: Dr. David Alan Gilbert Message-Id: <20260812211708.92824-7-philmd@oss.qualcomm.com> --- migration/migration-hmp-cmds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index b5eb27467c..ad68fa23aa 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -15,6 +15,7 @@ #include "qemu/osdep.h" #include "block/qapi.h" +#include "block/block-global-state.h" #include "migration/snapshot.h" #include "monitor/hmp.h" #include "monitor/hmp-completion.h" From 79a71f3a49f106282447598b9ebb0e78cfc47425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:13:48 +0200 Subject: [PATCH 301/627] monitor: Include missing 'qemu/aio-wait.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both monitor.c and qmp.c use types / methods declared in "qemu/aio-wait.h". Include the latter to avoid the following errors when refactoring unrelated headers: ../monitor/monitor.c:648:5: error: call to undeclared function 'AIO_WAIT_WHILE_UNLOCKED' 648 | AIO_WAIT_WHILE_UNLOCKED(NULL, | ^ ../monitor/qmp.c:792:9: error: call to undeclared function 'aio_wait_bh_oneshot' 792 | aio_wait_bh_oneshot(iothread_get_aio_context(mon_iothread), | ^ Fixes: 9ce44e2ce26 ("qmp: Move dispatcher to a coroutine") Fixes: a5df506e129 ("monitor: implement support for deleting QMP objects") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-8-philmd@oss.qualcomm.com> --- monitor/monitor.c | 1 + monitor/qmp.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/monitor/monitor.c b/monitor/monitor.c index ed195fd97b..c75ae81534 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -30,6 +30,7 @@ #include "qapi/qapi-visit-control.h" #include "qobject/qdict.h" #include "qom/object_interfaces.h" +#include "qemu/aio-wait.h" #include "qemu/error-report.h" #include "qemu/option.h" #include "system/qtest.h" diff --git a/monitor/qmp.c b/monitor/qmp.c index 338d37cb7e..6ae1098d39 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" - +#include "qemu/aio-wait.h" #include "chardev/char-io.h" #include "monitor-internal.h" #include "qapi/error.h" From e883c338dd1997a4e06a5f3be8ea53310b3a44ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:10:29 +0200 Subject: [PATCH 302/627] monitor: Include missing 'qemu/lockable.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files in monitor/ use the QEMU_LOCK_GUARD() macros, which are declared in "qemu/lockable.h". Include the latter to avoid when refactoring unrelated headers: ../monitor/fds.c:146:5: error: call to undeclared function 'QEMU_LOCK_GUARD' 146 | QEMU_LOCK_GUARD(&mon->mon_lock); | ^ ../monitor/monitor.c:176:5: error: call to undeclared function 'QEMU_LOCK_GUARD' 176 | QEMU_LOCK_GUARD(&mon->mon_lock); | ^ ../monitor/qmp.c:164:5: error: call to undeclared function 'WITH_QEMU_LOCK_GUARD' 164 | WITH_QEMU_LOCK_GUARD(&mon->mon_lock) { | ^ Fixes: 0210c3b39be ("monitor: Use LOCK_GUARD macros") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-9-philmd@oss.qualcomm.com> --- monitor/fds.c | 1 + monitor/monitor.c | 1 + monitor/qmp.c | 1 + 3 files changed, 3 insertions(+) diff --git a/monitor/fds.c b/monitor/fds.c index cc35d2ec33..abe5f13487 100644 --- a/monitor/fds.c +++ b/monitor/fds.c @@ -29,6 +29,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/ctype.h" #include "qemu/cutils.h" +#include "qemu/lockable.h" #include "system/runstate.h" /* file descriptors passed via SCM_RIGHTS */ diff --git a/monitor/monitor.c b/monitor/monitor.c index c75ae81534..6af09f2f6e 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -32,6 +32,7 @@ #include "qom/object_interfaces.h" #include "qemu/aio-wait.h" #include "qemu/error-report.h" +#include "qemu/lockable.h" #include "qemu/option.h" #include "system/qtest.h" #include "trace.h" diff --git a/monitor/qmp.c b/monitor/qmp.c index 6ae1098d39..aec0315775 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/aio-wait.h" +#include "qemu/lockable.h" #include "chardev/char-io.h" #include "monitor-internal.h" #include "qapi/error.h" From 25780a68e335d17ee068dcfcf49c5575ceae0591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:16:05 +0200 Subject: [PATCH 303/627] monitor: Include missing 'qemu/coroutine-core.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "monitor/monitor.h" declares monitor_set_cur() which use the 'Coroutine' type, itself declared in "qemu/coroutine-core.h". Include the latter to avoid when refactoring unrelated headers: In file included from ../../target/sh4/monitor.c:26: qemu/include/monitor/monitor.h:32:26: error: unknown type name 'Coroutine' 32 | Monitor *monitor_set_cur(Coroutine *co, Monitor *mon); | ^ Fixes: e69ee454b5f ("monitor: Make current monitor a per-coroutine property") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-10-philmd@oss.qualcomm.com> --- include/monitor/monitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 890497b0d2..efdd2165aa 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -4,6 +4,7 @@ #include "block/block.h" #include "qapi/qapi-types-misc.h" #include "qapi/qapi-emit-events.h" +#include "qemu/coroutine-core.h" #include "qemu/readline.h" #include "exec/hwaddr.h" #include "qom/object.h" From 880584428002db3b5db3c24d3e5e2d59da9f32cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:27:57 +0200 Subject: [PATCH 304/627] monitor: Reduce inclusion of 'qapi/qapi-emit-events.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "monitor/monitor.h" don't use anything declared in the generated "qapi/qapi-emit-events.h" header. However the "monitor/monitor-internal.h" do: 107 struct MonitorClass { ... 116 /* 117 * If non-NULL, the monitor is able to send event 118 * notifications back to the client 119 */ 120 void (*emit_event)(Monitor *mon, QAPIEvent event, QDict *qdict); ^^^^^^^^^ Move the header inclusion to "monitor/monitor-internal.h" to avoid including / re-exposing unnecessary declarations in the global "monitor/monitor.h" header. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-11-philmd@oss.qualcomm.com> --- include/monitor/monitor.h | 1 - monitor/monitor-internal.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index efdd2165aa..fa9f4a8a75 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -3,7 +3,6 @@ #include "block/block.h" #include "qapi/qapi-types-misc.h" -#include "qapi/qapi-emit-events.h" #include "qemu/coroutine-core.h" #include "qemu/readline.h" #include "exec/hwaddr.h" diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 23829f32f9..bc0932c425 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -27,6 +27,7 @@ #include "chardev/char-fe.h" #include "monitor/monitor.h" +#include "qapi/qapi-emit-events.h" #include "qapi/qapi-types-control.h" #include "qapi/qapi-types-qom.h" #include "qapi/qmp-registry.h" From 2697e7199a61a87964df0f202144f80b1f29a8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 11:15:01 +0200 Subject: [PATCH 305/627] monitor: Remove unnecessary 'block/block.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing here requires declarations from "block/block.h" anymore. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-12-philmd@oss.qualcomm.com> --- include/monitor/monitor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index fa9f4a8a75..fd98ee2c71 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -1,7 +1,6 @@ #ifndef MONITOR_H #define MONITOR_H -#include "block/block.h" #include "qapi/qapi-types-misc.h" #include "qemu/coroutine-core.h" #include "qemu/readline.h" From bd2871ac5031dde689ca42e2c3e4492da403d853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:40:56 +0200 Subject: [PATCH 306/627] system: Remove unnecessary 'monitor/monitor.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No code in device_tree.c or physmem.c require declarations from "monitor/monitor.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-13-philmd@oss.qualcomm.com> --- system/device_tree.c | 1 - system/physmem.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/system/device_tree.c b/system/device_tree.c index 1ea1962984..48365435ea 100644 --- a/system/device_tree.c +++ b/system/device_tree.c @@ -29,7 +29,6 @@ #include "qemu/config-file.h" #include "qapi/qapi-commands-machine.h" #include "qobject/qdict.h" -#include "monitor/hmp.h" #include diff --git a/system/physmem.c b/system/physmem.c index 2f37cbeb07..362a00f76c 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -84,8 +84,6 @@ #include "qemu/mmap-alloc.h" #endif -#include "monitor/monitor.h" - #ifdef CONFIG_LIBDAXCTL #include #endif From c339d8459e9dce4d1ccd1e8f636138c348d00f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:39:23 +0200 Subject: [PATCH 307/627] system/dirtylimit: Extract HMP code to dirtylimit-hmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Reviewed-by: Hyman Huang Message-Id: <20260812211708.92824-14-philmd@oss.qualcomm.com> --- MAINTAINERS | 1 + system/dirtylimit-hmp-cmds.c | 74 ++++++++++++++++++++++++++++++++++++ system/dirtylimit.c | 60 ----------------------------- system/meson.build | 1 + 4 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 system/dirtylimit-hmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index c296dd5abf..bad65aeda5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3875,6 +3875,7 @@ Migration dirty limit and dirty page rate M: Hyman Huang S: Maintained F: system/dirtylimit.c +F: system/dirtylimit-hmp-cmds.c F: include/system/dirtylimit.h F: migration/dirtyrate.c F: migration/dirtyrate.h diff --git a/system/dirtylimit-hmp-cmds.c b/system/dirtylimit-hmp-cmds.c new file mode 100644 index 0000000000..4928d57cc8 --- /dev/null +++ b/system/dirtylimit-hmp-cmds.c @@ -0,0 +1,74 @@ +/* + * HMP commands related to migration dirty page rate limit + * + * Copyright (c) 2022 CHINA TELECOM CO.,LTD. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-migration.h" +#include "qobject/qdict.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "system/dirtylimit.h" + +void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); + Error *err = NULL; + + qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); + if (err) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " + "dirty limit for virtual CPU]\n"); +} + +void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); + int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); + Error *err = NULL; + + if (dirty_rate < 0) { + error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); + goto out; + } + + qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); + +out: + hmp_handle_error(mon, err); +} + +void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) +{ + DirtyLimitInfoList *info; + g_autoptr(DirtyLimitInfoList) head = NULL; + Error *err = NULL; + + if (!dirtylimit_in_service()) { + monitor_printf(mon, "Dirty page limit not enabled!\n"); + return; + } + + head = qmp_query_vcpu_dirty_limit(&err); + if (err) { + hmp_handle_error(mon, err); + return; + } + + for (info = head; info != NULL; info = info->next) { + monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," + " current rate %"PRIi64 " (MB/s)\n", + info->value->cpu_index, + info->value->limit_rate, + info->value->current_rate); + } +} diff --git a/system/dirtylimit.c b/system/dirtylimit.c index 50fa67f3d6..70bb7bac2d 100644 --- a/system/dirtylimit.c +++ b/system/dirtylimit.c @@ -17,8 +17,6 @@ #include "qapi/error.h" #include "system/dirtyrate.h" #include "system/dirtylimit.h" -#include "monitor/hmp.h" -#include "monitor/monitor.h" #include "system/memory.h" #include "exec/target_page.h" #include "hw/core/boards.h" @@ -491,21 +489,6 @@ void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } -void hmp_cancel_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) -{ - int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); - Error *err = NULL; - - qmp_cancel_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, &err); - if (err) { - hmp_handle_error(mon, err); - return; - } - - monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " - "dirty limit for virtual CPU]\n"); -} - void qmp_set_vcpu_dirty_limit(bool has_cpu_index, int64_t cpu_index, uint64_t dirty_rate, @@ -548,23 +531,6 @@ void qmp_set_vcpu_dirty_limit(bool has_cpu_index, dirtylimit_state_unlock(); } -void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) -{ - int64_t dirty_rate = qdict_get_int(qdict, "dirty_rate"); - int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); - Error *err = NULL; - - if (dirty_rate < 0) { - error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); - goto out; - } - - qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); - -out: - hmp_handle_error(mon, err); -} - /* Return the max throttle time of each virtual CPU */ uint64_t dirtylimit_throttle_time_per_round(void) { @@ -646,29 +612,3 @@ struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) { return dirtylimit_query_all(); } - -void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) -{ - DirtyLimitInfoList *info; - g_autoptr(DirtyLimitInfoList) head = NULL; - Error *err = NULL; - - if (!dirtylimit_in_service()) { - monitor_printf(mon, "Dirty page limit not enabled!\n"); - return; - } - - head = qmp_query_vcpu_dirty_limit(&err); - if (err) { - hmp_handle_error(mon, err); - return; - } - - for (info = head; info != NULL; info = info->next) { - monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," - " current rate %"PRIi64 " (MB/s)\n", - info->value->cpu_index, - info->value->limit_rate, - info->value->current_rate); - } -} diff --git a/system/meson.build b/system/meson.build index cd3193d170..377adce803 100644 --- a/system/meson.build +++ b/system/meson.build @@ -9,6 +9,7 @@ system_ss.add(files( 'cpus.c', 'cpu-timers.c', 'dirtylimit.c', + 'dirtylimit-hmp-cmds.c', 'dma-helpers.c', 'exit-with-parent.c', 'globals.c', From 5bd649ccf93a6daa26888015deb6bfbc6d764d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 14:45:03 +0200 Subject: [PATCH 308/627] system: Move qmp_inject_nmi() to hw/core/machine-qmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We figured NMI relates to machines (for their machine-specific handling), so move the 'inject-nmi' QMP handler with the rest of machine ones, in hw/core/machine-qmp-cmds.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-15-philmd@oss.qualcomm.com> --- hw/core/machine-qmp-cmds.c | 6 ++++++ system/cpus.c | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index e62cb4ec88..1aa5f26229 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "hw/acpi/vmgenid.h" #include "hw/core/boards.h" +#include "hw/core/nmi.h" #include "hw/intc/intc.h" #include "hw/mem/memory-device.h" #include "qapi/error.h" @@ -448,3 +449,8 @@ void qmp_dump_skeys(const char *filename, Error **errp) } DUMP_SKEYS_INTERFACE_CLASS(oc)->qmp_dump_skeys(filename, errp); } + +void qmp_inject_nmi(Error **errp) +{ + nmi_inject(errp); +} diff --git a/system/cpus.c b/system/cpus.c index 9758cda463..aa2510bf8f 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -26,7 +26,6 @@ #include "qemu/coroutine-tls.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" -#include "qapi/qapi-commands-misc.h" #include "qapi/qapi-events-run-state.h" #include "qapi/qmp/qerror.h" #include "exec/gdbstub.h" @@ -38,7 +37,6 @@ #include "qemu/plugin.h" #include "system/cpus.h" #include "qemu/guest-random.h" -#include "hw/core/nmi.h" #include "system/physmem.h" #include "system/replay.h" #include "system/runstate.h" @@ -922,9 +920,3 @@ void qmp_pmemsave(uint64_t addr, uint64_t size, const char *filename, exit: fclose(f); } - -void qmp_inject_nmi(Error **errp) -{ - nmi_inject(errp); -} - From 259c2aae8d24b7ef4631e11ed14b7b32795127f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 14:53:58 +0200 Subject: [PATCH 309/627] system: Extract QMP memsave/pmemsave commands to physmem-qmp-cmds.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep cpus.c related to vCPU scheduling, move the QMP handlers related to dumping physical memory to file to their own unit. Fix a pair of checkpatch.pl errors doing so: ERROR: braces {} are necessary for all arms of this statement #185: FILE: system/physmem-qmp-cmds.c:51: + if (l > size) [...] Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-16-philmd@oss.qualcomm.com> --- MAINTAINERS | 1 + system/cpus.c | 92 -------------------------------- system/meson.build | 1 + system/physmem-qmp-cmds.c | 107 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 system/physmem-qmp-cmds.c diff --git a/MAINTAINERS b/MAINTAINERS index bad65aeda5..b51f5c3e60 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3436,6 +3436,7 @@ F: system/ioport.c F: system/memory.c F: system/memory_mapping.c F: system/physmem.c +F: system/physmem-qmp-cmds.c F: system/memory_ldst* F: system/memory-internal.h F: system/ram-block-attributes.c diff --git a/system/cpus.c b/system/cpus.c index aa2510bf8f..43ff10cf00 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -25,9 +25,7 @@ #include "qemu/osdep.h" #include "qemu/coroutine-tls.h" #include "qapi/error.h" -#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-events-run-state.h" -#include "qapi/qmp/qerror.h" #include "exec/gdbstub.h" #include "accel/accel-cpu-ops.h" #include "system/hw_accel.h" @@ -40,7 +38,6 @@ #include "system/physmem.h" #include "system/replay.h" #include "system/runstate.h" -#include "migration/misc.h" #include "system/cpu-timers.h" #include "system/whpx.h" #include "hw/core/boards.h" @@ -831,92 +828,3 @@ int vm_stop_force_state(RunState state) return ret; } } - -void qmp_memsave(uint64_t addr, uint64_t size, const char *filename, - bool has_cpu, int64_t cpu_index, Error **errp) -{ - FILE *f; - uint64_t l; - CPUState *cpu; - uint8_t buf[1024]; - uint64_t orig_addr = addr, orig_size = size; - - if (migration_guest_ram_loading()) { - error_setg(errp, "Guest memory access not allowed during migration"); - return; - } - - if (!has_cpu) { - cpu_index = 0; - } - - cpu = qemu_get_cpu(cpu_index); - if (cpu == NULL) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", - "a CPU number"); - return; - } - - f = fopen(filename, "wb"); - if (!f) { - error_setg_file_open(errp, errno, filename); - return; - } - - while (size != 0) { - l = sizeof(buf); - if (l > size) - l = size; - if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) { - error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRIu64 - " specified", orig_addr, orig_size); - goto exit; - } - if (fwrite(buf, 1, l, f) != l) { - error_setg(errp, "writing memory to '%s' failed", - filename); - goto exit; - } - addr += l; - size -= l; - } - -exit: - fclose(f); -} - -void qmp_pmemsave(uint64_t addr, uint64_t size, const char *filename, - Error **errp) -{ - FILE *f; - uint64_t l; - uint8_t buf[1024]; - - if (migration_guest_ram_loading()) { - error_setg(errp, "Guest memory access not allowed during migration"); - return; - } - - f = fopen(filename, "wb"); - if (!f) { - error_setg_file_open(errp, errno, filename); - return; - } - - while (size != 0) { - l = sizeof(buf); - if (l > size) - l = size; - physical_memory_read(addr, buf, l); - if (fwrite(buf, 1, l, f) != l) { - error_setg(errp, "writing memory to '%s' failed", - filename); - goto exit; - } - addr += l; - size -= l; - } - -exit: - fclose(f); -} diff --git a/system/meson.build b/system/meson.build index 377adce803..64e06e7abc 100644 --- a/system/meson.build +++ b/system/meson.build @@ -19,6 +19,7 @@ system_ss.add(files( 'memory_mapping.c', 'memory.c', 'physmem.c', + 'physmem-qmp-cmds.c', 'qdev-monitor.c', 'qtest.c', 'rtc.c', diff --git a/system/physmem-qmp-cmds.c b/system/physmem-qmp-cmds.c new file mode 100644 index 0000000000..d85430357d --- /dev/null +++ b/system/physmem-qmp-cmds.c @@ -0,0 +1,107 @@ +/* + * QMP commands to dump physical memory + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" +#include "qapi/qmp/qerror.h" +#include "hw/core/cpu.h" +#include "system/physmem.h" +#include "migration/misc.h" + +void qmp_memsave(uint64_t addr, uint64_t size, const char *filename, + bool has_cpu, int64_t cpu_index, Error **errp) +{ + FILE *f; + uint64_t l; + CPUState *cpu; + uint8_t buf[1024]; + uint64_t orig_addr = addr, orig_size = size; + + if (migration_guest_ram_loading()) { + error_setg(errp, "Guest memory access not allowed during migration"); + return; + } + + if (!has_cpu) { + cpu_index = 0; + } + + cpu = qemu_get_cpu(cpu_index); + if (cpu == NULL) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", + "a CPU number"); + return; + } + + f = fopen(filename, "wb"); + if (!f) { + error_setg_file_open(errp, errno, filename); + return; + } + + while (size != 0) { + l = sizeof(buf); + if (l > size) { + l = size; + } + if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) { + error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRIu64 + " specified", orig_addr, orig_size); + goto exit; + } + if (fwrite(buf, 1, l, f) != l) { + error_setg(errp, "writing memory to '%s' failed", + filename); + goto exit; + } + addr += l; + size -= l; + } + +exit: + fclose(f); +} + +void qmp_pmemsave(uint64_t addr, uint64_t size, const char *filename, + Error **errp) +{ + FILE *f; + uint64_t l; + uint8_t buf[1024]; + + if (migration_guest_ram_loading()) { + error_setg(errp, "Guest memory access not allowed during migration"); + return; + } + + f = fopen(filename, "wb"); + if (!f) { + error_setg_file_open(errp, errno, filename); + return; + } + + while (size != 0) { + l = sizeof(buf); + if (l > size) { + l = size; + } + physical_memory_read(addr, buf, l); + if (fwrite(buf, 1, l, f) != l) { + error_setg(errp, "writing memory to '%s' failed", + filename); + goto exit; + } + addr += l; + size -= l; + } + +exit: + fclose(f); +} From f036b28896f615eacbe70e89bc9966249c74b99d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 10:41:57 +0200 Subject: [PATCH 310/627] system: Move runstate-related code from cpus.c to runstate.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep cpus.c focused on vCPUs handling, move code related to VM state to runstate.c where similar code lives. Fix few checkpatch.pl warnings: WARNING: Block comments use a leading /* on a separate line WARNING: Block comments use * on subsequent lines #327: FILE: system/runstate.c:541: +/* does a state transition even if the VM is already stopped, + current state is forgotten forever */ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-17-philmd@oss.qualcomm.com> --- system/cpus.c | 147 ------------------------------------------- system/runstate.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 147 deletions(-) diff --git a/system/cpus.c b/system/cpus.c index 43ff10cf00..f37e215c58 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qemu/coroutine-tls.h" #include "qapi/error.h" -#include "qapi/qapi-events-run-state.h" #include "exec/gdbstub.h" #include "accel/accel-cpu-ops.h" #include "system/hw_accel.h" @@ -272,58 +271,6 @@ void cpu_interrupt(CPUState *cpu, int mask) cpus_accel->handle_interrupt(cpu, mask); } -/* - * True if the vm was previously suspended, and has not been woken or reset. - */ -static int vm_was_suspended; - -void vm_set_suspended(bool suspended) -{ - vm_was_suspended = suspended; -} - -bool vm_get_suspended(void) -{ - return vm_was_suspended; -} - -static int do_vm_stop(RunState state, bool send_stop) -{ - int ret = 0; - RunState oldstate = runstate_get(); - - if (runstate_is_live(oldstate)) { - vm_was_suspended = (oldstate == RUN_STATE_SUSPENDED); - runstate_set(state); - cpu_disable_ticks(); - if (oldstate == RUN_STATE_RUNNING) { - pause_all_vcpus(); - } - ret = vm_state_notify(0, state); - if (send_stop) { - qapi_event_send_stop(); - } - } - - bdrv_drain_all(); - /* - * Even if vm_state_notify() return failure, - * it would be better to flush as before. - */ - ret |= bdrv_flush_all(); - trace_vm_stop_flush_all(ret); - - return ret; -} - -/* Special vm_stop() variant for terminating the process. Historically clients - * did not expect a QMP STOP event and so we need to retain compatibility. - */ -int vm_shutdown(void) -{ - return do_vm_stop(RUN_STATE_SHUTDOWN, false); -} - bool cpu_can_run(CPUState *cpu) { if (cpu->stop) { @@ -734,97 +681,3 @@ void cpu_stop_current(void) cpu_exit(current_cpu); } } - -int vm_stop(RunState state) -{ - if (qemu_in_vcpu_thread()) { - qemu_system_vmstop_request_prepare(); - qemu_system_vmstop_request(state); - /* - * FIXME: should not return to device code in case - * vm_stop() has been requested. - */ - cpu_stop_current(); - return 0; - } - - return do_vm_stop(state, true); -} - -/** - * Prepare for (re)starting the VM. - * Returns 0 if the vCPUs should be restarted, -1 on an error condition, - * and 1 otherwise. - */ -int vm_prepare_start(bool step_pending) -{ - int ret = vm_was_suspended ? 1 : 0; - RunState state = vm_was_suspended ? RUN_STATE_SUSPENDED : RUN_STATE_RUNNING; - RunState requested; - - qemu_vmstop_requested(&requested); - if (runstate_is_running() && requested == RUN_STATE__MAX) { - return -1; - } - - /* Ensure that a STOP/RESUME pair of events is emitted if a - * vmstop request was pending. The BLOCK_IO_ERROR event, for - * example, according to documentation is always followed by - * the STOP event. - */ - if (runstate_is_running()) { - qapi_event_send_stop(); - qapi_event_send_resume(); - return -1; - } - - /* - * WHPX accelerator needs to know whether we are going to step - * any CPUs, before starting the first one. - */ - accel_pre_resume(MACHINE(qdev_get_machine()), step_pending); - - /* We are sending this now, but the CPUs will be resumed shortly later */ - qapi_event_send_resume(); - - cpu_enable_ticks(); - runstate_set(state); - vm_state_notify(1, state); - vm_was_suspended = false; - return ret; -} - -void vm_start(void) -{ - if (!vm_prepare_start(false)) { - resume_all_vcpus(); - } -} - -void vm_resume(RunState state) -{ - if (runstate_is_live(state)) { - vm_start(); - } else { - runstate_set(state); - } -} - -/* does a state transition even if the VM is already stopped, - current state is forgotten forever */ -int vm_stop_force_state(RunState state) -{ - if (runstate_is_live(runstate_get())) { - return vm_stop(state); - } else { - int ret; - runstate_set(state); - - bdrv_drain_all(); - /* Make sure to return an error if the flush in a previous vm_stop() - * failed. */ - ret = bdrv_flush_all(); - trace_vm_stop_flush_all(ret); - return ret; - } -} diff --git a/system/runstate.c b/system/runstate.c index 08acf801b0..d3e64d2b62 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -52,6 +52,7 @@ #include "qemu/thread.h" #include "qom/object.h" #include "qom/object_interfaces.h" +#include "system/cpu-timers.h" #include "system/cpus.h" #include "system/qtest.h" #include "system/replay.h" @@ -408,6 +409,159 @@ int vm_state_notify(bool running, RunState state) return ret; } +/* + * True if the vm was previously suspended, and has not been woken or reset. + */ +static int vm_was_suspended; + +void vm_set_suspended(bool suspended) +{ + vm_was_suspended = suspended; +} + +bool vm_get_suspended(void) +{ + return vm_was_suspended; +} + +static int do_vm_stop(RunState state, bool send_stop) +{ + int ret = 0; + RunState oldstate = runstate_get(); + + if (runstate_is_live(oldstate)) { + vm_was_suspended = (oldstate == RUN_STATE_SUSPENDED); + runstate_set(state); + cpu_disable_ticks(); + if (oldstate == RUN_STATE_RUNNING) { + pause_all_vcpus(); + } + ret = vm_state_notify(0, state); + if (send_stop) { + qapi_event_send_stop(); + } + } + + bdrv_drain_all(); + /* + * Even if vm_state_notify() return failure, + * it would be better to flush as before. + */ + ret |= bdrv_flush_all(); + trace_vm_stop_flush_all(ret); + + return ret; +} + +/* + * Special vm_stop() variant for terminating the process. Historically clients + * did not expect a QMP STOP event and so we need to retain compatibility. + */ +int vm_shutdown(void) +{ + return do_vm_stop(RUN_STATE_SHUTDOWN, false); +} + + +int vm_stop(RunState state) +{ + if (qemu_in_vcpu_thread()) { + qemu_system_vmstop_request_prepare(); + qemu_system_vmstop_request(state); + /* + * FIXME: should not return to device code in case + * vm_stop() has been requested. + */ + cpu_stop_current(); + return 0; + } + + return do_vm_stop(state, true); +} + +/** + * Prepare for (re)starting the VM. + * Returns 0 if the vCPUs should be restarted, -1 on an error condition, + * and 1 otherwise. + */ +int vm_prepare_start(bool step_pending) +{ + int ret = vm_was_suspended ? 1 : 0; + RunState state = vm_was_suspended ? RUN_STATE_SUSPENDED : RUN_STATE_RUNNING; + RunState requested; + + qemu_vmstop_requested(&requested); + if (runstate_is_running() && requested == RUN_STATE__MAX) { + return -1; + } + + /* + * Ensure that a STOP/RESUME pair of events is emitted if a + * vmstop request was pending. The BLOCK_IO_ERROR event, for + * example, according to documentation is always followed by + * the STOP event. + */ + if (runstate_is_running()) { + qapi_event_send_stop(); + qapi_event_send_resume(); + return -1; + } + + /* + * WHPX accelerator needs to know whether we are going to step + * any CPUs, before starting the first one. + */ + accel_pre_resume(MACHINE(qdev_get_machine()), step_pending); + + /* We are sending this now, but the CPUs will be resumed shortly later */ + qapi_event_send_resume(); + + cpu_enable_ticks(); + runstate_set(state); + vm_state_notify(1, state); + vm_was_suspended = false; + return ret; +} + +void vm_start(void) +{ + if (!vm_prepare_start(false)) { + resume_all_vcpus(); + } +} + +void vm_resume(RunState state) +{ + if (runstate_is_live(state)) { + vm_start(); + } else { + runstate_set(state); + } +} + +/* + * does a state transition even if the VM is already stopped, + * current state is forgotten forever + */ +int vm_stop_force_state(RunState state) +{ + if (runstate_is_live(runstate_get())) { + return vm_stop(state); + } else { + int ret; + runstate_set(state); + + bdrv_drain_all(); + /* + * Make sure to return an error if the flush in a previous vm_stop() + * failed. + */ + ret = bdrv_flush_all(); + trace_vm_stop_flush_all(ret); + return ret; + } +} + static ShutdownCause reset_requested; static ShutdownCause shutdown_requested; static int shutdown_exit_code = EXIT_SUCCESS; From e1212b51811bf95eaf384a9a97c481a2b888e03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 19:48:52 +0200 Subject: [PATCH 311/627] monitor: Rename MonitorHMP @mon -> @hmp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mechanical change to sanitize using the following patterns: MonitorQMP *qmp MonitorHMP *hmp Monitor *mon Rename @mon (and @hmp_mon) as @hmp when the type is MonitorHMP. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20260812211708.92824-19-philmd@oss.qualcomm.com> Acked-by: Marc-André Lureau --- include/monitor/monitor.h | 4 +- monitor/hmp-cmds.c | 6 +- monitor/hmp.c | 135 +++++++++++++++++++------------------ monitor/monitor-internal.h | 2 +- ui/ui-hmp-cmds.c | 4 +- 5 files changed, 76 insertions(+), 75 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index fd98ee2c71..54134f2aa4 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -55,8 +55,8 @@ void monitor_flush_locked(Monitor *mon); void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp); -void monitor_read_command(MonitorHMP *mon, int show_prompt); -int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, +void monitor_read_command(MonitorHMP *hmp, int show_prompt); +int monitor_read_password(MonitorHMP *hmp, ReadLineFunc *readline_func, void *opaque); AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index e9fb8d827a..bcd0a1fc87 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -290,16 +290,16 @@ void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) void hmp_info_history(Monitor *mon, const QDict *qdict) { - MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj); + MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); int i; const char *str; - if (!hmp_mon->rs) { + if (!hmp->rs) { return; } i = 0; for(;;) { - str = readline_get_history(hmp_mon->rs, i); + str = readline_get_history(hmp->rs, i); if (!str) { break; } diff --git a/monitor/hmp.c b/monitor/hmp.c index 71a1888249..cbf7a114c0 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -49,24 +49,24 @@ OBJECT_DEFINE_TYPE(MonitorHMP, monitor_hmp, MONITOR_HMP, MONITOR); static void monitor_hmp_finalize(Object *obj) { - MonitorHMP *mon = MONITOR_HMP(obj); - if (mon->rs) { - readline_free(mon->rs); + MonitorHMP *hmp = MONITOR_HMP(obj); + if (hmp->rs) { + readline_free(hmp->rs); } } static bool monitor_hmp_get_readline(Object *obj, Error **errp) { - MonitorHMP *mon = MONITOR_HMP(obj); + MonitorHMP *hmp = MONITOR_HMP(obj); - return mon->use_readline; + return hmp->use_readline; } static void monitor_hmp_set_readline(Object *obj, bool val, Error **errp) { - MonitorHMP *mon = MONITOR_HMP(obj); + MonitorHMP *hmp = MONITOR_HMP(obj); - mon->use_readline = val; + hmp->use_readline = val; } int monitor_hmp_vprintf(Monitor *mon, const char *fmt, va_list ap) @@ -128,34 +128,34 @@ static void monitor_hmp_accept_input(Monitor *mon) static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque) { - MonitorHMP *mon = opaque; + MonitorHMP *hmp = opaque; - monitor_suspend(&mon->parent_obj); - handle_hmp_command(mon, cmdline); - monitor_resume(&mon->parent_obj); + monitor_suspend(&hmp->parent_obj); + handle_hmp_command(hmp, cmdline); + monitor_resume(&hmp->parent_obj); } -void monitor_read_command(MonitorHMP *mon, int show_prompt) +void monitor_read_command(MonitorHMP *hmp, int show_prompt) { - if (!mon->rs) { + if (!hmp->rs) { return; } - readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL); + readline_start(hmp->rs, "(qemu) ", 0, monitor_command_cb, NULL); if (show_prompt) { - readline_show_prompt(mon->rs); + readline_show_prompt(hmp->rs); } } -int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, +int monitor_read_password(MonitorHMP *hmp, ReadLineFunc *readline_func, void *opaque) { - if (mon->rs) { - readline_start(mon->rs, "Password: ", 1, readline_func, opaque); + if (hmp->rs) { + readline_start(hmp->rs, "Password: ", 1, readline_func, opaque); /* prompt is printed on return from the command handler */ return 0; } else { - monitor_printf(&mon->parent_obj, + monitor_printf(&hmp->parent_obj, "terminal does not support password prompting\n"); return -ENOTTY; } @@ -772,12 +772,12 @@ static const HMPCommand *search_dispatch_table(const HMPCommand *disp_table, * Do not assume the return value points into @table! It doesn't when * the command is found in a sub-command table. */ -static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, +static const HMPCommand *monitor_parse_command(MonitorHMP *hmp, const char *cmdp_start, const char **cmdp, HMPCommand *table) { - Monitor *mon = &hmp_mon->parent_obj; + Monitor *mon = &hmp->parent_obj; const char *p; const HMPCommand *cmd; char cmdname[256]; @@ -809,7 +809,7 @@ static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, *cmdp = p; /* search sub command */ if (cmd->sub_table != NULL && *p != '\0') { - return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table); + return monitor_parse_command(hmp, cmdp_start, cmdp, cmd->sub_table); } return cmd; @@ -1254,15 +1254,15 @@ static void handle_hmp_command_co(void *opaque) data->done = true; } -void handle_hmp_command(MonitorHMP *mon, const char *cmdline) +void handle_hmp_command(MonitorHMP *hmp, const char *cmdline) { QDict *qdict; const HMPCommand *cmd; const char *cmd_start = cmdline; - trace_handle_hmp_command(mon, cmdline); + trace_handle_hmp_command(hmp, cmdline); - cmd = monitor_parse_command(mon, cmdline, &cmdline, + cmd = monitor_parse_command(hmp, cmdline, &cmdline, hmp_cmds_for_target(false)); if (!cmd) { return; @@ -1270,17 +1270,17 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) if (!cmd->cmd && !cmd->cmd_info_hrt) { /* FIXME: is it useful to try autoload modules here ??? */ - monitor_printf(&mon->parent_obj, "Command \"%.*s\" is not available.\n", + monitor_printf(&hmp->parent_obj, "Command \"%.*s\" is not available.\n", (int)(cmdline - cmd_start), cmd_start); return; } - qdict = monitor_parse_arguments(&mon->parent_obj, &cmdline, cmd); + qdict = monitor_parse_arguments(&hmp->parent_obj, &cmdline, cmd); if (!qdict) { while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) { cmdline--; } - monitor_printf(&mon->parent_obj, + monitor_printf(&hmp->parent_obj, "Try \"help %.*s\" for more information\n", (int)(cmdline - cmd_start), cmd_start); return; @@ -1289,18 +1289,18 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) if (!cmd->coroutine) { /* old_mon is non-NULL when called from qmp_human_monitor_command() */ Monitor *old_mon = monitor_set_cur(qemu_coroutine_self(), - &mon->parent_obj); - handle_hmp_command_exec(&mon->parent_obj, cmd, qdict); + &hmp->parent_obj); + handle_hmp_command_exec(&hmp->parent_obj, cmd, qdict); monitor_set_cur(qemu_coroutine_self(), old_mon); } else { HandleHmpCommandCo data = { - .mon = &mon->parent_obj, + .mon = &hmp->parent_obj, .cmd = cmd, .qdict = qdict, .done = false, }; Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data); - monitor_set_cur(co, &mon->parent_obj); + monitor_set_cur(co, &hmp->parent_obj); aio_co_enter(qemu_get_aio_context(), co); AIO_WAIT_WHILE_UNLOCKED(NULL, !data.done); } @@ -1308,7 +1308,8 @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) qobject_unref(qdict); } -static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) +static void cmd_completion(MonitorHMP *hmp, + const char *name, const char *list) { const char *p, *pstart; char cmd[128]; @@ -1324,7 +1325,7 @@ static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) } memcpy(cmd, pstart, len); cmd[len] = '\0'; - readline_add_completion_of(mon->rs, name, cmd); + readline_add_completion_of(hmp->rs, name, cmd); if (*p == '\0') { break; } @@ -1332,7 +1333,7 @@ static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) } } -static void file_completion(MonitorHMP *mon, const char *input) +static void file_completion(MonitorHMP *hmp, const char *input) { DIR *ffs; struct dirent *d; @@ -1384,7 +1385,7 @@ static void file_completion(MonitorHMP *mon, const char *input) if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) { pstrcat(file, sizeof(file), "/"); } - readline_add_completion(mon->rs, file); + readline_add_completion(hmp->rs, file); } } closedir(ffs); @@ -1396,7 +1397,7 @@ static const char *next_arg_type(const char *typestr) return (p != NULL ? ++p : typestr); } -static void monitor_find_completion_by_table(MonitorHMP *mon, +static void monitor_find_completion_by_table(MonitorHMP *hmp, const HMPCommand *cmd_table, char **args, int nb_args) @@ -1414,10 +1415,10 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, } else { cmdname = args[0]; } - readline_set_completion_index(mon->rs, strlen(cmdname)); + readline_set_completion_index(hmp->rs, strlen(cmdname)); for (cmd = cmd_table; cmd->name != NULL; cmd++) { if (cmd_available(cmd)) { - cmd_completion(mon, cmdname, cmd->name); + cmd_completion(hmp, cmdname, cmd->name); } } } else { @@ -1434,12 +1435,12 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, if (cmd->sub_table) { /* do the job again */ - monitor_find_completion_by_table(mon, cmd->sub_table, + monitor_find_completion_by_table(hmp, cmd->sub_table, &args[1], nb_args - 1); return; } if (cmd->command_completion) { - cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]); + cmd->command_completion(hmp->rs, nb_args, args[nb_args - 1]); return; } @@ -1461,20 +1462,20 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, switch (*ptype) { case 'F': /* file completion */ - readline_set_completion_index(mon->rs, strlen(str)); - file_completion(mon, str); + readline_set_completion_index(hmp->rs, strlen(str)); + file_completion(hmp, str); break; case 'B': /* block device name completion */ - readline_set_completion_index(mon->rs, strlen(str)); + readline_set_completion_index(hmp->rs, strlen(str)); while ((blk = blk_next(blk)) != NULL) { - readline_add_completion_of(mon->rs, str, blk_name(blk)); + readline_add_completion_of(hmp->rs, str, blk_name(blk)); } break; case 's': case 'S': if (!strcmp(cmd->name, "help|?")) { - monitor_find_completion_by_table(mon, cmd_table, + monitor_find_completion_by_table(hmp, cmd_table, &args[1], nb_args - 1); } break; @@ -1487,7 +1488,7 @@ static void monitor_find_completion_by_table(MonitorHMP *mon, static void monitor_find_completion(void *opaque, const char *cmdline) { - MonitorHMP *mon = opaque; + MonitorHMP *hmp = opaque; char *args[MAX_ARGS]; int nb_args, len; @@ -1509,7 +1510,7 @@ static void monitor_find_completion(void *opaque, } /* 2. auto complete according to args */ - monitor_find_completion_by_table(mon, hmp_cmds_for_target(false), + monitor_find_completion_by_table(hmp, hmp_cmds_for_target(false), args, nb_args); cleanup: @@ -1518,18 +1519,18 @@ cleanup: static void monitor_read(void *opaque, const uint8_t *buf, int size) { - MonitorHMP *mon = container_of(opaque, MonitorHMP, parent_obj); + MonitorHMP *hmp = container_of(opaque, MonitorHMP, parent_obj); int i; - if (mon->rs) { + if (hmp->rs) { for (i = 0; i < size; i++) { - readline_handle_byte(mon->rs, buf[i]); + readline_handle_byte(hmp->rs, buf[i]); } } else { if (size == 0 || buf[size - 1] != 0) { - monitor_printf(&mon->parent_obj, "corrupted command\n"); + monitor_printf(&hmp->parent_obj, "corrupted command\n"); } else { - handle_hmp_command(mon, (char *)buf); + handle_hmp_command(hmp, (char *)buf); } } } @@ -1598,17 +1599,17 @@ static void monitor_event(void *opaque, QEMUChrEvent event) static void G_GNUC_PRINTF(2, 3) monitor_readline_printf(void *opaque, const char *fmt, ...) { - MonitorHMP *mon = opaque; + MonitorHMP *hmp = opaque; va_list ap; va_start(ap, fmt); - monitor_vprintf(&mon->parent_obj, fmt, ap); + monitor_vprintf(&hmp->parent_obj, fmt, ap); va_end(ap); } static void monitor_readline_flush(void *opaque) { - MonitorHMP *mon = opaque; - monitor_flush(&mon->parent_obj); + MonitorHMP *hmp = opaque; + monitor_flush(&hmp->parent_obj); } void monitor_new_hmp(const char *id, const char *chardev_id, @@ -1626,11 +1627,11 @@ void monitor_new_hmp(const char *id, const char *chardev_id, static void monitor_hmp_complete(UserCreatable *uc, Error **errp) { - MonitorHMP *mon = MONITOR_HMP(uc); + MonitorHMP *hmp = MONITOR_HMP(uc); UserCreatableClass *ucc_parent = USER_CREATABLE_CLASS( object_class_get_parent( - OBJECT_CLASS(MONITOR_HMP_GET_CLASS(mon)))); + OBJECT_CLASS(MONITOR_HMP_GET_CLASS(hmp)))); ERRP_GUARD(); ucc_parent->complete(uc, errp); @@ -1638,21 +1639,21 @@ static void monitor_hmp_complete(UserCreatable *uc, Error **errp) return; } - if (mon->parent_obj.chardev_id) { - if (mon->use_readline) { - mon->rs = readline_init(monitor_readline_printf, + if (hmp->parent_obj.chardev_id) { + if (hmp->use_readline) { + hmp->rs = readline_init(monitor_readline_printf, monitor_readline_flush, - mon, + hmp, monitor_find_completion); - monitor_read_command(mon, 0); + monitor_read_command(hmp, 0); } - qemu_chr_fe_set_handlers(&mon->parent_obj.chr, + qemu_chr_fe_set_handlers(&hmp->parent_obj.chr, monitor_can_read, monitor_read, monitor_event, NULL, - &mon->parent_obj, NULL, true); - monitor_list_append(&mon->parent_obj); + &hmp->parent_obj, NULL, true); + monitor_list_append(&hmp->parent_obj); } } diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index bc0932c425..e0a124a317 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -221,7 +221,7 @@ void monitor_data_destroy_qmp(MonitorQMP *mon); void coroutine_fn monitor_qmp_dispatcher_co(void *data); void qmp_dispatcher_co_wake(void); -void handle_hmp_command(MonitorHMP *mon, const char *cmdline); +void handle_hmp_command(MonitorHMP *hmp, const char *cmdline); int hmp_compare_cmd(const char *name, const char *list); /* diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c index 06f4030ce4..24cf3a6710 100644 --- a/ui/ui-hmp-cmds.c +++ b/ui/ui-hmp-cmds.c @@ -343,8 +343,8 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target, return; } if (!arg) { - MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, parent_obj); - monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); + MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); + monitor_read_password(hmp, hmp_change_read_arg, NULL); } else { qmp_change_vnc_password(arg, errp); } From e33c5ac0d8ce64b9e08d7309ea5a3448edb3a13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 22:39:29 +0200 Subject: [PATCH 312/627] monitor: Better express monitor_read()'s opaque arg is of Monitor type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit monitor_read() is a IOReadHandler handler, called by qemu_chr_fe_set_handlers() with a Monitor* opaque argument. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-20-philmd@oss.qualcomm.com> --- monitor/hmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monitor/hmp.c b/monitor/hmp.c index cbf7a114c0..46f8d4a6ed 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1519,7 +1519,8 @@ cleanup: static void monitor_read(void *opaque, const uint8_t *buf, int size) { - MonitorHMP *hmp = container_of(opaque, MonitorHMP, parent_obj); + Monitor *mon = opaque; + MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); int i; if (hmp->rs) { From f32f9ffcfec61face1b9a684d19f64cc2cbcd6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Aug 2026 19:33:08 +0200 Subject: [PATCH 313/627] monitor: Replace container_of(MonitorHMP, parent_obj) -> MONITOR_HMP() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By replacing the container_of(MonitorHMP) use in ui/ui-hmp-cmds.c we can remove its incorrect inclusion of "monitor/monitor-internal.h" header, using the public "monitor/monitor.h" instead. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Marc-André Lureau Message-Id: <20260812211708.92824-23-philmd@oss.qualcomm.com> --- monitor/hmp-cmds.c | 2 +- monitor/hmp.c | 2 +- ui/ui-hmp-cmds.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index bcd0a1fc87..4e8d996dbb 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -290,7 +290,7 @@ void hmp_info_sync_profile(Monitor *mon, const QDict *qdict) void hmp_info_history(Monitor *mon, const QDict *qdict) { - MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); + MonitorHMP *hmp = MONITOR_HMP(mon); int i; const char *str; diff --git a/monitor/hmp.c b/monitor/hmp.c index 46f8d4a6ed..22b1972d34 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -1520,7 +1520,7 @@ cleanup: static void monitor_read(void *opaque, const uint8_t *buf, int size) { Monitor *mon = opaque; - MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); + MonitorHMP *hmp = MONITOR_HMP(mon); int i; if (hmp->rs) { diff --git a/ui/ui-hmp-cmds.c b/ui/ui-hmp-cmds.c index 24cf3a6710..806a7bece7 100644 --- a/ui/ui-hmp-cmds.c +++ b/ui/ui-hmp-cmds.c @@ -19,7 +19,7 @@ #endif #include "monitor/hmp.h" #include "monitor/hmp-completion.h" -#include "monitor/monitor-internal.h" +#include "monitor/monitor.h" #include "qapi/error.h" #include "qapi/qapi-commands-ui.h" #include "qobject/qdict.h" @@ -343,7 +343,7 @@ void hmp_change_vnc(Monitor *mon, const char *device, const char *target, return; } if (!arg) { - MonitorHMP *hmp = container_of(mon, MonitorHMP, parent_obj); + MonitorHMP *hmp = MONITOR_HMP(mon); monitor_read_password(hmp, hmp_change_read_arg, NULL); } else { qmp_change_vnc_password(arg, errp); From 260d49d8e28378b1f4f6c255c15cc20617726920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 12 Aug 2026 09:14:05 +0100 Subject: [PATCH 314/627] hw/elf_ops: defend against weird elf headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the ELF spec: PT_LOAD The array element specifies a loadable segment, described by p_filesz and p_memsz. The bytes from the file are mapped to the beginning of the memory segment. If the segment's memory size (p_memsz) is larger than the file size (p_filesz), the ``extra'' bytes are defined to hold the value 0 and to follow the segment's initialized area. The file size may not be larger than the memory size. Loadable segment entries in the program header table appear in ascending order, sorted on the p_vaddr member. which implies while both p_filesz and p_memsz can be zero we should never see a case where p_filesz is greater than the in memory size. Indeed it has been reported such a hand crafted ELF can blow up, for example during rom_reset(): address_space_set(rom->as, rom->addr + rom->datasize, 0, rom->romsize - rom->datasize, MEMTXATTRS_UNSPECIFIED); which could trigger and underflow leaving QEMU slowly filling a very large buffer. Cc: qemu-stable@nongnu.org Fixes: https://gitlab.com/qemu-project/qemu/-/work_items/4056 Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260812081405.3811787-1-alex.bennee@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/hw/elf_ops.h.inc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/hw/elf_ops.h.inc b/include/hw/elf_ops.h.inc index 9c35d1b9da..044e72de2a 100644 --- a/include/hw/elf_ops.h.inc +++ b/include/hw/elf_ops.h.inc @@ -427,6 +427,11 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd, file_size = ph->p_filesz; /* Size of the allocated data */ data_offset = ph->p_offset; /* Offset where the data is located */ + if (file_size > mem_size) { + ret = ELF_LOAD_TOO_BIG; + goto fail; + } + if (file_size > 0) { if (g_mapped_file_get_length(mapped_file) < file_size + data_offset) { From b409523587c49a08b1ddadd51212a320092347b1 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Fri, 14 Aug 2026 03:26:00 +0000 Subject: [PATCH 315/627] hw/core/machine: Move EHCI migration compat properties to 11.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The x-migrate-fetch-addr-64bit compatibility properties for sysbus-ehci-usb and pci-ehci-usb were reviewed before the QEMU 11.1 release and were therefore initially added to hw_compat_11_0. However, the EHCI migration change was merged after the QEMU 11.1 release. As a result, these compatibility properties belong in hw_compat_11_1 rather than hw_compat_11_0. Move both properties to hw_compat_11_1 so that migration compatibility is associated with the correct machine version. Fixes: 38ed803aebb2 ("usb/hcd-ehci: Change descriptor addresses to 64-bit") Signed-off-by: Jamin Lin Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260814032559.3381363-1-jamin_lin@aspeedtech.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/machine.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 4e55119446..e617f7804d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -40,7 +40,10 @@ #include "qemu/audio.h" #include "hw/arm/smmuv3.h" -GlobalProperty hw_compat_11_1[] = {}; +GlobalProperty hw_compat_11_1[] = { + { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, + { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, +}; const size_t hw_compat_11_1_len = G_N_ELEMENTS(hw_compat_11_1); GlobalProperty hw_compat_11_0[] = { @@ -54,8 +57,6 @@ GlobalProperty hw_compat_11_0[] = { { TYPE_ARM_SMMUV3, "ssidsize", "0" }, { TYPE_ARM_SMMUV3, "oas", "44" }, { "migration", "switchover-ack-legacy", "on" }, - { "sysbus-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, - { "pci-ehci-usb", "x-migrate-fetch-addr-64bit", "off" }, }; const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0); From 0924d9d3db3617f49ba9282acc6d85b349404ce6 Mon Sep 17 00:00:00 2001 From: Simon Scherer Date: Fri, 7 Aug 2026 08:28:31 +0200 Subject: [PATCH 316/627] target/i386: Clear OF, SF, and AF for fcomi/fucomi helper_fcomi_ST0_FT0() and helper_fucomi_ST0_FT0() only cleared CC_Z, CC_P, and CC_C before merging in the comparison result, leaving CC_O, CC_S, and CC_A untouched from whatever they were set to beforehand. The Intel SDM documents FCOMI/FCOMIP/FUCOMI/FUCOMIP as setting OF, SF, and AF to 0 unconditionally. The AMD manual doesn't mention them at all. However, testing on multiple real Intel and AMD systems confirms all three are unconditionally cleared regardless of the comparison result or their prior value. Since fcomi_ccval[] only ever contains CC_C, CC_Z, 0, or CC_Z|CC_P|CC_C, and CC_O|CC_S|CC_Z|CC_A|CC_P|CC_C already covers every flag bit, CC_SRC can be assigned from fcomi_ccval[ret + 1] directly instead of ORing it into a masked cpu_cc_compute_all() result. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4133 Signed-off-by: Simon Scherer Link: https://lore.kernel.org/r/20260807062831.19618-1-scherer.simon89@gmail.com Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/tcg/fpu_helper.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 978eb1411b..b812125efa 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -550,12 +550,11 @@ static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C}; void helper_fcomi_ST0_FT0(CPUX86State *env) { int old_flags = save_exception_flags(env); - int eflags; FloatRelation ret; ret = floatx80_compare(ST0, FT0, &env->fp_status); - eflags = cpu_cc_compute_all(env) & ~(CC_Z | CC_P | CC_C); - CC_SRC = eflags | fcomi_ccval[ret + 1]; + /* OF, SF, and AF are unconditionally cleared to 0 */ + CC_SRC = fcomi_ccval[ret + 1]; CC_OP = CC_OP_EFLAGS; merge_exception_flags(env, old_flags); } @@ -563,12 +562,11 @@ void helper_fcomi_ST0_FT0(CPUX86State *env) void helper_fucomi_ST0_FT0(CPUX86State *env) { int old_flags = save_exception_flags(env); - int eflags; FloatRelation ret; ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status); - eflags = cpu_cc_compute_all(env) & ~(CC_Z | CC_P | CC_C); - CC_SRC = eflags | fcomi_ccval[ret + 1]; + /* OF, SF, and AF are unconditionally cleared to 0 */ + CC_SRC = fcomi_ccval[ret + 1]; CC_OP = CC_OP_EFLAGS; merge_exception_flags(env, old_flags); } From 654d4cd059a541f56091dbfe9220806fd9b51a07 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Thu, 2 Jul 2026 14:47:46 +0200 Subject: [PATCH 317/627] target/i386: Skip supervisor in xsave decompaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supervisor state should be skipped b/c there is no slot in standard format XSAVE buffer for it. CET State is being migrated via MSRs and other supervisor state isn't currently migrated. Fixes: 8612deb3f4 Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260702124746.450228-1-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 2 ++ target/i386/xsave_helper.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e6a197602d..fff701c6c4 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -655,9 +655,11 @@ typedef enum X86Seg { #define XSTATE_DYNAMIC_MASK (XSTATE_XTILE_DATA_MASK) +#define ESA_FEATURE_XSS_BIT 0 #define ESA_FEATURE_ALIGN64_BIT 1 #define ESA_FEATURE_XFD_BIT 2 +#define ESA_FEATURE_XSS_MASK (1U << ESA_FEATURE_XSS_BIT) #define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT) #define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c index 625bae103a..1fa3133b1a 100644 --- a/target/i386/xsave_helper.c +++ b/target/i386/xsave_helper.c @@ -332,7 +332,7 @@ int decompact_xsave_area(const void *buf, size_t buflen, CPUX86State *env) size_t i; uint32_t eax, ebx, ecx, edx; uint32_t size, dst_off; - bool align64; + bool align64, supervisor; uint64_t guest_xcr0, *xstate_bv; compacted_xstate_bv = *(uint64_t *)(buf + XSAVE_XSTATE_BV_OFFSET); @@ -383,6 +383,7 @@ int decompact_xsave_area(const void *buf, size_t buflen, CPUX86State *env) size = eax; dst_off = ebx; align64 = (ecx & (1u << 1)) != 0; + supervisor = (ecx & ESA_FEATURE_XSS_MASK) != 0; /* Component is in the layout but unknown to the guest CPUID model */ if (size == 0) { @@ -433,8 +434,14 @@ int decompact_xsave_area(const void *buf, size_t buflen, CPUX86State *env) return -E2BIG; } - /* Copy components marked present in XSTATE_BV to guest model */ - if (((compacted_xstate_bv >> i) & 1) != 0) { + /* + * Copy components marked present in XSTATE_BV to guest model. + * + * NB: Supervisor state is skipped b/c there is no slot in the + * standard format XSAVE buffer (CET state is migrated via MSRs, + * others supervisor state isn't migrated). + */ + if (((compacted_xstate_bv >> i) & 1) != 0 && !supervisor) { memcpy(env->xsave_buf + dst_off, buf + xsave_offset, size); } From 5cc3e4ea53567405a30241c69da6215124279c64 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 7 Aug 2026 15:19:03 +0200 Subject: [PATCH 318/627] target/i386: use ESA_FEATURE_ALIGN64_MASK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not hardcode bit 1. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- target/i386/xsave_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c index 1fa3133b1a..666a281002 100644 --- a/target/i386/xsave_helper.c +++ b/target/i386/xsave_helper.c @@ -382,7 +382,7 @@ int decompact_xsave_area(const void *buf, size_t buflen, CPUX86State *env) size = eax; dst_off = ebx; - align64 = (ecx & (1u << 1)) != 0; + align64 = (ecx & ESA_FEATURE_ALIGN64_MASK) != 0; supervisor = (ecx & ESA_FEATURE_XSS_MASK) != 0; /* Component is in the layout but unknown to the guest CPUID model */ @@ -394,7 +394,7 @@ int decompact_xsave_area(const void *buf, size_t buflen, CPUX86State *env) */ host_cpuid(0xD, i, &eax, &ebx, &ecx, &edx); size = eax; - align64 = (ecx & (1u << 1)) != 0; + align64 = (ecx & ESA_FEATURE_ALIGN64_MASK) != 0; if (size == 0) { error_report("xsave component %zu: size unknown to both " "guest and host CPUID", i); @@ -530,7 +530,7 @@ int compact_xsave_area(CPUX86State *env, void *buf, size_t buflen) host_cpuid(0xD, i, &eax, &ebx, &ecx, &edx); size = eax; src_off = ebx; - align64 = (ecx >> 1) & 1; + align64 = (ecx & ESA_FEATURE_ALIGN64_MASK) != 0; if (size == 0) { /* Component in host xcr0 but unknown - shouldn't happen */ From ce0ee66044be066cbbf076a7530fe4e8f638f847 Mon Sep 17 00:00:00 2001 From: Simon Scherer Date: Thu, 25 Jun 2026 17:56:13 +0200 Subject: [PATCH 319/627] target/i386: fix incorrect decoding of EXTRQ_i The decoding of the extrq instruction with an immediate operand (EXTRQ_i) is incorrect. Per the AMD manual the instruction encoding looks as follows: EXTRQ xmm1, imm8, imm8 66 0F 78 /0 ib ib The /0 indicates that the "Reg" field of the ModR/M byte must be equal to 0 and the XMM register operand is specified by the "R/M" field. However, qemu incorrectly uses the "Reg" field to extract the register operand. This patch instead extracts the XMM register operand from the "R/M" field. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3611 Signed-off-by: Simon Scherer Reviewed-by: Richard Henderson Link: https://lore.kernel.org/r/20260625155613.192643-1-scherer.simon89@gmail.com [Check for the reg field to be 0. Make decoding of REPZ+66 consistent between 0F 78 and 0F 79. - Paolo] Signed-off-by: Paolo Bonzini --- target/i386/tcg/decode-new.c.inc | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index ac181308ca..ac5964b95d 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -603,23 +603,33 @@ static void decode_0F77(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui static void decode_0F78(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) { - static const X86OpEntry opcodes_0F78[4] = { - {}, - X86_OP_ENTRY3(EXTRQ_i, V,x, None,None, I,w, cpuid(SSE4A)), /* AMD extension */ - {}, - X86_OP_ENTRY3(INSERTQ_i, V,x, U,x, I,w, cpuid(SSE4A)), /* AMD extension */ - }; - *entry = *decode_by_prefix(s, opcodes_0F78); + static const X86OpEntry opcodes_0F78_f2 = + X86_OP_ENTRY3(INSERTQ_i, V,x, U,x, I,w, cpuid(SSE4A)); /* AMD extension */ + static const X86OpEntry opcodes_0F78_66 = + X86_OP_ENTRY3(EXTRQ_i, U,x, None,None, I,w, cpuid(SSE4A)); /* AMD extension */ + + entry->gen = NULL; + if (s->prefix & PREFIX_REPNZ) { + *entry = opcodes_0F78_f2; + } else if (s->prefix & PREFIX_REPZ) { + /* undefined */ + } else if (s->prefix & PREFIX_DATA) { + int op = (get_modrm(s, env) >> 3) & 7; + if (op == 0) { + *entry = opcodes_0F78_66; + } + } } static void decode_0F79(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) { + entry->gen = NULL; if (s->prefix & PREFIX_REPNZ) { entry->gen = gen_INSERTQ_r; /* AMD extension */ + } else if (s->prefix & PREFIX_REPZ) { + /* undefined */ } else if (s->prefix & PREFIX_DATA) { entry->gen = gen_EXTRQ_r; /* AMD extension */ - } else { - entry->gen = NULL; }; } From 3589cd995b4facf34071e944fd8ec2294524e25a Mon Sep 17 00:00:00 2001 From: "Craaijo, Jos" Date: Tue, 23 Jun 2026 13:21:22 +0000 Subject: [PATCH 320/627] target/i386: fix long mode segment override prefix decoding On x86, the ES/CS/SS/DS segment override prefixes are null prefixes in long mode, and should be ignored. (AMD APM Volume 3, Section 1.2.4) This patch fixes the prefix decoding to correctly ignore the prefixes in 64-bit mode. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3391 Signed-off-by: Jos Craaijo Tested-by: Yudistira Putra Link: https://lore.kernel.org/r/20260623-fix-x86-long-mode-segment-override-decoding-v1-1-26d9d4b5804e@ou.nl Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_decode.c | 6 ++++++ target/i386/tcg/decode-new.c.inc | 16 ++++++++++++---- tests/tcg/x86_64/Makefile.target | 1 + tests/tcg/x86_64/segment-prefixes.c | 25 +++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/tcg/x86_64/segment-prefixes.c diff --git a/target/i386/emulate/x86_decode.c b/target/i386/emulate/x86_decode.c index bae1dd4d6f..34dcac155a 100644 --- a/target/i386/emulate/x86_decode.c +++ b/target/i386/emulate/x86_decode.c @@ -1851,6 +1851,12 @@ static void decode_prefix(CPUX86State *env, struct x86_decode *decode) case PREFIX_SS_SEG_OVERRIDE: case PREFIX_DS_SEG_OVERRIDE: case PREFIX_ES_SEG_OVERRIDE: + if (x86_is_long_mode(env_cpu(env))) { + /* ES/CS/SS/DS segment overrides are ignored in long mode */ + decode->rex.rex = 0; + break; + } + /* fall through when not in long mode */ case PREFIX_FS_SEG_OVERRIDE: case PREFIX_GS_SEG_OVERRIDE: decode->segment_override = byte; diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index ac5964b95d..faf74b00bb 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -2816,16 +2816,24 @@ static void disas_insn(DisasContext *s, CPUState *cpu) s->prefix |= PREFIX_LOCK; goto next_byte; case 0x2e: - s->override = R_CS; + if (!CODE64(s)) { + s->override = R_CS; + } goto next_byte; case 0x36: - s->override = R_SS; + if (!CODE64(s)) { + s->override = R_SS; + } goto next_byte; case 0x3e: - s->override = R_DS; + if (!CODE64(s)) { + s->override = R_DS; + } goto next_byte; case 0x26: - s->override = R_ES; + if (!CODE64(s)) { + s->override = R_ES; + } goto next_byte; case 0x64: s->override = R_FS; diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target index be20fc64e8..c48767fef8 100644 --- a/tests/tcg/x86_64/Makefile.target +++ b/tests/tcg/x86_64/Makefile.target @@ -15,6 +15,7 @@ X86_64_TESTS += vsyscall X86_64_TESTS += noexec X86_64_TESTS += cmpxchg X86_64_TESTS += adox +X86_64_TESTS += segment-prefixes X86_64_TESTS += test-1648 X86_64_TESTS += test-2175 X86_64_TESTS += cross-modifying-code diff --git a/tests/tcg/x86_64/segment-prefixes.c b/tests/tcg/x86_64/segment-prefixes.c new file mode 100644 index 0000000000..a7e6e285b2 --- /dev/null +++ b/tests/tcg/x86_64/segment-prefixes.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* See https://gitlab.com/qemu-project/qemu/-/work_items/3391 */ + +int main() +{ + int data = 0; + + /* Ensure that ignored segment override prefixes are actually ignored */ + asm volatile ( + "wrgsbase %0\n\t" + ".byte 0x65, 0x26\n\t" /* prefixes: GS + ES */ + "movb $0, 0\n\t" + ".byte 0x65, 0x2E\n\t" /* prefixes: GS + CS */ + "movb $0, 0\n\t" + ".byte 0x65, 0x36\n\t" /* prefixes: GS + SS */ + "movb $0, 0\n\t" + ".byte 0x65, 0x3E\n\t" /* prefixes: GS + DS */ + "movb $0, 0\n\t" + : + : "r" (&data) + : "memory" + ); + + return 0; +} From 36f634fe4ab6b266031164ab8d1160e6d11addda Mon Sep 17 00:00:00 2001 From: Andrey Polivoda Date: Mon, 22 Jun 2026 18:21:19 +1000 Subject: [PATCH 321/627] target/i386: allow transition to virtual-8086 mode only if CPL == 0 and CPU is not in long mode According to the pseudocode for the IRET instruction in both the Intel 64 and IA-32 Architectures Software Developer's Manual and the AMD64 Architecture Programmer's Manual, a transition to virtual-8086 mode is allowed only if all of the following conditions are met: 1. The new EFLAGS.VM bit is set to 1. 2. The Current Privilege Level (CPL) is 0. 3. The CPU is in protected mode (and not in long mode). Currently, QEMU performs only the first check. This omission allows a transition to virtual-8086 mode from long mode, and also enables the guest's userspace to trigger this switch. During a legitimate transition, the EFLAGS register is updated in a way that allows modification of sensitive fields, such as IOPL and IF (which is expected, as only privileged code should be able to initiate this transition). However, due to the lack of appropriate checks, an unprivileged guest userspace process can now force this transition and freely modify these fields. This allows the userspace to: 1. Disable interrupts, preventing other processes from running on the CPU. 2. Gain direct hardware I/O access by elevating EFLAGS.IOPL to 3. 3. Crash the guest kernel by setting CS and SS to resemble segments with RPL = 0 and triggering an exception. Since the kernel is unaware that the process entered virtual-8086 mode, it will misinterpret the exception as originating from kernel space. This patch fixes this bug by adding the missing CPL and long mode checks before jumping to the `return_to_vm86` label. Fixes: 90a9fdae1f1a ("more ring 0 operations") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3583 Signed-off-by: Andrey Polivoda Cc: qemu-devel@nongnu.org Cc: Paolo Bonzini Cc: Richard Henderson Link: https://lore.kernel.org/r/20260622082119.11903-1-apolivodaa433@gmail.com Signed-off-by: Paolo Bonzini --- target/i386/tcg/seg_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index d5c174b7fd..6d424349a5 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -2077,7 +2077,8 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, new_cs = popl(&sa) & 0xffff; if (is_iret) { new_eflags = popl(&sa); - if (new_eflags & VM_MASK) { + bool allow_vm86 = (cpl == 0) && !(env->hflags & HF_LMA_MASK); + if ((new_eflags & VM_MASK) && allow_vm86) { goto return_to_vm86; } } From 380b9596181760f371713604ea3472c56c19deb9 Mon Sep 17 00:00:00 2001 From: Andrey Polivoda Date: Sun, 21 Jun 2026 13:25:23 +1000 Subject: [PATCH 322/627] target/i386: decode opcode extensions group 3 /1 as TEST According to Table A-6 in Volume 3 of AMD64 Architecture Programmer's Manual, opcodes F6 and F7 (opcode extensions group 3) with ModRM's reg field values of 0 and 1 can be used to encode a TEST instruction. Although Intel 64 and IA-32 Architectures Software Developer's Manual leaves the cell 1 of opcode extensions group 3 blank in the opcode table (Table A-6, Volume 2D), the instruction in a group 3 with reg field of ModRM byte set to 1 actually behaves like TEST instruction on Intel CPUs. Currently, QEMU decodes group 3 instruction as TEST only if reg field of ModRM byte is 0. When the reg field is 1, QEMU raises a #UD exception. This behavior does not match real Intel and AMD hardware. This patch fixes this issue by duplicating the existing [0x00] and [0x08] X86_OP_ENTRYrr(AND, ...) entries into slots [0x01] and [0x09] in the opcodes_grp3 table. Fixes: d7c41a60d0c5 ("target/i386: move C0-FF opcodes to new decoder (except for x87)") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3580 Signed-off-by: Andrey Polivoda Cc: qemu-devel@nongnu.org Cc: Paolo Bonzini Cc: Richard Henderson Reviewed-by: Richard Henderson Link: https://lore.kernel.org/r/20260621032524.1138213-1-apolivodaa433@gmail.com Signed-off-by: Paolo Bonzini --- target/i386/tcg/decode-new.c.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index faf74b00bb..9c429e113d 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -1624,6 +1624,7 @@ static void decode_group3(DisasContext *s, CPUX86State *env, X86OpEntry *entry, static const X86OpEntry opcodes_grp3[16] = { /* 0xf6 */ [0x00] = X86_OP_ENTRYrr(AND, E,b, I,b), + [0x01] = X86_OP_ENTRYrr(AND, E,b, I,b), [0x02] = X86_OP_ENTRY1(NOT, E,b, lock), [0x03] = X86_OP_ENTRY1(NEG, E,b, lock), [0x04] = X86_OP_ENTRYrr(MUL, E,b, 0,b, zextT0), @@ -1633,6 +1634,7 @@ static void decode_group3(DisasContext *s, CPUX86State *env, X86OpEntry *entry, /* 0xf7 */ [0x08] = X86_OP_ENTRYrr(AND, E,v, I,z), + [0x09] = X86_OP_ENTRYrr(AND, E,v, I,z), [0x0a] = X86_OP_ENTRY1(NOT, E,v, lock), [0x0b] = X86_OP_ENTRY1(NEG, E,v, lock), [0x0c] = X86_OP_ENTRYrr(MUL, E,v, 0,v, zextT0), From f3a89cded28054161d72feeb85a6fe082b4d1b70 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:23 +0200 Subject: [PATCH 323/627] target/i386/mshv: disable AMX TILE features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the time being we disable AMX TILE in partition processor features and CPUID b/c AMX TILE XSAVE state (XTILE_DATA) is 8KB, which exceeds the current fixed 4KB XSAVE buffer size. For now we filter it until buffer sizing is computed dynamically from CPUID. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-2-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 8 ++++++++ target/i386/mshv/mshv-cpu.c | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 72721d0f0d..5e8756ede2 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -203,6 +203,14 @@ static int create_partition(int mshv_fd, int *vm_fd) /* enable all */ disabled_xsave_features.as_uint64 = 0; + /* + * AMX TILE XSAVE state (XTILE_DATA) is 8KB, which exceeds the + * current fixed 4KB XSAVE buffer size. + */ + disabled_xsave_features.amx_tile_support = 1; + disabled_xsave_features.amx_bf16_support = 1; + disabled_xsave_features.amx_int8_support = 1; + disabled_xsave_features.amx_fp16_support = 1; /* * query host for supported processor features and disable unsupported diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 1c433c408c..8eca01a8fa 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -2156,6 +2156,22 @@ uint32_t mshv_get_supported_cpuid(uint32_t func, uint32_t idx, int reg) */ ret &= ~CPUID_7_0_ECX_LA57; } + if (func == 0x07 && idx == 0 && reg == R_EDX) { + /* + * AMX TILE XSAVE state (XTILE_DATA) is 8KB, which exceeds the + * current fixed 4KB XSAVE buffer size. Filter until buffer + * sizing is computed dynamically from CPUID. + */ + ret &= ~CPUID_7_0_EDX_AMX_TILE; + ret &= ~CPUID_7_0_EDX_AMX_BF16; + ret &= ~CPUID_7_0_EDX_AMX_INT8; + } + if (func == 0x07 && idx == 1 && reg == R_EAX) { + ret &= ~CPUID_7_1_EAX_AMX_FP16; + } + if (func == 0x07 && idx == 1 && reg == R_EDX) { + ret &= ~CPUID_7_1_EDX_AMX_COMPLEX; + } return ret; } From 3b599ae592db07e666cc2a7f1f449b4d792fbc95 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:33 +0200 Subject: [PATCH 324/627] target/i386/mshv: toggle fpu/xsave migration MSHV exposes overlapping legacy FP/SSE state through two paths: explicit Hyper-V FPU/XMM + registers and VP XSAVE state. There can be subtle inconsistencies across migrations when XSAVE is written after FPU state. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20260710101534.664604-12-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/mshv/mshv-cpu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 8eca01a8fa..fa15e399cb 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -950,7 +950,7 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } - ret = get_fpu(cpu); + ret = get_xsave_state(cpu); if (ret < 0) { return ret; } @@ -960,7 +960,7 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } - ret = get_xsave_state(cpu); + ret = get_fpu(cpu); if (ret < 0) { return ret; } @@ -1506,7 +1506,7 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return ret; } - ret = set_fpu(cpu); + ret = set_xsave_state(cpu); if (ret < 0) { return ret; } @@ -1516,7 +1516,8 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return ret; } - ret = set_xsave_state(cpu); + /* INVARIANT: legacy FPU state must be restored after XSAVE */ + ret = set_fpu(cpu); if (ret < 0) { return ret; } From f27b4fcfd8f584e4509a18d2ea4019257e19d5b9 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:24 +0200 Subject: [PATCH 325/627] accel/mshv: introduce SaveVMHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This mechanism is used to handle more imperative partition-wide steps that have to be taken as part of a migration routine. Currently it's just a skeleton. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-3-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 5e8756ede2..b34fb34d05 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -39,6 +39,8 @@ #include "system/mshv.h" #include "system/mshv_int.h" #include "system/reset.h" +#include "migration/qemu-file-types.h" +#include "migration/register.h" #include "trace.h" #include #include @@ -544,6 +546,9 @@ static int mshv_init_vcpu(CPUState *cpu) return 0; } +static SaveVMHandlers savevm_mshv = { +}; + static int mshv_init(AccelState *as, MachineState *ms) { MshvState *s; @@ -599,6 +604,8 @@ static int mshv_init(AccelState *as, MachineState *ms) 0, "mshv-memory"); memory_listener_register(&mshv_io_listener, &address_space_io); + register_savevm_live("mshv", 0, 1, &savevm_mshv, s); + return 0; } From 922c1a4aac5a02f2782153ff5702652c4b332ca6 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:25 +0200 Subject: [PATCH 326/627] hw/i386/mshv: migrate REFERENCE_TIME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a partition-wide state for which we use a dedicated hw clock facility, similar to KVM. We have to freeze the time for a partition before we are allowed to set it. We register a state change handler for the clock device and a post-load handler for migration state. In the post-load handler we toggle a flag that will set the reference time state on next state to "running" on the partition. We can move the time freeze and reference-time ioctls/hvcalls to the clock module. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-4-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- MAINTAINERS | 1 + accel/mshv/mshv-all.c | 67 ++------------ accel/mshv/trace-events | 1 + hw/i386/meson.build | 1 + hw/i386/mshv/clock.c | 189 +++++++++++++++++++++++++++++++++++++++ hw/i386/mshv/meson.build | 4 + include/system/mshv.h | 3 + 7 files changed, 208 insertions(+), 58 deletions(-) create mode 100644 hw/i386/mshv/clock.c create mode 100644 hw/i386/mshv/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index f249be744e..937c47f491 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -620,6 +620,7 @@ R: Wei Liu R: Doru Blânzeanu S: Supported F: target/i386/mshv/ +F: hw/i386/mshv/ X86 Instruction Emulator M: Roman Bolshakov diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index b34fb34d05..7b3c13cf1e 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -60,54 +60,6 @@ static int init_mshv(int *mshv_fd) return 0; } -/* freeze 1 to pause, 0 to resume */ -static int set_time_freeze(int vm_fd, int freeze) -{ - int ret; - struct hv_input_set_partition_property in = {0}; - in.property_code = HV_PARTITION_PROPERTY_TIME_FREEZE; - in.property_value = freeze; - - struct mshv_root_hvcall args = {0}; - args.code = HVCALL_SET_PARTITION_PROPERTY; - args.in_sz = sizeof(in); - args.in_ptr = (uint64_t)∈ - - ret = mshv_hvcall(vm_fd, &args); - if (ret < 0) { - error_report("Failed to set time freeze"); - return -1; - } - - return 0; -} - -static int pause_vm(int vm_fd) -{ - int ret; - - ret = set_time_freeze(vm_fd, 1); - if (ret < 0) { - error_report("Failed to pause partition: %s", strerror(errno)); - return -1; - } - - return 0; -} - -static int resume_vm(int vm_fd) -{ - int ret; - - ret = set_time_freeze(vm_fd, 0); - if (ret < 0) { - error_report("Failed to resume partition: %s", strerror(errno)); - return -1; - } - - return 0; -} - static int get_host_partition_property(int mshv_fd, uint32_t property_code, uint64_t *value) { @@ -330,9 +282,6 @@ static int create_vm(int mshv_fd, int *vm_fd) return -1; } - /* Always create a frozen partition */ - pause_vm(*vm_fd); - return 0; } @@ -578,13 +527,6 @@ static int mshv_init(AccelState *as, MachineState *ms) return -1; } - ret = resume_vm(vm_fd); - if (ret < 0) { - close(mshv_fd); - close(vm_fd); - return -1; - } - s->vm = vm_fd; s->fd = mshv_fd; @@ -606,6 +548,8 @@ static int mshv_init(AccelState *as, MachineState *ms) register_savevm_live("mshv", 0, 1, &savevm_mshv, s); + mshv_clock_init(); + return 0; } @@ -643,6 +587,13 @@ static int mshv_cpu_exec(CPUState *cpu) cpu->vcpu_dirty = false; } + /* Corresponding store-release is in cpu_exit. */ + if (qatomic_load_acquire(&cpu->exit_request)) { + trace_mshv_interrupt_exit_request(cpu->cpu_index); + ret = EXCP_INTERRUPT; + break; + } + ret = mshv_run_vcpu(mshv_state->vm, cpu, &mshv_msg, &exit_reason); if (ret < 0) { error_report("Failed to run on vcpu %d", cpu->cpu_index); diff --git a/accel/mshv/trace-events b/accel/mshv/trace-events index a4dffeb24a..859e8bfb0f 100644 --- a/accel/mshv/trace-events +++ b/accel/mshv/trace-events @@ -4,6 +4,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later mshv_start_vcpu_thread(const char* thread, uint32_t cpu) "thread=%s cpu_index=%d" +mshv_interrupt_exit_request(uint32_t cpu) "cpu_index=%d" mshv_set_memory(bool add, uint64_t gpa, uint64_t size, uint64_t user_addr, bool readonly, int ret) "add=%d gpa=0x%" PRIx64 " size=0x%" PRIx64 " user=0x%" PRIx64 " readonly=%d result=%d" mshv_mem_ioeventfd_add(uint64_t addr, uint32_t size, uint32_t data) "addr=0x%" PRIx64 " size=%d data=0x%x" diff --git a/hw/i386/meson.build b/hw/i386/meson.build index b611fbb5a7..f4d3122863 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -39,6 +39,7 @@ i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c')) subdir('kvm') subdir('xen') +subdir('mshv') i386_ss.add_all(xenpv_ss) diff --git a/hw/i386/mshv/clock.c b/hw/i386/mshv/clock.c new file mode 100644 index 0000000000..02c586503a --- /dev/null +++ b/hw/i386/mshv/clock.c @@ -0,0 +1,189 @@ +/* + * MSHV partition reference clock + * + * Copyright Microsoft, Corp. 2026 + * + * Authors: Magnus Kulke + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "migration/vmstate.h" +#include "system/runstate.h" +#include "hw/hyperv/hvhdk.h" +#include "hw/hyperv/hvhdk_mini.h" +#include "hw/hyperv/hvgdk.h" +#include "hw/hyperv/hvgdk_mini.h" +#include "linux/mshv.h" +#include "system/mshv.h" +#include "system/mshv_int.h" + +/* + * Partition reference clock (HV_PARTITION_PROPERTY_REFERENCE_TIME), captured + * when the VM is stopped and re-applied when it resumes. + * + * Mirrors hw/i386/kvm/clock.c. + */ +typedef struct MshvClockState { + uint64_t ref_time; + bool ref_time_pending; +} MshvClockState; + +static MshvClockState mshv_clock; + +static int mshv_get_reference_time(int vm_fd, uint64_t *ref_time) +{ + struct hv_input_get_partition_property in = { 0 }; + struct hv_output_get_partition_property out = { 0 }; + struct mshv_root_hvcall args = { 0 }; + int ret; + + in.property_code = HV_PARTITION_PROPERTY_REFERENCE_TIME; + + args.code = HVCALL_GET_PARTITION_PROPERTY; + args.in_sz = sizeof(in); + args.in_ptr = (uint64_t)∈ + args.out_sz = sizeof(out); + args.out_ptr = (uint64_t)&out; + + ret = mshv_hvcall(vm_fd, &args); + if (ret < 0) { + error_report("Failed to get reference time"); + return -1; + } + + *ref_time = out.property_value; + return 0; +} + +static int mshv_set_reference_time(int vm_fd, uint64_t ref_time) +{ + struct hv_input_set_partition_property in = { 0 }; + struct mshv_root_hvcall args = { 0 }; + int ret; + + in.property_code = HV_PARTITION_PROPERTY_REFERENCE_TIME; + in.property_value = ref_time; + + args.code = HVCALL_SET_PARTITION_PROPERTY; + args.in_sz = sizeof(in); + args.in_ptr = (uint64_t)∈ + + ret = mshv_hvcall(vm_fd, &args); + if (ret < 0) { + error_report("Failed to set reference time"); + return -1; + } + + return 0; +} + +/* + * Freeze (freeze=1) or unfreeze (freeze=0) time for a partition. This will not + * pause/eject vCPU execution. It is assumed that the caller already has stopped + * the partition's vCPUs. + * + * NB: a partition's reference clock can only be written while the time is + * frozen. + */ +static int mshv_set_time_freeze(int vm_fd, int freeze) +{ + struct hv_input_set_partition_property in = { 0 }; + struct mshv_root_hvcall args = { 0 }; + int ret; + + in.property_code = HV_PARTITION_PROPERTY_TIME_FREEZE; + in.property_value = freeze; + + args.code = HVCALL_SET_PARTITION_PROPERTY; + args.in_sz = sizeof(in); + args.in_ptr = (uint64_t)∈ + + ret = mshv_hvcall(vm_fd, &args); + if (ret < 0) { + error_report("Failed to set time freeze"); + return -1; + } + + return 0; +} + +static void mshv_clock_vm_state_change(void *opaque, bool running, + RunState state) +{ + MshvClockState *s = opaque; + int vm_fd = mshv_state->vm; + int ret; + + if (running) { + /* Skip if we have nothing to restore, e.g. on initial boot. */ + if (!s->ref_time_pending) { + return; + } + + ret = mshv_set_time_freeze(vm_fd, 1); + if (ret < 0) { + error_report("Failed to freeze partition time on resume"); + abort(); + } + + /* INVARIANT: reference time can only be written if time is frozen. */ + ret = mshv_set_reference_time(vm_fd, s->ref_time); + if (ret < 0) { + error_report("Failed to restore reference time on resume"); + abort(); + } + + if (mshv_set_time_freeze(vm_fd, 0) < 0) { + error_report("Failed to unfreeze partition time on resume"); + abort(); + } + + s->ref_time_pending = false; + } else { + /* Skip if we already have a to-be-set ref time */ + if (s->ref_time_pending) { + return; + } + + ret = mshv_get_reference_time(vm_fd, &s->ref_time); + if (ret < 0) { + error_report("Failed to capture reference time on stop"); + abort(); + } + + s->ref_time_pending = true; + } +} + +/* + * The incoming reference time should be applied on the next resume before + * vCPUs start executing. + */ +static int mshv_clock_post_load(void *opaque, int version_id) +{ + MshvClockState *s = opaque; + + s->ref_time_pending = true; + + return 0; +} + +static const VMStateDescription vmstate_mshv_clock = { + .name = "mshv-clock", + .version_id = 1, + .minimum_version_id = 1, + .post_load = mshv_clock_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT64(ref_time, MshvClockState), + VMSTATE_END_OF_LIST() + }, +}; + +void mshv_clock_init(void) +{ + vmstate_register(NULL, 0, &vmstate_mshv_clock, &mshv_clock); + qemu_add_vm_change_state_handler(mshv_clock_vm_state_change, &mshv_clock); +} diff --git a/hw/i386/mshv/meson.build b/hw/i386/mshv/meson.build new file mode 100644 index 0000000000..0e556851b6 --- /dev/null +++ b/hw/i386/mshv/meson.build @@ -0,0 +1,4 @@ +i386_mshv_ss = ss.source_set() +i386_mshv_ss.add(files('clock.c')) + +i386_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss) diff --git a/include/system/mshv.h b/include/system/mshv.h index 46fe3fcebc..a6f815b822 100644 --- a/include/system/mshv.h +++ b/include/system/mshv.h @@ -55,6 +55,9 @@ DECLARE_INSTANCE_CHECKER(MshvState, MSHV_STATE, extern MshvState *mshv_state; +/* clock (partition reference time) */ +void mshv_clock_init(void); + /* interrupt */ int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector, uint32_t vp_index, bool logical_destination_mode, From 2f6c2ede4688f90a3583cfb2050de66a100fc5cb Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:26 +0200 Subject: [PATCH 327/627] accel/mshv: install dummy handler for SIG_IPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is similar to HVF's implementation. We want to interrupt the blocking vcpu run. The self-kick was effectively a no-op for mshv. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-5-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 7b3c13cf1e..f9511ca050 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -621,17 +621,13 @@ static int mshv_cpu_exec(CPUState *cpu) } /* - * The signal handler is triggered when QEMU's main thread receives a SIG_IPI - * (SIGUSR1). This signal causes the current CPU thread to be kicked, forcing a - * VM exit on the CPU. The VM exit generates an exit reason that breaks the loop - * (see mshv_cpu_exec). If the exit is due to a Ctrl+A+x command, the system - * will shut down. For other cases, the system will continue running. + * We need a dummy handler to make SIG_IPI a deliverable signal. The kernel + * handler will be woken up by the caught signal and instruct the hypervisor + * to suspend execution (the concrete mechanism differs between schedulers) + * and return to userspace. */ -static void sa_ipi_handler(int sig) +static void dummy_handler(int sig) { - /* TODO: call IOCTL to set_immediate_exit, once implemented. */ - - qemu_cpu_kick_self(); } static void init_signal(CPUState *cpu) @@ -641,7 +637,7 @@ static void init_signal(CPUState *cpu) sigset_t set; memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = sa_ipi_handler; + sigact.sa_handler = dummy_handler; sigaction(SIG_IPI, &sigact, NULL); pthread_sigmask(SIG_BLOCK, NULL, &set); From 662b6c053ec24517b4cbfdf1911e2e78cf73aee4 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:27 +0200 Subject: [PATCH 328/627] target/i386/mshv: migrate LAPIC state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change implements loading and storing the hyperv lapic state as part of the load/store routines for a vcpu. The HyperV LAPIC is similar to the the split-irqchip in KVM. MSHV currently keeps PIC/IOAPIC emulation in userspace, while LAPIC interrupt injection is handled through hypercalls. We introduced dedicated apic infra in hw/i386/mshv to handle the migration and move lapic related functions from target/i386/mshv there. References have been the WHPX's whpx-apic implemenation and the mshv-ioctls crate's get_/set_lapic() impl for the mapping between MSHV/QEMU lapic state. We are mapping the lapic state that we receive from the hypervisor to fields in APICCommonState. Common fields are used where feasible, with an mshv-specific MshvAPICState object that carries mshv-specific fields. We have introduced a guard in pic_irq_request() that will early exit for the mshv accelerator, because mshv cannot take part in the userland path for legacy PIC interrupt injection. The TSC_DEADLINE MSR is also migrated as part of LAPIC migration. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-6-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 1 + hw/i386/meson.build | 2 +- hw/i386/mshv/apic.c | 395 +++++++++++++++++++++++++++++++++ hw/i386/mshv/meson.build | 1 + hw/i386/x86-cpu.c | 6 + include/hw/hyperv/hvgdk_mini.h | 2 + include/hw/i386/apic-msidef.h | 1 + include/system/mshv.h | 2 + include/system/mshv_int.h | 8 +- target/i386/cpu-apic.c | 3 + target/i386/mshv/mshv-cpu.c | 151 ++++--------- target/i386/mshv/msr.c | 2 + 12 files changed, 460 insertions(+), 114 deletions(-) create mode 100644 hw/i386/mshv/apic.c diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index f9511ca050..1516475f34 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -813,6 +813,7 @@ static void mshv_accel_ops_class_init(ObjectClass *oc, const void *data) ops->synchronize_state = mshv_cpu_synchronize; ops->synchronize_pre_loadvm = mshv_cpu_synchronize_pre_loadvm; ops->cpus_are_resettable = mshv_cpus_are_resettable; + ops->cpu_thread_is_idle = mshv_vcpu_thread_is_idle; ops->handle_interrupt = generic_handle_interrupt; } diff --git a/hw/i386/meson.build b/hw/i386/meson.build index f4d3122863..39ac8c9edc 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -38,8 +38,8 @@ i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'), i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c')) subdir('kvm') -subdir('xen') subdir('mshv') +subdir('xen') i386_ss.add_all(xenpv_ss) diff --git a/hw/i386/mshv/apic.c b/hw/i386/mshv/apic.c new file mode 100644 index 0000000000..9188a93b2f --- /dev/null +++ b/hw/i386/mshv/apic.c @@ -0,0 +1,395 @@ +/* + * MSHV in-kernel APIC support + * + * Copyright Microsoft, Corp. 2026 + * + * Authors: Magnus Kulke + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/memalign.h" +#include "qemu/error-report.h" +#include "hw/i386/apic_internal.h" +#include "hw/i386/apic-msidef.h" +#include "hw/pci/msi.h" +#include "migration/vmstate.h" +#include "qemu/typedefs.h" +#include "system/hw_accel.h" +#include "system/mshv.h" +#include "system/mshv_int.h" + +typedef struct hv_local_interrupt_controller_state + hv_local_interrupt_controller_state; + +#define TYPE_MSHV_APIC "mshv-apic" +OBJECT_DECLARE_SIMPLE_TYPE(MshvAPICState, MSHV_APIC) + +struct MshvAPICState { + APICCommonState parent_obj; + + uint32_t apic_version; + uint32_t apic_lvt_cmci; + uint32_t apic_error_status; + uint32_t apic_counter_value; + uint32_t apic_remote_read; +}; + +static int get_lapic(int cpu_fd, + struct hv_local_interrupt_controller_state *state) +{ + int ret; + size_t size = 4096; + /* buffer aligned to 4k, as *state requires that */ + void *buffer = qemu_memalign(size, size); + struct mshv_get_set_vp_state mshv_state = { 0 }; + + mshv_state.buf_ptr = (uint64_t) buffer; + mshv_state.buf_sz = size; + mshv_state.type = MSHV_VP_STATE_LAPIC; + + ret = mshv_get_vp_state(cpu_fd, &mshv_state); + if (ret == 0) { + memcpy(state, buffer, sizeof(*state)); + } + qemu_vfree(buffer); + if (ret < 0) { + error_report("failed to get lapic"); + return -1; + } + + return 0; +} + +static int set_lapic(int cpu_fd, + const struct hv_local_interrupt_controller_state *state) +{ + int ret; + size_t size = 4096; + /* buffer aligned to 4k, as *state requires that */ + void *buffer = qemu_memalign(size, size); + struct mshv_get_set_vp_state mshv_state = { 0 }; + + if (!state) { + error_report("lapic state is NULL"); + return -1; + } + memcpy(buffer, state, sizeof(*state)); + + mshv_state.buf_ptr = (uint64_t) buffer; + mshv_state.buf_sz = size; + mshv_state.type = MSHV_VP_STATE_LAPIC; + + ret = mshv_set_vp_state(cpu_fd, &mshv_state); + qemu_vfree(buffer); + if (ret < 0) { + error_report("failed to set lapic: %s", strerror(errno)); + return -1; + } + + return 0; +} + +static void populate_apic_state(CPUState *cpu, + const hv_local_interrupt_controller_state *hv) +{ + X86CPU *x86cpu = X86_CPU(cpu); + MshvAPICState *ms = MSHV_APIC(x86cpu->apic_state); + APICCommonState *s = &ms->parent_obj; + size_t i; + + /* + * x2APIC: + * - APIC ID is the full 32-bit initial_apic_id + * - LDR is read-only, architecturally derived from the ID + * - DFR does not exist in x2APIC mode + */ + if (is_x2apic_mode(s)) { + s->initial_apic_id = hv->apic_id; + } else { + s->id = hv->apic_id >> 24; + s->log_dest = hv->apic_ldr >> 24; + s->dest_mode = hv->apic_dfr >> 28; + } + ms->apic_version = hv->apic_version; + s->spurious_vec = hv->apic_spurious; + for (i = 0; i < 8; i++) { + s->isr[i] = hv->apic_isr[i]; + s->tmr[i] = hv->apic_tmr[i]; + s->irr[i] = hv->apic_irr[i]; + } + s->esr = hv->apic_esr; + s->icr[1] = hv->apic_icr_high; + s->icr[0] = hv->apic_icr_low; + + s->lvt[APIC_LVT_TIMER] = hv->apic_lvt_timer; + s->lvt[APIC_LVT_THERMAL] = hv->apic_lvt_thermal; + s->lvt[APIC_LVT_PERFORM] = hv->apic_lvt_perfmon; + s->lvt[APIC_LVT_LINT0] = hv->apic_lvt_lint0; + s->lvt[APIC_LVT_LINT1] = hv->apic_lvt_lint1; + s->lvt[APIC_LVT_ERROR] = hv->apic_lvt_error; + ms->apic_lvt_cmci = hv->apic_lvt_cmci; + + ms->apic_error_status = hv->apic_error_status; + s->initial_count = hv->apic_initial_count; + ms->apic_counter_value = hv->apic_counter_value; + s->divide_conf = hv->apic_divide_configuration; + ms->apic_remote_read = hv->apic_remote_read; +} + +static uint32_t set_apic_delivery_mode(uint32_t reg, uint32_t mode) +{ + return ((reg) & ~0x700) | ((mode) << 8); +} + +int mshv_init_lint(CPUState *cpu) +{ + uint32_t *lvt_lint0, *lvt_lint1; + int cpu_fd = mshv_vcpufd(cpu); + int ret; + struct hv_local_interrupt_controller_state lapic_state = { 0 }; + + ret = get_lapic(cpu_fd, &lapic_state); + if (ret < 0) { + return ret; + } + + lvt_lint0 = &lapic_state.apic_lvt_lint0; + *lvt_lint0 = set_apic_delivery_mode(*lvt_lint0, APIC_DM_EXTINT); + + lvt_lint1 = &lapic_state.apic_lvt_lint1; + *lvt_lint1 = set_apic_delivery_mode(*lvt_lint1, APIC_DM_NMI); + + /* TODO: should we skip setting lapic if the values are the same? */ + + ret = set_lapic(cpu_fd, &lapic_state); + if (ret < 0) { + return -1; + } + + populate_apic_state(cpu, &lapic_state); + + return 0; +} + +static void populate_hv_lapic_state(hv_local_interrupt_controller_state *hv, + const CPUState *cpu) +{ + uint32_t x2apic_id; + X86CPU *x86cpu = X86_CPU(cpu); + MshvAPICState *ms = MSHV_APIC(x86cpu->apic_state); + APICCommonState *s = &ms->parent_obj; + size_t i; + + /* + * x2APIC: + * - APIC ID is the full 32-bit initial_apic_id + * - LDR is read-only, architecturally derived from the ID + * - DFR does not exist in x2APIC mode + */ + if (is_x2apic_mode(s)) { + x2apic_id = s->initial_apic_id; + + hv->apic_id = x2apic_id; + hv->apic_ldr = ((x2apic_id >> 4) << 16) | (1 << (x2apic_id & 0xf)); + hv->apic_dfr = 0; + } else { + hv->apic_id = s->id << 24; + hv->apic_ldr = s->log_dest << 24; + hv->apic_dfr = s->dest_mode << 28 | 0x0fffffff; + } + hv->apic_version = ms->apic_version; + hv->apic_spurious = s->spurious_vec; + for (i = 0; i < 8; i++) { + hv->apic_isr[i] = s->isr[i]; + hv->apic_tmr[i] = s->tmr[i]; + hv->apic_irr[i] = s->irr[i]; + } + hv->apic_esr = s->esr; + hv->apic_icr_high = s->icr[1]; + hv->apic_icr_low = s->icr[0]; + + hv->apic_lvt_timer = s->lvt[APIC_LVT_TIMER]; + hv->apic_lvt_thermal = s->lvt[APIC_LVT_THERMAL]; + hv->apic_lvt_perfmon = s->lvt[APIC_LVT_PERFORM]; + hv->apic_lvt_lint0 = s->lvt[APIC_LVT_LINT0]; + hv->apic_lvt_lint1 = s->lvt[APIC_LVT_LINT1]; + hv->apic_lvt_error = s->lvt[APIC_LVT_ERROR]; + hv->apic_lvt_cmci = ms->apic_lvt_cmci; + + hv->apic_error_status = ms->apic_error_status; + hv->apic_initial_count = s->initial_count; + hv->apic_counter_value = ms->apic_counter_value; + hv->apic_divide_configuration = s->divide_conf; + hv->apic_remote_read = ms->apic_remote_read; +} + +int mshv_set_lapic(const CPUState *cpu) +{ + int cpu_fd = mshv_vcpufd(cpu); + struct hv_local_interrupt_controller_state lapic_state = { 0 }; + + populate_hv_lapic_state(&lapic_state, cpu); + + return set_lapic(cpu_fd, &lapic_state); +} + +int mshv_get_lapic(CPUState *cpu) +{ + int cpu_fd = mshv_vcpufd(cpu); + int ret; + struct hv_local_interrupt_controller_state lapic_state = { 0 }; + + ret = get_lapic(cpu_fd, &lapic_state); + if (ret < 0) { + return -1; + } + + populate_apic_state(cpu, &lapic_state); + + return 0; +} + +static int mshv_apic_set_base(APICCommonState *s, uint64_t val) +{ + s->apicbase = val; + + return 0; +} + +static void mshv_apic_set_tpr(APICCommonState *s, uint8_t val) +{ + s->tpr = (val & APIC_PR_SUB_CLASS) << APIC_PR_CLASS_SHIFT; +} + +static uint8_t mshv_apic_get_tpr(APICCommonState *s) +{ + return s->tpr >> APIC_PR_CLASS_SHIFT; +} + +static void mshv_apic_external_nmi(APICCommonState *s) +{ +} + +static void mshv_apic_vapic_base_update(APICCommonState *s) +{ +} + +static void mshv_send_msi(MSIMessage *msi) +{ + uint64_t addr; + uint32_t data, dest; + uint8_t vector, dest_mode, trigger_mode, delivery; + + addr = msi->address; + data = msi->data; + dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT | + (addr >> 32); + vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; + dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; + trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; + delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & + MSI_DATA_DELIVERY_MODE_MASK; + + mshv_request_interrupt(mshv_state, delivery, vector, dest, dest_mode, + trigger_mode); +} + +static uint64_t mshv_apic_mem_read(void *opaque, hwaddr addr, + unsigned size) +{ + return UINT64_MAX; +} + +static void mshv_apic_mem_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + MSIMessage msg = { .address = addr, .data = data }; + + mshv_send_msi(&msg); +} + +static const MemoryRegionOps mshv_apic_io_ops = { + .read = mshv_apic_mem_read, + .write = mshv_apic_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void mshv_apic_reset(APICCommonState *s) +{ + s->wait_for_sipi = 0; +} + +static const VMStateDescription vmstate_mshv_apic = { + .name = "mshv-apic", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(apic_version, MshvAPICState), + VMSTATE_UINT32(apic_lvt_cmci, MshvAPICState), + VMSTATE_UINT32(apic_error_status, MshvAPICState), + VMSTATE_UINT32(apic_counter_value, MshvAPICState), + VMSTATE_UINT32(apic_remote_read, MshvAPICState), + VMSTATE_END_OF_LIST() + } +}; + +static void mshv_apic_realize(DeviceState *dev, Error **errp) +{ + APICCommonState *s = APIC_COMMON(dev); + MshvAPICState *ms = MSHV_APIC(dev); + + memory_region_init_io(&s->io_memory, OBJECT(s), &mshv_apic_io_ops, s, + "mshv-apic-msi", APIC_SPACE_SIZE); + + msi_nonbroken = true; + + /* + * We register this state explicity, rather than going via dc->vmsd. + * The auto-wiring would register the state with + * instance_id == VMSTATE_INSTANCE_ID_ANY, which for the APIC doesn't + * work, b/c the ID carries semantic meaning for restoring the state + * on the destination (which vcpu it belongs to). + */ + vmstate_register_with_alias_id(NULL, + s->initial_apic_id, &vmstate_mshv_apic, ms, + -1, 0, NULL); +} + +static void mshv_apic_unrealize(DeviceState *dev) +{ + MshvAPICState *ms = MSHV_APIC(dev); + + vmstate_unregister(NULL, &vmstate_mshv_apic, ms); +} + +static void mshv_apic_class_init(ObjectClass *klass, const void *data) +{ + APICCommonClass *k = APIC_COMMON_CLASS(klass); + + k->realize = mshv_apic_realize; + k->unrealize = mshv_apic_unrealize; + k->reset = mshv_apic_reset; + k->set_base = mshv_apic_set_base; + k->set_tpr = mshv_apic_set_tpr; + k->get_tpr = mshv_apic_get_tpr; + k->external_nmi = mshv_apic_external_nmi; + k->vapic_base_update = mshv_apic_vapic_base_update; + k->send_msi = mshv_send_msi; +} + +static const TypeInfo mshv_apic_info = { + .name = TYPE_MSHV_APIC, + .parent = TYPE_APIC_COMMON, + .instance_size = sizeof(MshvAPICState), + .class_init = mshv_apic_class_init, +}; + +static void mshv_apic_register_types(void) +{ + type_register_static(&mshv_apic_info); +} + +type_init(mshv_apic_register_types) diff --git a/hw/i386/mshv/meson.build b/hw/i386/mshv/meson.build index 0e556851b6..c631ee1302 100644 --- a/hw/i386/mshv/meson.build +++ b/hw/i386/mshv/meson.build @@ -1,4 +1,5 @@ i386_mshv_ss = ss.source_set() i386_mshv_ss.add(files('clock.c')) +i386_mshv_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c')) i386_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss) diff --git a/hw/i386/x86-cpu.c b/hw/i386/x86-cpu.c index 95e08e3c2a..fba313376c 100644 --- a/hw/i386/x86-cpu.c +++ b/hw/i386/x86-cpu.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" #include "system/whpx.h" +#include "system/mshv.h" #include "system/cpu-timers.h" #include "trace.h" @@ -44,6 +45,11 @@ static void pic_irq_request(void *opaque, int irq, int level) X86CPU *cpu = X86_CPU(cs); trace_x86_pic_interrupt(irq, level); + + if (mshv_irqchip_in_kernel()) { + return; + } + if (cpu_is_apic_enabled(cpu->apic_state) && !kvm_irqchip_in_kernel() && !whpx_irqchip_in_kernel()) { CPU_FOREACH(cs) { diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h index f8838a31bb..0602a7c6cc 100644 --- a/include/hw/hyperv/hvgdk_mini.h +++ b/include/hw/hyperv/hvgdk_mini.h @@ -168,6 +168,7 @@ typedef enum hv_register_name { /* Available */ HV_X64_REGISTER_SPEC_CTRL = 0x00080084, + HV_X64_REGISTER_TSC_DEADLINE = 0x00080095, HV_X64_REGISTER_TSC_ADJUST = 0x00080096, /* CET / Shadow Stack */ @@ -930,6 +931,7 @@ struct hv_cpuid { #define IA32_MSR_DEBUG_CTL 0x1D9 #define IA32_MSR_SPEC_CTRL 0x00000048 #define IA32_MSR_TSC_ADJUST 0x0000003b +#define IA32_MSR_TSC_DEADLINE 0x000006e0 #define IA32_MSR_MISC_ENABLE 0x000001a0 diff --git a/include/hw/i386/apic-msidef.h b/include/hw/i386/apic-msidef.h index 420b41167d..6b860b5807 100644 --- a/include/hw/i386/apic-msidef.h +++ b/include/hw/i386/apic-msidef.h @@ -13,6 +13,7 @@ #define MSI_DATA_VECTOR_MASK 0x000000ff #define MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define MSI_DATA_DELIVERY_MODE_MASK 7 #define MSI_DATA_LEVEL_SHIFT 14 #define MSI_DATA_TRIGGER_SHIFT 15 diff --git a/include/system/mshv.h b/include/system/mshv.h index a6f815b822..f98ddff9b5 100644 --- a/include/system/mshv.h +++ b/include/system/mshv.h @@ -41,9 +41,11 @@ extern bool mshv_allowed; #define mshv_enabled() (mshv_allowed) #define mshv_msi_via_irqfd_enabled() mshv_enabled() +#define mshv_irqchip_in_kernel() mshv_enabled() #else /* CONFIG_MSHV_IS_POSSIBLE */ #define mshv_enabled() false #define mshv_msi_via_irqfd_enabled() mshv_enabled() +#define mshv_irqchip_in_kernel() mshv_enabled() #endif #define TYPE_MSHV_ACCEL ACCEL_CLASS_NAME("mshv") diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index b91c4d661a..c2f13c0194 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -105,10 +105,16 @@ void mshv_arch_amend_proc_features( void mshv_arch_disable_partition_proc_features( union hv_partition_processor_features *disabled_features); int mshv_arch_post_init_vm(int vm_fd); - +int mshv_get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state); +int mshv_set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state); typedef struct mshv_root_hvcall mshv_root_hvcall; int mshv_hvcall(int fd, const mshv_root_hvcall *args); +/* apic */ +int mshv_init_lint(CPUState *cpu); +int mshv_set_lapic(const CPUState *cpu); +int mshv_get_lapic(CPUState *cpu); + /* memory */ typedef struct MshvMemoryRegion { uint64_t guest_phys_addr; diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c index 04b7257ad1..b4cf048a7c 100644 --- a/target/i386/cpu-apic.c +++ b/target/i386/cpu-apic.c @@ -14,6 +14,7 @@ #include "system/hw_accel.h" #include "system/kvm.h" #include "system/xen.h" +#include "system/mshv.h" #include "system/address-spaces.h" #include "hw/core/qdev-properties.h" #include "hw/i386/apic_internal.h" @@ -34,6 +35,8 @@ APICCommonClass *apic_get_class(Error **errp) apic_type = "xen-apic"; } else if (whpx_irqchip_in_kernel()) { apic_type = "whpx-apic"; + } else if (mshv_enabled()) { + apic_type = "mshv-apic"; } return APIC_COMMON_CLASS(object_class_by_name(apic_type)); diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index fa15e399cb..00e948903d 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -21,7 +21,6 @@ #include "hw/hyperv/hvgdk.h" #include "hw/hyperv/hvgdk_mini.h" #include "hw/hyperv/hvhdk_mini.h" -#include "hw/i386/apic_internal.h" #include "cpu.h" #include "host-cpu.h" @@ -955,6 +954,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } + ret = mshv_get_lapic(cpu); + if (ret < 0) { + return ret; + } + ret = mshv_get_msrs(cpu); if (ret < 0) { return ret; @@ -1377,116 +1381,6 @@ static int set_xc_reg(const CPUState *cpu) return 0; } -static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state) -{ - int ret; - - ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state); - if (ret < 0) { - error_report("failed to get partition state: %s", strerror(errno)); - return -1; - } - - return 0; -} - -static int get_lapic(const CPUState *cpu, - struct hv_local_interrupt_controller_state *state) -{ - int ret; - size_t size = 4096; - /* buffer aligned to 4k, as *state requires that */ - void *buffer = qemu_memalign(size, size); - struct mshv_get_set_vp_state mshv_state = { 0 }; - int cpu_fd = mshv_vcpufd(cpu); - - mshv_state.buf_ptr = (uint64_t) buffer; - mshv_state.buf_sz = size; - mshv_state.type = MSHV_VP_STATE_LAPIC; - - ret = get_vp_state(cpu_fd, &mshv_state); - if (ret == 0) { - memcpy(state, buffer, sizeof(*state)); - } - qemu_vfree(buffer); - if (ret < 0) { - error_report("failed to get lapic"); - return -1; - } - - return 0; -} - -static uint32_t set_apic_delivery_mode(uint32_t reg, uint32_t mode) -{ - return ((reg) & ~0x700) | ((mode) << 8); -} - -static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state) -{ - int ret; - - ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state); - if (ret < 0) { - error_report("failed to set partition state: %s", strerror(errno)); - return -1; - } - - return 0; -} - -static int set_lapic(const CPUState *cpu, - const struct hv_local_interrupt_controller_state *state) -{ - int ret; - size_t size = 4096; - /* buffer aligned to 4k, as *state requires that */ - void *buffer = qemu_memalign(size, size); - struct mshv_get_set_vp_state mshv_state = { 0 }; - int cpu_fd = mshv_vcpufd(cpu); - - if (!state) { - error_report("lapic state is NULL"); - return -1; - } - memcpy(buffer, state, sizeof(*state)); - - mshv_state.buf_ptr = (uint64_t) buffer; - mshv_state.buf_sz = size; - mshv_state.type = MSHV_VP_STATE_LAPIC; - - ret = set_vp_state(cpu_fd, &mshv_state); - qemu_vfree(buffer); - if (ret < 0) { - error_report("failed to set lapic: %s", strerror(errno)); - return -1; - } - - return 0; -} - -static int init_lint(const CPUState *cpu) -{ - int ret; - uint32_t *lvt_lint0, *lvt_lint1; - - struct hv_local_interrupt_controller_state lapic_state = { 0 }; - ret = get_lapic(cpu, &lapic_state); - if (ret < 0) { - return ret; - } - - lvt_lint0 = &lapic_state.apic_lvt_lint0; - *lvt_lint0 = set_apic_delivery_mode(*lvt_lint0, APIC_DM_EXTINT); - - lvt_lint1 = &lapic_state.apic_lvt_lint1; - *lvt_lint1 = set_apic_delivery_mode(*lvt_lint1, APIC_DM_NMI); - - /* TODO: should we skip setting lapic if the values are the same? */ - - return set_lapic(cpu, &lapic_state); -} - int mshv_arch_store_vcpu_state(const CPUState *cpu) { int ret; @@ -1511,6 +1405,12 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return ret; } + /* INVARIANT: special regs (APIC_BASE) must be restored before LAPIC */ + ret = mshv_set_lapic(cpu); + if (ret < 0) { + return ret; + } + ret = mshv_set_msrs(cpu); if (ret < 0) { return ret; @@ -2100,7 +2000,7 @@ void mshv_arch_init_vcpu(CPUState *cpu) ret = mshv_init_msrs(cpu); assert(ret == 0); - ret = init_lint(cpu); + ret = mshv_init_lint(cpu); assert(ret == 0); } @@ -2247,6 +2147,33 @@ static void mshv_cpu_xsave_init(void) } } +int mshv_set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state) +{ + int ret; + + ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state); + if (ret < 0) { + error_report("failed to set partition state: %s", strerror(errno)); + return -1; + } + + return 0; +} + + +int mshv_get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state) +{ + int ret; + + ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state); + if (ret < 0) { + error_report("failed to get partition state: %s", strerror(errno)); + return -1; + } + + return 0; +} + static void mshv_cpu_instance_init(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); diff --git a/target/i386/mshv/msr.c b/target/i386/mshv/msr.c index 8c220a9942..a5f639c3ca 100644 --- a/target/i386/mshv/msr.c +++ b/target/i386/mshv/msr.c @@ -60,6 +60,8 @@ static const MshvMsrEnvMap msr_env_map[] = { offsetof(CPUX86State, tsc_aux) }, { IA32_MSR_TSC_ADJUST, HV_X64_REGISTER_TSC_ADJUST, offsetof(CPUX86State, tsc_adjust) }, + { IA32_MSR_TSC_DEADLINE, HV_X64_REGISTER_TSC_DEADLINE, + offsetof(CPUX86State, tsc_deadline) }, /* Hyper-V per-partition MSRs */ { HV_X64_MSR_HYPERCALL, HV_X64_REGISTER_HYPERCALL, From 65867d2edea0ec2cb1e7de338a998e0d7d5ee1aa Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:28 +0200 Subject: [PATCH 329/627] target/i386/mshv: migrate Synic SINT MSRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate HyperV SynIC SINT MSRs. We can only read/write those if SCONTROL is enabled in the guest, hence we have to split the SINT MSR out and make reading/writing them dependent on that MSR. Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-7-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/mshv/msr.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/target/i386/mshv/msr.c b/target/i386/mshv/msr.c index a5f639c3ca..5288e32b6d 100644 --- a/target/i386/mshv/msr.c +++ b/target/i386/mshv/msr.c @@ -331,6 +331,8 @@ int mshv_get_msrs(CPUState *cpu) struct hv_register_assoc assocs[MSHV_MSR_TOTAL_COUNT]; size_t i, j; uint32_t name; + X86CPU *x86cpu = X86_CPU(cpu); + bool synic_enabled; set_hv_name_in_assocs(assocs, n_assocs); @@ -357,6 +359,27 @@ int mshv_get_msrs(CPUState *cpu) store_in_env(cpu, assocs, n_assocs); + /* Read SINT MSRs only if SynIC is enabled */ + synic_enabled = x86cpu->env.msr_hv_synic_control & 1; + if (synic_enabled) { + QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT); + + for (i = 0; i < HV_SINT_COUNT; i++) { + assocs[i].name = HV_REGISTER_SINT0 + i; + } + + ret = mshv_get_generic_regs(cpu, assocs, HV_SINT_COUNT); + if (ret < 0) { + error_report("Failed to get SynIC SINT MSRs"); + return -errno; + } + + for (i = 0; i < HV_SINT_COUNT; i++) { + uint64_t hv_sint_value = assocs[i].value.reg64; + x86cpu->env.msr_hv_synic_sint[i] = hv_sint_value; + } + } + return 0; } @@ -391,6 +414,8 @@ int mshv_set_msrs(const CPUState *cpu) struct hv_register_assoc assocs[MSHV_MSR_TOTAL_COUNT]; int ret; size_t i, j; + X86CPU *x86cpu = X86_CPU(cpu); + bool synic_enabled = x86cpu->env.msr_hv_synic_control & 1; load_from_env(cpu, assocs, n_assocs); @@ -423,5 +448,21 @@ int mshv_set_msrs(const CPUState *cpu) return -errno; } + /* SINT MSRs can only be written if SCONTROL has been set, so we split */ + if (synic_enabled) { + QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT); + + for (i = 0; i < HV_SINT_COUNT; i++) { + assocs[i].name = HV_REGISTER_SINT0 + i; + assocs[i].value.reg64 = x86cpu->env.msr_hv_synic_sint[i]; + } + + ret = mshv_set_generic_regs(cpu, assocs, HV_SINT_COUNT); + if (ret < 0) { + error_report("Failed to set SynIC SINT MSRs"); + return -errno; + } + } + return 0; } From e514ff235b41c5582becc821b79f466d62f90c83 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:29 +0200 Subject: [PATCH 330/627] target/i386/mshv: migrate SIMP and SIEFP state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This part SynIC state is retrieved from the hypervisor via aligned state pages: - Add new synic source file - Centralize the synic_enabled() check - r/w pages from the hyper via aligned pages - only handle pages when synic is enabled - add buffers for migration to VM state Signed-off-by: Magnus Kulke Reviewed-by: Doru Blânzeanu Link: https://lore.kernel.org/r/20260710101534.664604-8-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- include/system/mshv_int.h | 7 ++ target/i386/cpu.h | 5 ++ target/i386/machine.c | 26 ++++++ target/i386/mshv/meson.build | 1 + target/i386/mshv/mshv-cpu.c | 64 +++++++++++++++ target/i386/mshv/msr.c | 7 +- target/i386/mshv/synic.c | 155 +++++++++++++++++++++++++++++++++++ 7 files changed, 260 insertions(+), 5 deletions(-) create mode 100644 target/i386/mshv/synic.c diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index c2f13c0194..bc023d3535 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -138,4 +138,11 @@ int mshv_init_msrs(const CPUState *cpu); int mshv_get_msrs(CPUState *cpu); int mshv_set_msrs(const CPUState *cpu); +/* synic */ +int mshv_get_simp(int cpu_fd, uint8_t *page); +int mshv_set_simp(int cpu_fd, const uint8_t *page); +int mshv_get_siefp(int cpu_fd, uint8_t *page); +int mshv_set_siefp(int cpu_fd, const uint8_t *page); +bool mshv_synic_enabled(const CPUState *cpu); + #endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index fff701c6c4..fcde895600 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -33,6 +33,7 @@ #include "qemu/cpu-float.h" #include "qemu/timer.h" #include "standard-headers/asm-x86/kvm_para.h" +#include "hw/hyperv/hvgdk_mini.h" #define XEN_NR_VIRQS 24 @@ -2301,6 +2302,10 @@ typedef struct CPUArchState { #if defined(CONFIG_HVF) || defined(CONFIG_MSHV) || defined(CONFIG_WHPX) void *emu_mmio_buf; #endif +#if defined(CONFIG_MSHV) + uint8_t hv_simp_page[HV_HYP_PAGE_SIZE]; + uint8_t hv_siefp_page[HV_HYP_PAGE_SIZE]; +#endif uint64_t mcg_cap; uint64_t mcg_ctl; diff --git a/target/i386/machine.c b/target/i386/machine.c index df0e0c178e..023a397ab8 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -951,6 +951,29 @@ static const VMStateDescription vmstate_msr_hyperv_reenlightenment = { } }; +#ifdef CONFIG_MSHV +static bool mshv_synic_vp_state_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + /* Only migrate SIMP/SIEFP if SynIC is enabled */ + return env->msr_hv_synic_control & 1; +} + +static const VMStateDescription vmstate_mshv_synic_vp_state = { + .name = "cpu/mshv_synic_vp_state", + .version_id = 1, + .minimum_version_id = 1, + .needed = mshv_synic_vp_state_needed, + .fields = (const VMStateField[]) { + VMSTATE_BUFFER(env.hv_simp_page, X86CPU), + VMSTATE_BUFFER(env.hv_siefp_page, X86CPU), + VMSTATE_END_OF_LIST() + } +}; +#endif + static bool avx512_needed(void *opaque) { X86CPU *cpu = opaque; @@ -1915,6 +1938,9 @@ const VMStateDescription vmstate_x86_cpu = { &vmstate_cet, #ifdef TARGET_X86_64 &vmstate_apx, +#endif +#ifdef CONFIG_MSHV + &vmstate_mshv_synic_vp_state, #endif NULL } diff --git a/target/i386/mshv/meson.build b/target/i386/mshv/meson.build index 6091c21887..31ff4cc995 100644 --- a/target/i386/mshv/meson.build +++ b/target/i386/mshv/meson.build @@ -3,6 +3,7 @@ i386_mshv_ss = ss.source_set() i386_mshv_ss.add(files( 'mshv-cpu.c', 'msr.c', + 'synic.c', )) i386_system_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss) diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 00e948903d..ea6a660d05 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -111,6 +111,33 @@ static enum hv_register_name FPU_REGISTER_NAMES[26] = { static int set_special_regs(const CPUState *cpu); +static int get_synic_state(CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + int cpu_fd = mshv_vcpufd(cpu); + int ret; + + /* SIMP/SIEFP can only be read when SynIC is enabled */ + if (!mshv_synic_enabled(cpu)) { + return 0; + } + + ret = mshv_get_simp(cpu_fd, env->hv_simp_page); + if (ret < 0) { + error_report("failed to get simp state"); + return -1; + } + + ret = mshv_get_siefp(cpu_fd, env->hv_siefp_page); + if (ret < 0) { + error_report("failed to get siefp state"); + return -1; + } + + return 0; +} + static int get_xsave_state(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); @@ -969,6 +996,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } + ret = get_synic_state(cpu); + if (ret < 0) { + return ret; + } + ret = get_vcpu_events(cpu); if (ret < 0) { return ret; @@ -1381,6 +1413,33 @@ static int set_xc_reg(const CPUState *cpu) return 0; } +static int set_synic_state(const CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + int cpu_fd = mshv_vcpufd(cpu); + int ret; + + /* SIMP/SIEFP can only be written when SynIC is enabled */ + if (!mshv_synic_enabled(cpu)) { + return 0; + } + + ret = mshv_set_simp(cpu_fd, env->hv_simp_page); + if (ret < 0) { + error_report("failed to set simp state"); + return -1; + } + + ret = mshv_set_siefp(cpu_fd, env->hv_siefp_page); + if (ret < 0) { + error_report("failed to set siefp state"); + return -1; + } + + return 0; +} + int mshv_arch_store_vcpu_state(const CPUState *cpu) { int ret; @@ -1422,6 +1481,11 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return ret; } + ret = set_synic_state(cpu); + if (ret < 0) { + return ret; + } + ret = set_vcpu_events(cpu); if (ret < 0) { return ret; diff --git a/target/i386/mshv/msr.c b/target/i386/mshv/msr.c index 5288e32b6d..d3788d7715 100644 --- a/target/i386/mshv/msr.c +++ b/target/i386/mshv/msr.c @@ -332,7 +332,6 @@ int mshv_get_msrs(CPUState *cpu) size_t i, j; uint32_t name; X86CPU *x86cpu = X86_CPU(cpu); - bool synic_enabled; set_hv_name_in_assocs(assocs, n_assocs); @@ -360,8 +359,7 @@ int mshv_get_msrs(CPUState *cpu) store_in_env(cpu, assocs, n_assocs); /* Read SINT MSRs only if SynIC is enabled */ - synic_enabled = x86cpu->env.msr_hv_synic_control & 1; - if (synic_enabled) { + if (mshv_synic_enabled(cpu)) { QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT); for (i = 0; i < HV_SINT_COUNT; i++) { @@ -415,7 +413,6 @@ int mshv_set_msrs(const CPUState *cpu) int ret; size_t i, j; X86CPU *x86cpu = X86_CPU(cpu); - bool synic_enabled = x86cpu->env.msr_hv_synic_control & 1; load_from_env(cpu, assocs, n_assocs); @@ -449,7 +446,7 @@ int mshv_set_msrs(const CPUState *cpu) } /* SINT MSRs can only be written if SCONTROL has been set, so we split */ - if (synic_enabled) { + if (mshv_synic_enabled(cpu)) { QEMU_BUILD_BUG_ON(MSHV_MSR_TOTAL_COUNT < HV_SINT_COUNT); for (i = 0; i < HV_SINT_COUNT; i++) { diff --git a/target/i386/mshv/synic.c b/target/i386/mshv/synic.c new file mode 100644 index 0000000000..8f9fee6ed7 --- /dev/null +++ b/target/i386/mshv/synic.c @@ -0,0 +1,155 @@ +/* + * QEMU MSHV SynIC support + * + * Copyright Microsoft, Corp. 2026 + * + * Authors: Magnus Kulke + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/memalign.h" +#include "qemu/error-report.h" + +#include "system/mshv.h" +#include "system/mshv_int.h" + +#include "linux/mshv.h" +#include "hw/hyperv/hvgdk_mini.h" +#include "cpu.h" + +#include + +bool mshv_synic_enabled(const CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + + return x86cpu->env.msr_hv_synic_control & 1; +} + +static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state) +{ + int ret; + + ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state); + if (ret < 0) { + error_report("failed to get vp state: %s", strerror(errno)); + return -1; + } + + return 0; +} + +static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state) +{ + int ret; + + ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state); + if (ret < 0) { + error_report("failed to set vp state: %s", strerror(errno)); + return -1; + } + + return 0; +} + +int mshv_get_simp(int cpu_fd, uint8_t *page) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SIMP; + + ret = get_vp_state(cpu_fd, &args); + + if (ret < 0) { + qemu_vfree(buffer); + error_report("failed to get simp"); + return -1; + } + + memcpy(page, buffer, HV_HYP_PAGE_SIZE); + qemu_vfree(buffer); + + return 0; +} + +int mshv_set_simp(int cpu_fd, const uint8_t *page) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SIMP; + + assert(page); + memcpy(buffer, page, HV_HYP_PAGE_SIZE); + + ret = set_vp_state(cpu_fd, &args); + qemu_vfree(buffer); + + if (ret < 0) { + error_report("failed to set simp"); + return -1; + } + + return 0; +} + +int mshv_get_siefp(int cpu_fd, uint8_t *page) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SIEFP, + + ret = get_vp_state(cpu_fd, &args); + + if (ret < 0) { + qemu_vfree(buffer); + error_report("failed to get siefp"); + return -1; + } + + memcpy(page, buffer, HV_HYP_PAGE_SIZE); + qemu_vfree(buffer); + + return 0; +} + +int mshv_set_siefp(int cpu_fd, const uint8_t *page) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SIEFP, + + assert(page); + memcpy(buffer, page, HV_HYP_PAGE_SIZE); + + ret = set_vp_state(cpu_fd, &args); + qemu_vfree(buffer); + + if (ret < 0) { + error_report("failed to set simp"); + return -1; + } + + return 0; +} From f2c8f7bcd424e17aea74fdb84d739887f1d52aa1 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:30 +0200 Subject: [PATCH 331/627] target/i386/mshv: migrate STIMER state This part of Synic state is retrieved via a mem-aligned page. We declare the required space (size reference: rust-vmm/mshv) as a buffer on the VM state struct for inclusion in a migration. Other than other SynIC features, STIMER doesn't depend on SCONTROL being set. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20260710101534.664604-9-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- include/system/mshv_int.h | 2 ++ target/i386/cpu.h | 5 ++++ target/i386/machine.c | 20 +++++++++++++++ target/i386/mshv/mshv-cpu.c | 12 +++++++++ target/i386/mshv/synic.c | 51 +++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index bc023d3535..063852115e 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -144,5 +144,7 @@ int mshv_set_simp(int cpu_fd, const uint8_t *page); int mshv_get_siefp(int cpu_fd, uint8_t *page); int mshv_set_siefp(int cpu_fd, const uint8_t *page); bool mshv_synic_enabled(const CPUState *cpu); +int mshv_get_synthetic_timers(int cpu_fd, uint8_t *state); +int mshv_set_synthetic_timers(int cpu_fd, const uint8_t *state); #endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index fcde895600..641f3ee5c2 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -45,6 +45,10 @@ #define ELF_MACHINE_UNAME "i686" #endif +#ifdef CONFIG_MSHV +#define MSHV_STIMERS_STATE_SIZE 200 +#endif + enum { R_EAX = 0, R_ECX = 1, @@ -2305,6 +2309,7 @@ typedef struct CPUArchState { #if defined(CONFIG_MSHV) uint8_t hv_simp_page[HV_HYP_PAGE_SIZE]; uint8_t hv_siefp_page[HV_HYP_PAGE_SIZE]; + uint8_t hv_synthetic_timers_state[MSHV_STIMERS_STATE_SIZE]; #endif uint64_t mcg_cap; diff --git a/target/i386/machine.c b/target/i386/machine.c index 023a397ab8..8d69d7e25e 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -10,6 +10,7 @@ #include "exec/watchpoint.h" #include "system/kvm.h" #include "system/kvm_xen.h" +#include "system/mshv.h" #include "system/tcg.h" #include "qemu/error-report.h" @@ -952,6 +953,24 @@ static const VMStateDescription vmstate_msr_hyperv_reenlightenment = { }; #ifdef CONFIG_MSHV + +static bool mshv_synthetic_timers_needed(void *opaque) +{ + /* Always migrate synthetic timers */ + return mshv_enabled(); +} + +static const VMStateDescription vmstate_mshv_synthetic_timers = { + .name = "cpu/mshv_synthetic_timers", + .version_id = 1, + .minimum_version_id = 1, + .needed = mshv_synthetic_timers_needed, + .fields = (const VMStateField[]) { + VMSTATE_BUFFER(env.hv_synthetic_timers_state, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + static bool mshv_synic_vp_state_needed(void *opaque) { X86CPU *cpu = opaque; @@ -1941,6 +1960,7 @@ const VMStateDescription vmstate_x86_cpu = { #endif #ifdef CONFIG_MSHV &vmstate_mshv_synic_vp_state, + &vmstate_mshv_synthetic_timers, #endif NULL } diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index ea6a660d05..86d64c67fb 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -118,6 +118,12 @@ static int get_synic_state(CPUState *cpu) int cpu_fd = mshv_vcpufd(cpu); int ret; + ret = mshv_get_synthetic_timers(cpu_fd, env->hv_synthetic_timers_state); + if (ret < 0) { + error_report("failed to get synthetic timers"); + return -1; + } + /* SIMP/SIEFP can only be read when SynIC is enabled */ if (!mshv_synic_enabled(cpu)) { return 0; @@ -1420,6 +1426,12 @@ static int set_synic_state(const CPUState *cpu) int cpu_fd = mshv_vcpufd(cpu); int ret; + ret = mshv_set_synthetic_timers(cpu_fd, env->hv_synthetic_timers_state); + if (ret < 0) { + error_report("failed to set synthetic timers state"); + return -1; + } + /* SIMP/SIEFP can only be written when SynIC is enabled */ if (!mshv_synic_enabled(cpu)) { return 0; diff --git a/target/i386/mshv/synic.c b/target/i386/mshv/synic.c index 8f9fee6ed7..4c629adc3a 100644 --- a/target/i386/mshv/synic.c +++ b/target/i386/mshv/synic.c @@ -54,6 +54,57 @@ static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state) return 0; } +int mshv_get_synthetic_timers(int cpu_fd, uint8_t *state) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SYNTHETIC_TIMERS; + + ret = get_vp_state(cpu_fd, &args); + + if (ret < 0) { + qemu_vfree(buffer); + error_report("failed to get synthetic timers"); + return -1; + } + + memcpy(state, buffer, MSHV_STIMERS_STATE_SIZE); + qemu_vfree(buffer); + + return 0; +} + +int mshv_set_synthetic_timers(int cpu_fd, const uint8_t *state) +{ + int ret; + void *buffer; + struct mshv_get_set_vp_state args = {0}; + + buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE); + memset(buffer, 0, HV_HYP_PAGE_SIZE); + args.buf_ptr = (uint64_t)buffer; + args.buf_sz = HV_HYP_PAGE_SIZE; + args.type = MSHV_VP_STATE_SYNTHETIC_TIMERS; + + assert(state); + memcpy(buffer, state, MSHV_STIMERS_STATE_SIZE); + + ret = set_vp_state(cpu_fd, &args); + qemu_vfree(buffer); + + if (ret < 0) { + error_report("failed to set synthetic timers"); + return -1; + } + + return 0; +} + int mshv_get_simp(int cpu_fd, uint8_t *page) { int ret; From 49cd174b56ae5db509a075752a8a9e5247ebbc2e Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:31 +0200 Subject: [PATCH 332/627] accel/mshv: write synthetic MSRs after migration Write partition-wide synthetic MSRs. This ensures the hypercall page and SynIC facilities are set up before vCPUs attempt to use it. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20260710101534.664604-10-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 15 +++++++++++++++ include/hw/hyperv/hvgdk_mini.h | 3 +++ include/system/mshv_int.h | 1 + target/i386/mshv/mshv-cpu.c | 15 +++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 1516475f34..1ca1d4b54f 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -60,6 +60,20 @@ static int init_mshv(int *mshv_fd) return 0; } +static int mshv_load_cleanup(void *opaque) +{ + int ret; + + ret = mshv_arch_set_partition_msrs(first_cpu); + if (ret < 0) { + error_report("Failed to set partition MSRs: %s", strerror(-ret)); + return -1; + } + + return 0; +} + + static int get_host_partition_property(int mshv_fd, uint32_t property_code, uint64_t *value) { @@ -496,6 +510,7 @@ static int mshv_init_vcpu(CPUState *cpu) } static SaveVMHandlers savevm_mshv = { + .load_cleanup = mshv_load_cleanup, }; static int mshv_init(AccelState *as, MachineState *ms) diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h index 0602a7c6cc..a5527d49cf 100644 --- a/include/hw/hyperv/hvgdk_mini.h +++ b/include/hw/hyperv/hvgdk_mini.h @@ -23,6 +23,9 @@ #define HV_X64_MSR_APIC_FREQUENCY 0x40000023 typedef enum hv_register_name { + /* VP Management Registers */ + HV_REGISTER_INTERNAL_ACTIVITY_STATE = 0x00000004, + /* Pending Interruption Register */ HV_REGISTER_PENDING_INTERRUPTION = 0x00010002, HV_REGISTER_INTERRUPT_STATE = 0x00010003, diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index 063852115e..cbfcb8611b 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -98,6 +98,7 @@ int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs, size_t n_regs); int mshv_arch_store_vcpu_state(const CPUState *cpu); int mshv_arch_load_vcpu_state(CPUState *cpu); +int mshv_arch_set_partition_msrs(const CPUState *cpu); void mshv_arch_init_vcpu(CPUState *cpu); void mshv_arch_destroy_vcpu(CPUState *cpu); void mshv_arch_amend_proc_features( diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 86d64c67fb..6bb3045752 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -1506,6 +1506,21 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return 0; } +int mshv_arch_set_partition_msrs(const CPUState *cpu) +{ + CPUX86State *env = &X86_CPU(cpu)->env; + struct hv_register_assoc assocs[] = { + { .name = HV_REGISTER_GUEST_OS_ID, + .value.reg64 = env->msr_hv_guest_os_id }, + { .name = HV_REGISTER_REFERENCE_TSC, + .value.reg64 = env->msr_hv_tsc }, + { .name = HV_X64_REGISTER_HYPERCALL, + .value.reg64 = env->msr_hv_hypercall }, + }; + + return mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs)); +} + void mshv_arch_amend_proc_features( union hv_partition_synthetic_processor_features *features) { From ec38b3d54c4ff314670b923a50daf0bd7c040b8a Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:32 +0200 Subject: [PATCH 333/627] target/i386/mshv: migrate MP_STATE MSHV's "internal activity state" roughly maps to QEMU's env->mp_state and cpu->halted states that describe state of APs in a guest. We don't invoke set_mp_state as part of store_vcpu_state() b/c we would put all BSP + APs in a RUNNABLE (0) state immediately, breaking SMP boot Instead we store the mp state as part of the load_cleanup() routine after a migration. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20260710101534.664604-11-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- accel/mshv/mshv-all.c | 10 +++++ include/system/mshv_int.h | 1 + target/i386/mshv/mshv-cpu.c | 80 +++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 1ca1d4b54f..5921ce693e 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -62,6 +62,7 @@ static int init_mshv(int *mshv_fd) static int mshv_load_cleanup(void *opaque) { + CPUState *cpu; int ret; ret = mshv_arch_set_partition_msrs(first_cpu); @@ -70,6 +71,15 @@ static int mshv_load_cleanup(void *opaque) return -1; } + CPU_FOREACH(cpu) { + ret = mshv_arch_set_mp_state(cpu); + if (ret < 0) { + error_report("Failed to set mp state for vCPU %d: %s", + cpu->cpu_index, strerror(-ret)); + return -1; + } + } + return 0; } diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index cbfcb8611b..3dffe3c5fb 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -99,6 +99,7 @@ int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs, int mshv_arch_store_vcpu_state(const CPUState *cpu); int mshv_arch_load_vcpu_state(CPUState *cpu); int mshv_arch_set_partition_msrs(const CPUState *cpu); +int mshv_arch_set_mp_state(const CPUState *cpu); void mshv_arch_init_vcpu(CPUState *cpu); void mshv_arch_destroy_vcpu(CPUState *cpu); void mshv_arch_amend_proc_features( diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 6bb3045752..f528dd2b9a 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -35,6 +35,11 @@ #include +#define MSHV_MP_STATE_RUNNABLE 0 +#define MSHV_MP_STATE_UNINITIALIZED 1 +#define MSHV_MP_STATE_INIT_RECEIVED 2 +#define MSHV_MP_STATE_HALTED 3 + #define MAX_REGISTER_COUNT (MAX_CONST(ARRAY_SIZE(STANDARD_REGISTER_NAMES), \ MAX_CONST(ARRAY_SIZE(SPECIAL_REGISTER_NAMES), \ ARRAY_SIZE(FPU_REGISTER_NAMES)))) @@ -950,6 +955,76 @@ static int set_vcpu_events(const CPUState *cpu) return 0; } +static int get_mp_state(CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + struct hv_register_assoc assoc = { + .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE, + }; + union hv_internal_activity_register activity; + int ret; + + ret = mshv_get_generic_regs(cpu, &assoc, 1); + if (ret < 0) { + error_report("failed to get internal activity state"); + return -1; + } + + activity.as_uint64 = assoc.value.reg64; + + /* + * map MSHV activity state to KVM mp_state values, which are used as the + * shared representation in env->mp_state and serialized by vmstate_x86_cpu. + */ + + if (activity.startup_suspend) { + env->mp_state = MSHV_MP_STATE_UNINITIALIZED; + } else if (activity.halt_suspend) { + env->mp_state = MSHV_MP_STATE_HALTED; + } else { + env->mp_state = MSHV_MP_STATE_RUNNABLE; + } + + cpu->halted = (env->mp_state == MSHV_MP_STATE_HALTED); + + return 0; +} + +int mshv_arch_set_mp_state(const CPUState *cpu) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + union hv_internal_activity_register activity = { 0 }; + struct hv_register_assoc assoc = { + .name = HV_REGISTER_INTERNAL_ACTIVITY_STATE, + }; + int ret; + + switch (env->mp_state) { + case MSHV_MP_STATE_HALTED: + activity.halt_suspend = 1; + break; + case MSHV_MP_STATE_UNINITIALIZED: + case MSHV_MP_STATE_INIT_RECEIVED: + activity.startup_suspend = 1; + break; + case MSHV_MP_STATE_RUNNABLE: + default: + break; + } + + assoc.value.reg64 = activity.as_uint64; + + ret = mshv_set_generic_regs(cpu, &assoc, 1); + if (ret < 0) { + error_report("failed to set internal activity state"); + return -1; + } + + return 0; +} + static int update_hflags(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); @@ -1012,6 +1087,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } + ret = get_mp_state(cpu); + if (ret < 0) { + return ret; + } + return 0; } From 24bf07b6e2e3fc99c65035ffa778951cbcbfb475 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Fri, 10 Jul 2026 12:15:34 +0200 Subject: [PATCH 334/627] hw/i386/mshv: drop initial msi vector 0 This has been a warning before that was always raised if the machine has a hpet. hpet_reset() will eventually result in mshv_send_msi called w/ vector 0, which we can safely drop. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20260710101534.664604-13-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- hw/i386/mshv/apic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/i386/mshv/apic.c b/hw/i386/mshv/apic.c index 9188a93b2f..ad326030bf 100644 --- a/hw/i386/mshv/apic.c +++ b/hw/i386/mshv/apic.c @@ -293,6 +293,16 @@ static void mshv_send_msi(MSIMessage *msi) delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & MSI_DATA_DELIVERY_MODE_MASK; + /* + * Vector 0 is not a valid interrupt vector (0-15 are reserved for CPU + * exceptions). This can trigger during machine reset, if hpet_reset() + * forces the PIT to pulse GSI 2 before IOAPIC's own reset has masked its + * redirection entries. + */ + if (vector == 0) { + return; + } + mshv_request_interrupt(mshv_state, delivery, vector, dest, dest_mode, trigger_mode); } From 4196b5f0a0c01581418263fb8d9f63a179741b2c Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:54 +0530 Subject: [PATCH 335/627] target/i386: SEV: Generalize handling of SVM_SEV_FEAT_SNP_ACTIVE Align with IGVM files providing SEV features with SVM_SEV_FEAT_SNP_ACTIVE set by setting the same when creating a sev-snp-guest object. Since KVM sets this feature itself, SVM_SEV_FEAT_SNP_ACTIVE is unset before KVM_SEV_INIT2 ioctl is invoked. Move that out of IGVM-specific section to common code. While at it, convert the existing SVM_SEV_FEAT_SNP_ACTIVE definition to use the BIT() macro for consistency with upcoming feature flags. Reviewed-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/031de849edf2ae4eaa6e00df83b053605a3ecfea.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 24 +++++++++++++++++------- target/i386/sev.h | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index d7dcefc8ec..7b03f534b1 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -324,6 +324,15 @@ sev_set_guest_state(SevCommonState *sev_common, SevState new_state) sev_common->state = new_state; } +static void sev_set_feature(SevCommonState *sev_common, uint64_t feature, bool set) +{ + if (set) { + sev_common->sev_features |= feature; + } else { + sev_common->sev_features &= ~feature; + } +} + static void sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, size_t max_size) @@ -1899,15 +1908,15 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) ->process(x86machine->igvm, machine, true, errp) == -1) { return -1; } - /* - * KVM maintains a bitmask of allowed sev_features. This does not - * include SVM_SEV_FEAT_SNP_ACTIVE which is set accordingly by KVM - * itself. Therefore we need to clear this flag. - */ - args.vmsa_features = sev_common->sev_features & - ~SVM_SEV_FEAT_SNP_ACTIVE; } + /* + * KVM maintains a bitmask of allowed sev_features. This does not + * include SVM_SEV_FEAT_SNP_ACTIVE which is set accordingly by KVM + * itself. Therefore we need to clear this flag. + */ + args.vmsa_features = sev_common->sev_features & ~SVM_SEV_FEAT_SNP_ACTIVE; + ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_INIT2, &args, &fw_error); break; } @@ -3211,6 +3220,7 @@ sev_snp_guest_instance_init(Object *obj) /* default init/start/finish params for kvm */ sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY; + sev_set_feature(SEV_COMMON(sev_snp_guest), SVM_SEV_FEAT_SNP_ACTIVE, true); } static void diff --git a/target/i386/sev.h b/target/i386/sev.h index 4358df40e4..b84ca3ce0b 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -46,7 +46,7 @@ bool sev_snp_enabled(void); #define SEV_SNP_POLICY_SMT 0x10000 #define SEV_SNP_POLICY_DBG 0x80000 -#define SVM_SEV_FEAT_SNP_ACTIVE 1 +#define SVM_SEV_FEAT_SNP_ACTIVE BIT(0) typedef struct SevKernelLoaderContext { char *setup_data; From a593e468dac5e3d7815eba8993304909efb16f9e Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:55 +0530 Subject: [PATCH 336/627] target/i386: SEV: Ensure SEV features are only set through qemu cli or IGVM In preparation for qemu being able to set SEV features through the cli, add a check to ensure that SEV features are not also set if using IGVM files. Reviewed-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/6939de99f13d7170af68b74e711eb9f03f32f682.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index 7b03f534b1..093d29e761 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1904,6 +1904,16 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) * as SEV_STATE_UNINIT. */ if (x86machine->igvm) { + /* + * Test only the user-set SEV features by masking out + * SVM_SEV_FEAT_SNP_ACTIVE which is set by default. + */ + if (sev_common->sev_features & ~SVM_SEV_FEAT_SNP_ACTIVE) { + error_setg(errp, + "%s: SEV features can't be specified when using IGVM files", + __func__); + return -1; + } if (IGVM_CFG_GET_CLASS(x86machine->igvm) ->process(x86machine->igvm, machine, true, errp) == -1) { return -1; From 9743cd30f33ff9ab5338efc3801505f125280587 Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:56 +0530 Subject: [PATCH 337/627] target/i386: SEV: Consolidate SEV feature validation to common init path Currently, check_sev_features() is called in multiple places when processing IGVM files: both when processing the initial VMSA SEV features from IGVM, as well as when validating the full contents of the VMSA. Move this to a single point in sev_common_kvm_init() to simplify the flow, as well as to re-use this function when VMSA SEV features are being set without using IGVM files. Reviewed-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/35449df94eb20c29923a7cd0e2742ddba605928c.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 093d29e761..d8fb88d2b2 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -600,9 +600,6 @@ static int check_vmsa_supported(SevCommonState *sev_common, hwaddr gpa, vmsa_check.x87_fcw = 0; vmsa_check.mxcsr = 0; - if (check_sev_features(sev_common, vmsa_check.sev_features, errp) < 0) { - return -1; - } vmsa_check.sev_features = 0; if (!buffer_is_zero(&vmsa_check, sizeof(vmsa_check))) { @@ -1920,6 +1917,10 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) } } + if (check_sev_features(sev_common, sev_common->sev_features, errp) < 0) { + return -1; + } + /* * KVM maintains a bitmask of allowed sev_features. This does not * include SVM_SEV_FEAT_SNP_ACTIVE which is set accordingly by KVM @@ -2581,9 +2582,6 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, __func__); return -1; } - if (check_sev_features(sev_common, sa->sev_features, errp) < 0) { - return -1; - } sev_common->sev_features = sa->sev_features; } return 0; From c93800f544dbac9ea7bf78cd802ab0731224b27f Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:57 +0530 Subject: [PATCH 338/627] target/i386: SEV: Validate that SEV-ES is enabled when VMSA features are used SEV features in the VMSA are only meaningful for SEV-ES and SEV-SNP guests, as they control aspects of the encrypted guest state that are not relevant for basic SEV guests. Add a check in check_sev_features() to ensure that SEV-ES or SEV-SNP is enabled when any SEV features are specified. Reviewed-by: Nikunj A Dadhania Reviewed-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/11e34ae3db91643e45e097404d1aa949a820aa0d.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/i386/sev.c b/target/i386/sev.c index d8fb88d2b2..52379855b3 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -523,6 +523,12 @@ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, __func__); return -1; } + if (sev_features && !sev_es_enabled()) { + error_setg(errp, + "%s: SEV features require either SEV-ES or SEV-SNP to be enabled", + __func__); + return -1; + } if (sev_features & ~sev_common->supported_sev_features) { error_setg(errp, "%s: VMSA contains unsupported sev_features: %lX, " From 891d419f972f96b19ef7531dc72c11c302af5f35 Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:58 +0530 Subject: [PATCH 339/627] target/i386: SEV: Enable use of KVM_SEV_INIT2 for SEV-ES guests In preparation for allowing SEV-ES guests to enable VMSA SEV features, update sev_init2_required() to return true if any SEV features are requested. This enables qemu to use KVM_SEV_INIT2 for SEV-ES guests when necessary. Reviewed-by: Nikunj A Dadhania Reviewed-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/f2a7778ab26b11a8de90e170ff984ccd29dc05a0.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 52379855b3..9cdccc872a 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -1697,8 +1697,7 @@ sev_vm_state_change(void *opaque, bool running, RunState state) */ static bool sev_init2_required(SevGuestState *sev_guest) { - /* Currently no KVM_SEV_INIT2-specific options are exposed via QEMU */ - return false; + return !!SEV_COMMON(sev_guest)->sev_features; } static int sev_kvm_type(X86ConfidentialGuest *cg) From 51ac358fdeab4e84b0ba8a3e38123eba7054e50d Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:57:59 +0530 Subject: [PATCH 340/627] target/i386: SEV: Add support for enabling debug-swap SEV feature Add support for enabling debug-swap VMSA SEV feature in SEV-ES and SEV-SNP guests through a new "debug-swap" boolean property on SEV guest objects. Though the boolean property is available for plain SEV guests, check_sev_features() has a check that rejects attempts to enable any SEV feature for a plain SEV guest. Though this SEV feature is called "Debug virtualization" in the APM, KVM calls this "debug swap" so use the same name for consistency. Sample command-line: -machine q35,confidential-guest-support=sev0 \ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,debug-swap=on Restrict debug-swap to SEV-SNP guests at this time due to a compatibility issue with SEV-ES pflash devices. Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/416e7b156e49f95958f8c5c8549b48a88c1995fc.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- qapi/qom.json | 7 ++++++- target/i386/sev.c | 26 ++++++++++++++++++++++++++ target/i386/sev.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index c55776af7d..ad7e39aa75 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1017,6 +1017,10 @@ # designated guest firmware page for measured boot with -kernel # (default: false) (since 6.2) # +# @debug-swap: enable virtualization of debug registers, +# only supported on SEV-ES and SEV-SNP guests +# (default: false) (since 11.1) +# # Features: # # @confidential-guest-reset: If present, the hypervisor supports @@ -1028,7 +1032,8 @@ 'data': { '*sev-device': 'str', '*cbitpos': 'uint32', 'reduced-phys-bits': 'uint32', - '*kernel-hashes': 'bool' }, + '*kernel-hashes': 'bool', + '*debug-swap': 'bool' }, 'features': ['confidential-guest-reset']} ## diff --git a/target/i386/sev.c b/target/i386/sev.c index 9cdccc872a..2103a121aa 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -324,6 +324,11 @@ sev_set_guest_state(SevCommonState *sev_common, SevState new_state) sev_common->state = new_state; } +static bool is_sev_feature_set(SevCommonState *sev_common, uint64_t feature) +{ + return !!(sev_common->sev_features & feature); +} + static void sev_set_feature(SevCommonState *sev_common, uint64_t feature, bool set) { if (set) { @@ -523,6 +528,12 @@ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, __func__); return -1; } + if (sev_features && sev_es_enabled() && !sev_snp_enabled()) { + error_setg(errp, + "%s: SEV features are not supported with SEV-ES at this time", + __func__); + return -1; + } if (sev_features && !sev_es_enabled()) { error_setg(errp, "%s: SEV features require either SEV-ES or SEV-SNP to be enabled", @@ -2797,6 +2808,16 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type, return 0; } +static bool sev_common_get_debug_swap(Object *obj, Error **errp) +{ + return is_sev_feature_set(SEV_COMMON(obj), SVM_SEV_FEAT_DEBUG_SWAP); +} + +static void sev_common_set_debug_swap(Object *obj, bool value, Error **errp) +{ + sev_set_feature(SEV_COMMON(obj), SVM_SEV_FEAT_DEBUG_SWAP, value); +} + static void sev_common_class_init(ObjectClass *oc, const void *data) { @@ -2822,6 +2843,11 @@ sev_common_class_init(ObjectClass *oc, const void *data) sev_common_set_kernel_hashes); object_class_property_set_description(oc, "kernel-hashes", "add kernel hashes to guest firmware for measured Linux boot"); + object_class_property_add_bool(oc, "debug-swap", + sev_common_get_debug_swap, + sev_common_set_debug_swap); + object_class_property_set_description(oc, "debug-swap", + "enable virtualization of debug registers"); } static void diff --git a/target/i386/sev.h b/target/i386/sev.h index b84ca3ce0b..d19a396697 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -47,6 +47,7 @@ bool sev_snp_enabled(void); #define SEV_SNP_POLICY_DBG 0x80000 #define SVM_SEV_FEAT_SNP_ACTIVE BIT(0) +#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) typedef struct SevKernelLoaderContext { char *setup_data; From a26f9b975d5c0690ac5828fadb6242bfee79c008 Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:58:00 +0530 Subject: [PATCH 341/627] target/i386: SEV: Add support for enabling Secure TSC SEV feature Add support for enabling Secure TSC VMSA SEV feature in SEV-SNP guests through a new "secure-tsc" boolean property on SEV-SNP guest objects. By default, KVM uses the host TSC frequency for Secure TSC. Sample command-line: -machine q35,confidential-guest-support=sev0 \ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,secure-tsc=on Reviewed-by: Tom Lendacky Co-developed-by: Ketan Chaturvedi Signed-off-by: Ketan Chaturvedi Co-developed-by: Nikunj A Dadhania Signed-off-by: Nikunj A Dadhania Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/9f58b92a173f319b3ef725f5ed8a2a173eed55b1.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- qapi/qom.json | 6 +++++- target/i386/sev.c | 13 +++++++++++++ target/i386/sev.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index ad7e39aa75..4732fa8975 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1113,6 +1113,9 @@ # firmware. Set this to true to disable the use of VCEK. # (default: false) (since: 9.1) # +# @secure-tsc: enable Secure TSC +# (default: false) (since 11.1) +# # Since: 9.1 ## { 'struct': 'SevSnpGuestProperties', @@ -1124,7 +1127,8 @@ '*id-auth': 'str', '*author-key-enabled': 'bool', '*host-data': 'str', - '*vcek-disabled': 'bool' } } + '*vcek-disabled': 'bool', + '*secure-tsc': 'bool' } } ## # @TdxGuestProperties: diff --git a/target/i386/sev.c b/target/i386/sev.c index 2103a121aa..fdfeb604f6 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -3212,6 +3212,16 @@ sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp) memcpy(finish->host_data, blob, len); } +static bool sev_snp_guest_get_secure_tsc(Object *obj, Error **errp) +{ + return is_sev_feature_set(SEV_COMMON(obj), SVM_SEV_FEAT_SECURE_TSC); +} + +static void sev_snp_guest_set_secure_tsc(Object *obj, bool value, Error **errp) +{ + sev_set_feature(SEV_COMMON(obj), SVM_SEV_FEAT_SECURE_TSC, value); +} + static void sev_snp_guest_class_init(ObjectClass *oc, const void *data) { @@ -3247,6 +3257,9 @@ sev_snp_guest_class_init(ObjectClass *oc, const void *data) object_class_property_add_str(oc, "host-data", sev_snp_guest_get_host_data, sev_snp_guest_set_host_data); + object_class_property_add_bool(oc, "secure-tsc", + sev_snp_guest_get_secure_tsc, + sev_snp_guest_set_secure_tsc); } static void diff --git a/target/i386/sev.h b/target/i386/sev.h index d19a396697..7725f92e19 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -48,6 +48,7 @@ bool sev_snp_enabled(void); #define SVM_SEV_FEAT_SNP_ACTIVE BIT(0) #define SVM_SEV_FEAT_DEBUG_SWAP BIT(5) +#define SVM_SEV_FEAT_SECURE_TSC BIT(9) typedef struct SevKernelLoaderContext { char *setup_data; From f79c89c296896d97f5c6dc4f1635dbbe897bfdbc Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:58:01 +0530 Subject: [PATCH 342/627] target/i386: SEV: Add support for setting TSC frequency for Secure TSC Add support for configuring the TSC frequency when Secure TSC is enabled in SEV-SNP guests through a new "tsc-frequency" property on SEV-SNP guest objects, similar to the vCPU-specific property used by regular guests and TDX. A new property is needed since SEV-SNP guests require the TSC frequency to be specified during early SNP_LAUNCH_START command before any vCPUs are created. The user-provided TSC frequency is set through KVM_SET_TSC_KHZ before issuing KVM_SEV_SNP_LAUNCH_START. Attempts to set TSC frequency on both the SEV_SNP object and the cpu object result in an error from KVM (on the vCPU ioctl), so do not add separate checks for the same. Sample command-line: -machine q35,confidential-guest-support=sev0 \ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,secure-tsc=on,tsc-frequency=2500000000 Co-developed-by: Ketan Chaturvedi Signed-off-by: Ketan Chaturvedi Co-developed-by: Nikunj A Dadhania Signed-off-by: Nikunj A Dadhania Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/af688610978f213a456a7753e1d9fe7d3a51e80a.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- qapi/qom.json | 6 +++++- target/i386/sev.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index 4732fa8975..4a9b7f9088 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1116,6 +1116,9 @@ # @secure-tsc: enable Secure TSC # (default: false) (since 11.1) # +# @tsc-frequency: set secure TSC frequency. Only valid if Secure TSC +# is enabled (default: zero) (since 11.1) +# # Since: 9.1 ## { 'struct': 'SevSnpGuestProperties', @@ -1128,7 +1131,8 @@ '*author-key-enabled': 'bool', '*host-data': 'str', '*vcek-disabled': 'bool', - '*secure-tsc': 'bool' } } + '*secure-tsc': 'bool', + '*tsc-frequency': 'uint32' } } ## # @TdxGuestProperties: diff --git a/target/i386/sev.c b/target/i386/sev.c index fdfeb604f6..ae9c85af13 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -183,6 +183,7 @@ struct SevSnpGuestState { char *id_auth_base64; uint8_t *id_auth; char *host_data; + uint32_t tsc_khz; struct kvm_sev_snp_launch_start kvm_start_conf; struct kvm_sev_snp_launch_finish kvm_finish_conf; @@ -547,6 +548,13 @@ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, __func__, sev_features, sev_common->supported_sev_features); return -1; } + if (sev_snp_enabled() && SEV_SNP_GUEST(sev_common)->tsc_khz && + !(sev_features & SVM_SEV_FEAT_SECURE_TSC)) { + error_setg(errp, + "%s: TSC frequency can only be set if Secure TSC is enabled", + __func__); + return -1; + } return 0; } @@ -1095,6 +1103,19 @@ sev_snp_launch_start(SevCommonState *sev_common) return 1; } + if (is_sev_feature_set(sev_common, SVM_SEV_FEAT_SECURE_TSC) && + sev_snp_guest->tsc_khz) { + rc = -EINVAL; + if (kvm_check_extension(kvm_state, KVM_CAP_VM_TSC_CONTROL)) { + rc = kvm_vm_ioctl(kvm_state, KVM_SET_TSC_KHZ, sev_snp_guest->tsc_khz); + } + if (rc < 0) { + error_report("%s: Unable to set Secure TSC frequency to %u kHz ret=%d", + __func__, sev_snp_guest->tsc_khz, rc); + return 1; + } + } + rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START, start, &fw_error); if (rc < 0) { @@ -3222,6 +3243,28 @@ static void sev_snp_guest_set_secure_tsc(Object *obj, bool value, Error **errp) sev_set_feature(SEV_COMMON(obj), SVM_SEV_FEAT_SECURE_TSC, value); } +static void +sev_snp_guest_get_tsc_frequency(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value = SEV_SNP_GUEST(obj)->tsc_khz * 1000; + + visit_type_uint32(v, name, &value, errp); +} + +static void +sev_snp_guest_set_tsc_frequency(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + SEV_SNP_GUEST(obj)->tsc_khz = value / 1000; +} + static void sev_snp_guest_class_init(ObjectClass *oc, const void *data) { @@ -3260,6 +3303,9 @@ sev_snp_guest_class_init(ObjectClass *oc, const void *data) object_class_property_add_bool(oc, "secure-tsc", sev_snp_guest_get_secure_tsc, sev_snp_guest_set_secure_tsc); + object_class_property_add(oc, "tsc-frequency", "uint32", + sev_snp_guest_get_tsc_frequency, + sev_snp_guest_set_tsc_frequency, NULL, NULL); } static void From feed8bdfdc1a292fa2b6fe993cb5a9e8f2190e1f Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Wed, 20 May 2026 18:58:02 +0530 Subject: [PATCH 343/627] target/i386: SEV: Refactor check_sev_features() Refactor check_sev_features() to consolidate SEV-SNP checks to a single if block. This is also helpful when adding checks for future SEV features. While at it, move the comment about the checks being done outside of the function body and expand it to describe what this function does. Update error_setg() invocations to use a consistent format. No functional change intended. Suggested-by: Tom Lendacky Signed-off-by: Naveen N Rao (AMD) Link: https://lore.kernel.org/r/cae04d88adfbcdc2997e518475f3b89091adf8a9.1779281646.git.naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 67 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index ae9c85af13..8acbb01da2 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -507,40 +507,22 @@ static void sev_apply_cpu_context(CPUState *cpu) } } +/* + * Ensure SEV_FEATURES is configured for correct SEV hardware and that + * the requested features are supported. In addition, ensure feature + * dependencies are satisfied (allow tsc-frequency only if secure-tsc + * is also enabled, as an example). + */ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, Error **errp) { - /* - * Ensure SEV_FEATURES is configured for correct SEV hardware and that - * the requested features are supported. If SEV-SNP is enabled then - * that feature must be enabled, otherwise it must be cleared. - */ - if (sev_snp_enabled() && !(sev_features & SVM_SEV_FEAT_SNP_ACTIVE)) { - error_setg( - errp, - "%s: SEV_SNP is enabled but is not enabled in VMSA sev_features", - __func__); - return -1; - } else if (!sev_snp_enabled() && - (sev_features & SVM_SEV_FEAT_SNP_ACTIVE)) { - error_setg( - errp, - "%s: SEV_SNP is not enabled but is enabled in VMSA sev_features", - __func__); - return -1; - } - if (sev_features && sev_es_enabled() && !sev_snp_enabled()) { - error_setg(errp, - "%s: SEV features are not supported with SEV-ES at this time", - __func__); - return -1; - } if (sev_features && !sev_es_enabled()) { error_setg(errp, "%s: SEV features require either SEV-ES or SEV-SNP to be enabled", __func__); return -1; } + if (sev_features & ~sev_common->supported_sev_features) { error_setg(errp, "%s: VMSA contains unsupported sev_features: %lX, " @@ -548,13 +530,36 @@ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, __func__, sev_features, sev_common->supported_sev_features); return -1; } - if (sev_snp_enabled() && SEV_SNP_GUEST(sev_common)->tsc_khz && - !(sev_features & SVM_SEV_FEAT_SECURE_TSC)) { - error_setg(errp, - "%s: TSC frequency can only be set if Secure TSC is enabled", - __func__); - return -1; + + if (sev_snp_enabled()) { + if (!(sev_features & SVM_SEV_FEAT_SNP_ACTIVE)) { + error_setg(errp, + "%s: SEV_SNP is enabled but is not enabled in VMSA sev_features", + __func__); + return -1; + } + if (SEV_SNP_GUEST(sev_common)->tsc_khz && + !(sev_features & SVM_SEV_FEAT_SECURE_TSC)) { + error_setg(errp, + "%s: TSC frequency can only be set if Secure TSC is enabled", + __func__); + return -1; + } + } else { + if (sev_features && sev_es_enabled()) { + error_setg(errp, + "%s: SEV features are not supported with SEV-ES at this time", + __func__); + return -1; + } + if (sev_features & SVM_SEV_FEAT_SNP_ACTIVE) { + error_setg(errp, + "%s: SEV_SNP is not enabled but is enabled in VMSA sev_features", + __func__); + return -1; + } } + return 0; } From 5be66f90bdf180d70a3f5d4ab2de399b5190a851 Mon Sep 17 00:00:00 2001 From: "Naveen N Rao (AMD)" Date: Fri, 26 Jun 2026 12:30:10 +0530 Subject: [PATCH 344/627] target/i386: SEV: Remove use of __func__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove all usages of __func__ in target/i386/sev.c to align with the general QEMU preference, and replace those with "SEV:" prefix. Suggested-by: Daniel P. Berrangé Signed-off-by: Naveen N Rao (AMD) Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20260626070010.1955433-1-naveen@kernel.org Signed-off-by: Paolo Bonzini --- target/i386/sev.c | 155 +++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/target/i386/sev.c b/target/i386/sev.c index 8acbb01da2..4d875d10ff 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -363,8 +363,8 @@ sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, trace_kvm_memcrypt_register_region(host, max_size); r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range); if (r) { - error_report("%s: failed to register region (%p+%#zx) error '%s'", - __func__, host, max_size, strerror(errno)); + error_report("SEV: Failed to register region (%p+%#zx) error '%s'", + host, max_size, strerror(errno)); exit(1); } } @@ -393,8 +393,8 @@ sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, trace_kvm_memcrypt_unregister_region(host, max_size); r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range); if (r) { - error_report("%s: failed to unregister region (%p+%#zx)", - __func__, host, max_size); + error_report("SEV: Failed to unregister region (%p+%#zx)", + host, max_size); } } @@ -518,44 +518,39 @@ static int check_sev_features(SevCommonState *sev_common, uint64_t sev_features, { if (sev_features && !sev_es_enabled()) { error_setg(errp, - "%s: SEV features require either SEV-ES or SEV-SNP to be enabled", - __func__); + "SEV: SEV features require either SEV-ES or SEV-SNP to be enabled"); return -1; } if (sev_features & ~sev_common->supported_sev_features) { error_setg(errp, - "%s: VMSA contains unsupported sev_features: %lX, " + "SEV: VMSA contains unsupported sev_features: %lX, " "supported features: %lX", - __func__, sev_features, sev_common->supported_sev_features); + sev_features, sev_common->supported_sev_features); return -1; } if (sev_snp_enabled()) { if (!(sev_features & SVM_SEV_FEAT_SNP_ACTIVE)) { error_setg(errp, - "%s: SEV_SNP is enabled but is not enabled in VMSA sev_features", - __func__); + "SEV: SEV_SNP is enabled but is not enabled in VMSA sev_features"); return -1; } if (SEV_SNP_GUEST(sev_common)->tsc_khz && !(sev_features & SVM_SEV_FEAT_SECURE_TSC)) { error_setg(errp, - "%s: TSC frequency can only be set if Secure TSC is enabled", - __func__); + "SEV: TSC frequency can only be set if Secure TSC is enabled"); return -1; } } else { if (sev_features && sev_es_enabled()) { error_setg(errp, - "%s: SEV features are not supported with SEV-ES at this time", - __func__); + "SEV: SEV features are not supported with SEV-ES at this time"); return -1; } if (sev_features & SVM_SEV_FEAT_SNP_ACTIVE) { error_setg(errp, - "%s: SEV_SNP is not enabled but is enabled in VMSA sev_features", - __func__); + "SEV: SEV_SNP is not enabled but is enabled in VMSA sev_features"); return -1; } } @@ -578,8 +573,8 @@ static int check_vmsa_supported(SevCommonState *sev_common, hwaddr gpa, */ if (gpa != KVM_VMSA_GPA) { error_setg(errp, - "%s: The VMSA GPA must be %lX but is specified as %lX", - __func__, KVM_VMSA_GPA, gpa); + "SEV: The VMSA GPA must be %lX but is specified as %lX", + KVM_VMSA_GPA, gpa); return -1; } @@ -634,11 +629,10 @@ static int check_vmsa_supported(SevCommonState *sev_common, hwaddr gpa, if (!buffer_is_zero(&vmsa_check, sizeof(vmsa_check))) { error_setg(errp, - "%s: The VMSA contains fields that are not " + "SEV: The VMSA contains fields that are not " "synchronized with KVM. Continuing would result in " "either unpredictable guest behavior, or a " - "mismatched launch measurement.", - __func__); + "mismatched launch measurement."); return -1; } return 0; @@ -1115,8 +1109,8 @@ sev_snp_launch_start(SevCommonState *sev_common) rc = kvm_vm_ioctl(kvm_state, KVM_SET_TSC_KHZ, sev_snp_guest->tsc_khz); } if (rc < 0) { - error_report("%s: Unable to set Secure TSC frequency to %u kHz ret=%d", - __func__, sev_snp_guest->tsc_khz, rc); + error_report("SEV: Unable to set Secure TSC frequency to %u kHz ret=%d", + sev_snp_guest->tsc_khz, rc); return 1; } } @@ -1124,8 +1118,8 @@ sev_snp_launch_start(SevCommonState *sev_common) rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_SNP_LAUNCH_START, start, &fw_error); if (rc < 0) { - error_report("%s: SNP_LAUNCH_START ret=%d fw_error=%d '%s'", - __func__, rc, fw_error, fw_error_to_str(fw_error)); + error_report("SEV: SNP_LAUNCH_START ret=%d fw_error=%d '%s'", + rc, fw_error, fw_error_to_str(fw_error)); return 1; } @@ -1167,8 +1161,8 @@ sev_launch_start(SevCommonState *sev_common) trace_kvm_sev_launch_start(start.policy, session, dh_cert); rc = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_START, &start, &fw_error); if (rc < 0) { - error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'", - __func__, ret, fw_error, fw_error_to_str(fw_error)); + error_report("SEV: LAUNCH_START ret=%d fw_error=%d '%s'", + ret, fw_error, fw_error_to_str(fw_error)); goto out; } @@ -1341,7 +1335,7 @@ static int sev_launch_update_data(SevCommonState *sev_common, hwaddr gpa, ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA, &update, &fw_error); if (ret) { - error_setg(errp, "%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'", __func__, + error_setg(errp, "SEV: LAUNCH_UPDATE ret=%d fw_error=%d '%s'", ret, fw_error, fw_error_to_str(fw_error)); } @@ -1366,8 +1360,8 @@ sev_launch_update_vmsa(SevGuestState *sev_guest) ret = sev_ioctl(SEV_COMMON(sev_guest)->sev_fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL, &fw_error); if (ret) { - error_report("%s: LAUNCH_UPDATE_VMSA ret=%d fw_error=%d '%s'", - __func__, ret, fw_error, fw_error_to_str(fw_error)); + error_report("SEV: LAUNCH_UPDATE_VMSA ret=%d fw_error=%d '%s'", + ret, fw_error, fw_error_to_str(fw_error)); } return ret; @@ -1399,8 +1393,8 @@ sev_launch_get_measure(Notifier *notifier, void *unused) ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE, &measurement, &error); if (!measurement.len) { - error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", - __func__, ret, error, fw_error_to_str(errno)); + error_report("SEV: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", + ret, error, fw_error_to_str(errno)); return; } @@ -1411,8 +1405,8 @@ sev_launch_get_measure(Notifier *notifier, void *unused) ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_MEASURE, &measurement, &error); if (ret) { - error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", - __func__, ret, error, fw_error_to_str(errno)); + error_report("SEV: LAUNCH_MEASURE ret=%d fw_error=%d '%s'", + ret, error, fw_error_to_str(errno)); return; } @@ -1467,8 +1461,8 @@ sev_launch_finish(SevCommonState *sev_common) ret = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error); if (ret) { - error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'", - __func__, ret, error, fw_error_to_str(error)); + error_report("SEV: LAUNCH_FINISH ret=%d fw_error=%d '%s'", + ret, error, fw_error_to_str(error)); exit(1); } @@ -1627,8 +1621,8 @@ snp_populate_metadata_pages(SevSnpGuestState *sev_snp, hva = gpa2hva(&mr, desc->base, desc->len, NULL); if (!hva) { - error_report("%s: Failed to get HVA for GPA 0x%x sz 0x%x", - __func__, desc->base, desc->len); + error_report("SEV: Failed to get HVA for GPA 0x%x sz 0x%x", + desc->base, desc->len); exit(1); } @@ -1644,8 +1638,8 @@ snp_populate_metadata_pages(SevSnpGuestState *sev_snp, } if (ret) { - error_report("%s: Failed to add metadata page gpa 0x%x+%x type %d", - __func__, desc->base, desc->len, desc->type); + error_report("SEV: Failed to add metadata page gpa 0x%x+%x type %d", + desc->base, desc->len, desc->type); exit(1); } } @@ -1674,7 +1668,7 @@ sev_snp_launch_finish(SevCommonState *sev_common) */ metadata = pc_system_get_ovmf_sev_metadata_ptr(); if (metadata == NULL) { - error_report("%s: Failed to locate SEV metadata header", __func__); + error_report("SEV: SNP_LAUNCH_FINISH failed to locate SEV metadata header"); exit(1); } @@ -1812,8 +1806,7 @@ static int sev_init_supported_features(ConfidentialGuestSupport *cgs, .addr = (unsigned long)&sev_common->supported_sev_features, }; if (kvm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr) < 0) { - error_setg(errp, "%s: failed to query supported sev_features", - __func__); + error_setg(errp, "SEV: failed to query supported sev_features"); return -1; } if (sev_snp_enabled()) { @@ -1851,8 +1844,8 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) * comparison against the host value accomplishes that. */ if (host_cbitpos != sev_common->cbitpos) { - error_setg(errp, "%s: cbitpos check failed, host '%d' requested '%d'", - __func__, host_cbitpos, sev_common->cbitpos); + error_setg(errp, "SEV: cbitpos check failed, host '%d' requested '%d'", + host_cbitpos, sev_common->cbitpos); return -1; } @@ -1863,9 +1856,9 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) */ if (sev_common->reduced_phys_bits < 1 || sev_common->reduced_phys_bits > 63) { - error_setg(errp, "%s: reduced_phys_bits check failed," + error_setg(errp, "SEV: reduced_phys_bits check failed," " it should be in the range of 1 to 63, requested '%d'", - __func__, sev_common->reduced_phys_bits); + sev_common->reduced_phys_bits); return -1; } @@ -1881,8 +1874,8 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) ret = sev_platform_ioctl(sev_common->sev_fd, SEV_PLATFORM_STATUS, &status, &fw_error); if (ret) { - error_setg(errp, "%s: failed to get platform status ret=%d " - "fw_error='%d: %s'", __func__, ret, fw_error, + error_setg(errp, "SEV: failed to get platform status ret=%d " + "fw_error='%d: %s'", ret, fw_error, fw_error_to_str(fw_error)); return -1; } @@ -1892,17 +1885,15 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) if (sev_es_enabled()) { if (!kvm_kernel_irqchip_allowed()) { - error_setg(errp, "%s: SEV-ES guests require in-kernel irqchip" - "support", __func__); + error_setg(errp, "SEV: SEV-ES guests require in-kernel irqchip support"); return -1; } } if (sev_es_enabled() && !sev_snp_enabled()) { if (!(status.flags & SEV_STATUS_FLAGS_CONFIG_ES)) { - error_setg(errp, "%s: guest policy requires SEV-ES, but " - "host SEV-ES support unavailable", - __func__); + error_setg(errp, "SEV: guest policy requires SEV-ES, but " + "host SEV-ES support unavailable"); return -1; } } @@ -1949,8 +1940,7 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) */ if (sev_common->sev_features & ~SVM_SEV_FEAT_SNP_ACTIVE) { error_setg(errp, - "%s: SEV features can't be specified when using IGVM files", - __func__); + "SEV: SEV features can't be specified when using IGVM files"); return -1; } if (IGVM_CFG_GET_CLASS(x86machine->igvm) @@ -1974,21 +1964,20 @@ static int sev_common_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) break; } default: - error_setg(errp, "%s: host kernel does not support the requested SEV configuration.", - __func__); + error_setg(errp, "SEV: host kernel does not support the requested SEV configuration."); return -1; } if (ret) { - error_setg(errp, "%s: failed to initialize ret=%d fw_error=%d '%s'", - __func__, ret, fw_error, fw_error_to_str(fw_error)); + error_setg(errp, "SEV: failed to initialize ret=%d fw_error=%d '%s'", + ret, fw_error, fw_error_to_str(fw_error)); return -1; } ret = klass->launch_start(sev_common); if (ret) { - error_setg(errp, "%s: failed to create encryption context", __func__); + error_setg(errp, "SEV: failed to create encryption context"); return -1; } @@ -2016,7 +2005,7 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) */ ret = ram_block_discard_disable(true); if (ret) { - error_setg(errp, "%s: cannot disable RAM discard", __func__); + error_setg(errp, "SEV: cannot disable RAM discard"); return -1; } @@ -2620,8 +2609,7 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, const struct sev_es_save_area *sa = (const struct sev_es_save_area *)ptr; if (len < sizeof(*sa)) { - error_setg(errp, "%s: invalid VMSA length encountered", - __func__); + error_setg(errp, "SEV: invalid VMSA length encountered"); return -1; } sev_common->sev_features = sa->sev_features; @@ -2630,8 +2618,8 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, } if (!sev_enabled()) { - error_setg(errp, "%s: attempt to configure guest memory, but SEV " - "is not enabled", __func__); + error_setg(errp, "SEV: attempt to configure guest memory, but SEV " + "is not enabled"); return -1; } @@ -2643,9 +2631,8 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, case CGS_PAGE_TYPE_VMSA: if (!sev_es_enabled()) { error_setg(errp, - "%s: attempt to configure initial VMSA, but SEV-ES " - "is not supported", - __func__); + "SEV: attempt to configure initial VMSA, but SEV-ES " + "is not supported"); return -1; } if (check_vmsa_supported(sev_common, gpa, @@ -2666,9 +2653,8 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, case CGS_PAGE_TYPE_SECRETS: if (!sev_snp_enabled()) { error_setg(errp, - "%s: attempt to configure secrets page, but SEV-SNP " - "is not supported", - __func__); + "SEV: attempt to configure secrets page, but SEV-SNP " + "is not supported"); return -1; } return snp_launch_update_data(gpa, ptr, len, @@ -2678,8 +2664,8 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, if (kvm_convert_memory(gpa, len, true) < 0) { error_setg( errp, - "%s: failed to configure required memory. gpa: %lX, type: %d", - __func__, gpa, memory_type); + "SEV: failed to configure required memory. gpa: %lX, type: %d", + gpa, memory_type); return -1; } return 0; @@ -2687,14 +2673,13 @@ static int cgs_set_guest_state(hwaddr gpa, uint8_t *ptr, uint64_t len, case CGS_PAGE_TYPE_CPUID: if (!sev_snp_enabled()) { error_setg(errp, - "%s: attempt to configure CPUID page, but SEV-SNP " - "is not supported", - __func__); + "SEV: attempt to configure CPUID page, but SEV-SNP " + "is not supported"); return -1; } return snp_launch_update_cpuid(gpa, ptr, len, errp); } - error_setg(errp, "%s: failed to update guest. gpa: %lX, type: %d", __func__, + error_setg(errp, "SEV: failed to update guest. gpa: %lX, type: %d", gpa, memory_type); return -1; } @@ -2750,8 +2735,8 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type, } if (policy_type != GUEST_POLICY_SEV) { - error_setg(errp, "%s: Invalid guest policy type provided for SEV: %d", - __func__, policy_type); + error_setg(errp, "SEV: Invalid guest policy type provided for SEV: %d", + policy_type); return -1; } /* @@ -2784,14 +2769,12 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type, (struct sev_snp_id_authentication *)policy_data2; if (policy_data1_size != KVM_SEV_SNP_ID_BLOCK_SIZE) { - error_setg(errp, "%s: Invalid SEV-SNP ID block: incorrect size", - __func__); + error_setg(errp, "SEV: Invalid SEV-SNP ID block: incorrect size"); return -1; } if (policy_data2_size != KVM_SEV_SNP_ID_AUTH_SIZE) { error_setg(errp, - "%s: Invalid SEV-SNP ID auth block: incorrect size", - __func__); + "SEV: Invalid SEV-SNP ID auth block: incorrect size"); return -1; } assert(policy_data1 != NULL); @@ -2821,8 +2804,8 @@ static int cgs_set_guest_policy(ConfidentialGuestPolicyType policy_type, SevGuestState *sev_guest = SEV_GUEST(MACHINE(qdev_get_machine())->cgs); /* Only the policy flags are supported for SEV and SEV-ES */ if ((policy_data1_size > 0) || (policy_data2_size > 0) || !sev_guest) { - error_setg(errp, "%s: An ID block/ID auth block has been provided " - "but SEV-SNP is not enabled", __func__); + error_setg(errp, "SEV: An ID block/ID auth block has been provided " + "but SEV-SNP is not enabled"); return -1; } From 2667133c2799f670366b94059cc0513ae57fe8cb Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 23 Jun 2026 17:24:05 +0200 Subject: [PATCH 345/627] job: keep job paused across overlapping pause requests job_pause_point_locked() sets job->paused before yielding and clears it unconditionally on wake, before re-checking whether a pause is still pending. job_pause() re-enters a parked job only while it is not yet paused, so the wake that resumes one comes from a drain *ending* (job_resume() -> job_enter_cond()). If the next drain begins before that wake runs, the woken coroutine clears job->paused while pause_count is already > 0 again: AioContext change (BQL thread) job coroutine (iothread) ----------------------------- ------------------------ parked in job_pause_point(): paused=1, pause_count=1, yielded drain ends -> job_resume(): pause_count = 0 job_enter_cond(): queue wake ..> (wake pending) bdrv_try_change_aio_context(): bdrv_drain_all_begin(): job_pause() per node pause_count = N (> 0) wake runs, leaves job_do_yield(): paused = 0 (pause_count == N) tran_commit -> job_set_aio_context(): assert(paused || completed) --> abort: paused == 0 bdrv_try_change_aio_context() drains precisely to quiesce the job before changing its AioContext, but that brief paused==0 window trips the assertion. It is guest-triggerable: a virtio-blk reset (virtio_blk_stop_ioeventfd() -> blk_set_aio_context()) racing a running mirror/blockCopy job hits it, as do x-blockdev-set-iothread, blockdev hot-plug/unplug and job completion. Keep job->paused set while a pause is still pending: loop the yield until job_should_pause_locked() is false (or the job is cancelled), and only then clear job->paused. Drained-state consumers then never observe a pending-pause job as unpaused. Signed-off-by: Denis V. Lunev Message-ID: <20260623152406.1180235-2-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- job.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/job.c b/job.c index e747908472..d7220aaf30 100644 --- a/job.c +++ b/job.c @@ -629,7 +629,14 @@ static void coroutine_fn job_pause_point_locked(Job *job) ? JOB_STATUS_STANDBY : JOB_STATUS_PAUSED); job->paused = true; - job_do_yield_locked(job, -1); + /* + * Stay paused across back-to-back pause requests: a transient + * paused == false while pause_count > 0 would be observed as + * "not paused" by job_set_aio_context() and other drain consumers. + */ + do { + job_do_yield_locked(job, -1); + } while (job_should_pause_locked(job) && !job_is_cancelled_locked(job)); job->paused = false; job_state_transition_locked(job, status); } From 438ee08bc97af48ade6365133f2f5b43d4d788ae Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 23 Jun 2026 17:24:06 +0200 Subject: [PATCH 346/627] tests/unit/test-blockjob: cover keeping a job paused while a pause is pending Add a regression test for the previous commit. A job that has reached its pause point is spuriously re-entered (job_enter()) while a pause is still pending (pause_count > 0), reproducing what an overlapping drain does: one drain's job_resume() wakes the job while the next drain's job_pause() is already counted. The job must stay parked - it must not run job code or clear job->paused, or job_set_aio_context() could observe paused == false and abort. The test counts the job's run-loop iterations: without the fix the re-entered job clears job->paused, runs one iteration and re-pauses, so the counter advances; with the fix it stays parked and the counter is unchanged. It runs in the main AioContext, so job_enter() is synchronous and the check is deterministic. Signed-off-by: Denis V. Lunev Message-ID: <20260623152406.1180235-3-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- tests/unit/test-blockjob.c | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/unit/test-blockjob.c b/tests/unit/test-blockjob.c index abdbe4b835..3b77d19b91 100644 --- a/tests/unit/test-blockjob.c +++ b/tests/unit/test-blockjob.c @@ -388,6 +388,105 @@ static void test_cancel_concluded(void) cancel_common(s); } +typedef struct PauseCountJob { + BlockJob common; + int n; + bool should_complete; +} PauseCountJob; + +static void pause_count_job_complete(Job *job, Error **errp) +{ + PauseCountJob *s = container_of(job, PauseCountJob, common.job); + s->should_complete = true; +} + +static int coroutine_fn pause_count_job_run(Job *job, Error **errp) +{ + PauseCountJob *s = container_of(job, PauseCountJob, common.job); + + while (!s->should_complete) { + if (job_is_cancelled(&s->common.job)) { + return 0; + } + s->n++; + /* + * Yields; while a pause is pending the yield is skipped and the job + * parks in job_pause_point() instead. + */ + job_sleep_ns(&s->common.job, 10 * 1000 * 1000); + } + + return 0; +} + +static const BlockJobDriver pause_count_job_driver = { + .job_driver = { + .instance_size = sizeof(PauseCountJob), + .free = block_job_free, + .user_resume = block_job_user_resume, + .run = pause_count_job_run, + .complete = pause_count_job_complete, + }, +}; + +/* + * A job that has reached its pause point must stay paused while a pause is + * still pending (pause_count > 0). An overlapping drain re-enters the job (one + * drain's job_resume() wakes it while the next drain's job_pause() is already + * counted); the job must not run or clear job->paused, otherwise + * job_set_aio_context() can observe paused == false and abort. + */ +static void test_pause_keeps_paused(void) +{ + BlockBackend *blk; + BlockJob *bjob; + PauseCountJob *s; + Job *job; + int n0; + + blk = create_blk(NULL); + bjob = mk_job(blk, "job0", &pause_count_job_driver, true, + JOB_MANUAL_FINALIZE | JOB_MANUAL_DISMISS); + s = container_of(bjob, PauseCountJob, common); + job = &bjob->job; + WITH_JOB_LOCK_GUARD() { + job_ref_locked(job); + } + + job_start(job); + + /* Pause the running job; it parks in job_pause_point() with paused set. */ + WITH_JOB_LOCK_GUARD() { + job_pause_locked(job); + g_assert_true(job->paused); + g_assert_cmpint(job->status, ==, JOB_STATUS_PAUSED); + } + n0 = s->n; + + /* + * Spurious wake while the pause is still pending. The job must stay parked: + * the bug clears job->paused, runs an iteration (s->n advances) and + * re-pauses, exposing a paused == false window. + */ + job_enter(job); + WITH_JOB_LOCK_GUARD() { + g_assert_true(job->paused); + } + g_assert_cmpint(s->n, ==, n0); + + /* Resume and tear down. */ + WITH_JOB_LOCK_GUARD() { + job_resume_locked(job); + } + job_cancel_sync(job, true); + WITH_JOB_LOCK_GUARD() { + Job *dummy = job; + job_dismiss_locked(&dummy, &error_abort); + job_unref_locked(job); + } + destroy_blk(blk); +} + int main(int argc, char **argv) { qemu_init_main_loop(&error_abort); @@ -402,5 +501,6 @@ int main(int argc, char **argv) g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); + g_test_add_func("/blockjob/pause/keep_paused", test_pause_keeps_paused); return g_test_run(); } From 59ecd8a1ac3f05f572155a2d7a81fbeec397e2d3 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 16 Jul 2026 13:22:40 +0200 Subject: [PATCH 347/627] block/monitor: reject persistent bitmap add on a read-only node qmp_block_dirty_bitmap_add() marks a new bitmap persistent without checking write access to its node. bdrv_create_dirty_bitmap() always creates bitmaps writable, so a persistent bitmap added to an already read-only node stays writable in memory on a node that can never store it, and the next global inactivation fails: Lost persistent bitmaps during inactivation of node '': No write access migration_block_inactivate: bdrv_inactivate_all() failed: -22 Forcing it read-only instead does not help: it was never stored, so it stays unpromotable on the next reopen to read-write and can trip bdrv_set_dirty()'s readonly assert on the first write. Reject the add instead, for both read-only and inactive nodes -- an already-inactive node skips qcow2_inactivate() on close, so a bitmap added during that window would never get stored either. Wrapped in a transaction, this denies the whole transaction, since qmp_transaction() is already all-or-none. Signed-off-by: Denis V. Lunev CC: Eric Blake CC: Vladimir Sementsov-Ogievskiy CC: John Snow CC: Andrey Drobyshev Message-ID: <20260716112242.3000035-2-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/monitor/bitmap-qmp-cmds.c | 15 +++++++--- qapi/block-core.json | 4 ++- .../tests/remove-bitmap-from-backing | 29 ++++++++++++++++++- .../tests/remove-bitmap-from-backing.out | 20 +++++++++++++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c index a738e7bbf7..d87ca982aa 100644 --- a/block/monitor/bitmap-qmp-cmds.c +++ b/block/monitor/bitmap-qmp-cmds.c @@ -125,10 +125,17 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, disabled = false; } - if (persistent && - !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) - { - return; + if (persistent) { + if (!bdrv_is_writable(bs)) { + error_setg(errp, "Cannot add a persistent bitmap to " + "read-only or inactive node '%s'", + bdrv_get_node_name(bs)); + return; + } + + if (!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) { + return; + } } bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); diff --git a/qapi/block-core.json b/qapi/block-core.json index 1f87b07850..199efc1e00 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2353,7 +2353,9 @@ # @persistent: the bitmap is persistent, i.e. it will be saved to the # corresponding block device image file on its close. For now # only Qcow2 disks support persistent bitmaps. Default is false -# for `block-dirty-bitmap-add`. (Since: 2.10) +# for `block-dirty-bitmap-add`. This fails if the node is +# read-only or inactive, since such a bitmap could never be +# stored. (Since: 2.10) # # @disabled: the bitmap is created in the disabled state, which means # that it will not track drive changes. The bitmap may be enabled diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing index 15be32dcb9..a54984fa58 100755 --- a/tests/qemu-iotests/tests/remove-bitmap-from-backing +++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing @@ -35,7 +35,7 @@ qemu_img('bitmap', '--add', base, 'bitmap0') # Just assert that our method of checking bitmaps in the image works. assert 'bitmaps' in qemu_img_info(base)['format-specific']['data'] -vm = iotests.VM().add_drive(top, 'backing.node-name=base') +vm = iotests.VM().add_drive(top, 'node-name=top,backing.node-name=base') vm.launch() log('Trying to remove persistent bitmap from r-o base node, should fail:') @@ -66,6 +66,33 @@ result = vm.qmp('blockdev-reopen', **new_base_opts) if result != {'return': {}}: log('Failed to reopen: ' + str(result)) +log('Adding a persistent bitmap to the r-o base node, should fail:') +vm.qmp_log('block-dirty-bitmap-add', node='base', name='bitmap1', + persistent=True) + +log('Same add inside a transaction, preceded by an otherwise valid') +log('action: the whole transaction must fail and roll back the') +log('already-succeeded first action too:') +vm.qmp_log('transaction', actions=[ + {'type': 'block-dirty-bitmap-add', + 'data': {'node': 'top', 'name': 'bitmap2', 'persistent': True}}, + {'type': 'block-dirty-bitmap-add', + 'data': {'node': 'base', 'name': 'bitmap1', 'persistent': True}}, +]) + +log('bitmap2 on the rw top node must not have survived the rollback:') +vm.qmp_log('block-dirty-bitmap-remove', node='top', name='bitmap2') + +log('Marking the rw top node inactive:') +vm.qmp_log('blockdev-set-active', **{'node-name': 'top', 'active': False}) + +log('Adding a persistent bitmap to a rw but inactive node, should fail:') +vm.qmp_log('block-dirty-bitmap-add', node='top', name='bitmap3', + persistent=True) + +log('Reactivating the top node:') +vm.qmp_log('blockdev-set-active', **{'node-name': 'top', 'active': True}) + vm.shutdown() if 'bitmaps' in qemu_img_info(base)['format-specific']['data']: diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing.out b/tests/qemu-iotests/tests/remove-bitmap-from-backing.out index c28af82c75..fe105fe0a3 100644 --- a/tests/qemu-iotests/tests/remove-bitmap-from-backing.out +++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing.out @@ -4,3 +4,23 @@ Trying to remove persistent bitmap from r-o base node, should fail: Remove persistent bitmap from base node reopened to RW: {"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "base"}} {"return": {}} +Adding a persistent bitmap to the r-o base node, should fail: +{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap1", "node": "base", "persistent": true}} +{"error": {"class": "GenericError", "desc": "Cannot add a persistent bitmap to read-only or inactive node 'base'"}} +Same add inside a transaction, preceded by an otherwise valid +action: the whole transaction must fail and roll back the +already-succeeded first action too: +{"execute": "transaction", "arguments": {"actions": [{"data": {"name": "bitmap2", "node": "top", "persistent": true}, "type": "block-dirty-bitmap-add"}, {"data": {"name": "bitmap1", "node": "base", "persistent": true}, "type": "block-dirty-bitmap-add"}]}} +{"error": {"class": "GenericError", "desc": "Cannot add a persistent bitmap to read-only or inactive node 'base'"}} +bitmap2 on the rw top node must not have survived the rollback: +{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap2", "node": "top"}} +{"error": {"class": "GenericError", "desc": "Dirty bitmap 'bitmap2' not found"}} +Marking the rw top node inactive: +{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "top"}} +{"return": {}} +Adding a persistent bitmap to a rw but inactive node, should fail: +{"execute": "block-dirty-bitmap-add", "arguments": {"name": "bitmap3", "node": "top", "persistent": true}} +{"error": {"class": "GenericError", "desc": "Cannot add a persistent bitmap to read-only or inactive node 'top'"}} +Reactivating the top node: +{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "top"}} +{"return": {}} From 3f3f5cdb929e8621699f92ee6e5018e1e6ea5bf2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 16 Jul 2026 13:22:41 +0200 Subject: [PATCH 348/627] migration/block-dirty-bitmap: reject bitmap load onto ro node dirty_bitmap_load_start() creates an incoming migrated bitmap with bdrv_create_dirty_bitmap() and, if the source marked it persistent, calls bdrv_dirty_bitmap_set_persistence() without checking whether the destination node can be written to. Same gap as qmp_block_dirty_bitmap_add(), reached via incoming migration: a persistent bitmap for a read-only destination (e.g. a migrated CD-ROM-class attachment with dirty-bitmaps migration enabled) ends up writable in memory on a node that can never store it. Reject it the same way, with one difference from the QMP path: every destination node is BDRV_O_INACTIVE until migration completes, so bdrv_is_writable() would reject every incoming persistent bitmap, not just read-only ones. Check bdrv_is_read_only() alone. Signed-off-by: Denis V. Lunev CC: Eric Blake CC: Vladimir Sementsov-Ogievskiy CC: John Snow CC: Andrey Drobyshev Message-ID: <20260716112242.3000035-3-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- migration/block-dirty-bitmap.c | 22 +++++++++---- tests/qemu-iotests/tests/migrate-bitmaps-test | 33 +++++++++++++++++++ .../tests/migrate-bitmaps-test.out | 4 +-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index cba54e25cd..1b8f39c12b 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -812,13 +812,6 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) error_report("Bitmap with the same name ('%s') already exists on " "destination", bdrv_dirty_bitmap_name(s->bitmap)); return -EINVAL; - } else { - s->bitmap = bdrv_create_dirty_bitmap(s->bs, granularity, - s->bitmap_name, &local_err); - if (!s->bitmap) { - error_report_err(local_err); - return -EINVAL; - } } if (flags & DIRTY_BITMAP_MIG_START_FLAG_RESERVED_MASK) { @@ -835,6 +828,21 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s) persistent = flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT; } + /* Not bdrv_is_writable(): nodes stay inactive until migration ends. */ + if (persistent && bdrv_is_read_only(s->bs)) { + error_report("Cannot make migrated bitmap '%s' persistent " + "on read-only node '%s'", s->bitmap_name, + bdrv_get_node_name(s->bs)); + return -EINVAL; + } + + s->bitmap = bdrv_create_dirty_bitmap(s->bs, granularity, + s->bitmap_name, &local_err); + if (!s->bitmap) { + error_report_err(local_err); + return -EINVAL; + } + if (persistent) { bdrv_dirty_bitmap_set_persistence(s->bitmap, true); } diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test index 8fb4099201..cb9154ca8d 100755 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test @@ -206,6 +206,39 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase): self.vm_b.launch() self.check_bitmap(self.vm_b, sha256 if persistent else False) + def test_migration_to_readonly_destination(self): + granularity = 512 + mig_caps = [{'capability': 'events', 'state': True}, + {'capability': 'dirty-bitmaps', 'state': True}] + + self.vm_b.add_incoming("defer") + self.vm_b.add_drive(disk_b, 'read-only=on') + + self.add_bitmap(self.vm_a, granularity, True) + self.vm_a.hmp_qemu_io('drive0', 'write 0 4096') + + self.vm_a.cmd('migrate-set-capabilities', capabilities=mig_caps) + self.vm_a.cmd('migrate', uri=mig_cmd) + while True: + event = self.vm_a.event_wait('MIGRATION') + if event['data']['status'] == 'completed': + break + self.vm_a.shutdown() + + self.vm_b.launch() + self.vm_b.cmd('migrate-set-capabilities', capabilities=mig_caps) + self.vm_b.cmd('migrate-incoming', uri=incoming_cmd) + while True: + event = self.vm_b.event_wait('MIGRATION') + if event['data']['status'] in ('completed', 'failed'): + break + + self.assert_qmp(event, 'data/status', 'failed') + + # A failed incoming load makes the destination process exit on + # its own; reap it so tearDown()'s shutdown() is a clean no-op. + self.vm_b.wait() + def inject_test_case(klass, suffix, method, *args, **kwargs): mc = operator.methodcaller(method, *args, **kwargs) diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test.out b/tests/qemu-iotests/tests/migrate-bitmaps-test.out index cafb8161f7..73e375a9d7 100644 --- a/tests/qemu-iotests/tests/migrate-bitmaps-test.out +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test.out @@ -1,5 +1,5 @@ -..................................... +...................................... ---------------------------------------------------------------------- -Ran 37 tests +Ran 38 tests OK From 9a77ef813f5f915bda408f4e53c11d0ca17c5d70 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 16 Jul 2026 13:22:42 +0200 Subject: [PATCH 349/627] block/monitor: allow dropping a bitmap never stored on disk block-dirty-bitmap-remove refuses any readonly bitmap outright, via the generic BDRV_BITMAP_RO check in bdrv_dirty_bitmap_check(). That check cannot tell whether the bitmap is actually on disk, so it also blocks dropping one that only ever existed in memory, which needs no write at all. Drop the blanket check and let qcow2 decide: bdrv_remove_persistent_ dirty_bitmap() already treats an absent on-disk entry as a no-op, so such a bitmap is now released with no write attempted. For one that is genuinely stored, qcow2_co_remove_persistent_dirty_bitmap_locked() now checks can_write() before it would update the on-disk directory, so removal still fails there, with a message naming the actual reason instead of just the bitmap's readonly flag. Signed-off-by: Denis V. Lunev CC: Eric Blake CC: Vladimir Sementsov-Ogievskiy CC: John Snow CC: Andrey Drobyshev Message-ID: <20260716112242.3000035-4-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/monitor/bitmap-qmp-cmds.c | 4 ++-- block/qcow2-bitmap.c | 9 +++++++++ tests/qemu-iotests/tests/remove-bitmap-from-backing.out | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c index d87ca982aa..aabf2790b6 100644 --- a/block/monitor/bitmap-qmp-cmds.c +++ b/block/monitor/bitmap-qmp-cmds.c @@ -165,11 +165,11 @@ BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name, return NULL; } - if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO, - errp)) { + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) { return NULL; } + /* Dropping a bitmap needs no write access unless it is actually stored. */ if (bdrv_dirty_bitmap_get_persistence(bitmap) && bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0) { diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 256ec99878..ac5a724588 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1487,6 +1487,15 @@ int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, goto out; } + if (!can_write(bs)) { + error_setg(errp, "Cannot remove persistent bitmap '%s': " + "no write access to node '%s'", name, + bdrv_get_node_name(bs)); + ret = -EACCES; + bm = NULL; + goto out; + } + QSIMPLEQ_REMOVE(bm_list, bm, Qcow2Bitmap, entry); ret = update_ext_header_and_dir(bs, bm_list); diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing.out b/tests/qemu-iotests/tests/remove-bitmap-from-backing.out index fe105fe0a3..628fa737d9 100644 --- a/tests/qemu-iotests/tests/remove-bitmap-from-backing.out +++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing.out @@ -1,6 +1,6 @@ Trying to remove persistent bitmap from r-o base node, should fail: {"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "base"}} -{"error": {"class": "GenericError", "desc": "Bitmap 'bitmap0' is readonly and cannot be modified"}} +{"error": {"class": "GenericError", "desc": "Cannot remove persistent bitmap 'bitmap0': no write access to node 'base'"}} Remove persistent bitmap from base node reopened to RW: {"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmap0", "node": "base"}} {"return": {}} From dc04053687ec7219a78f9b90fe2f71c9336914e1 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 11 Aug 2026 19:38:52 +0200 Subject: [PATCH 350/627] dirty-bitmap: fix integer overflow in serialization coverage The chunk size is an int and is shifted left by 3 before the result is widened, so a chunk size of 1 << 28 or above overflows. parallels passes s->cluster_size, which parallels_open() lets reach 2 GiB. With a bitmap needing two L1 entries the bogus limit makes the "bm_size - offset" in parallels_load_bitmap_data() underflow; both wrong values slip past the assertions in serialization_chunk() and the resulting index lands outside the hbitmap, so a 128 KiB image memsets unrelated memory through hbitmap_deserialize_ones(). Widen the shift. qcow2, the only other caller, never exceeds a 2 MiB cluster. Fixes: 35f428ba3971 ("qcow2-bitmap: make bytes_covered_by_bitmap_cluster() public") Cc: Eric Blake Cc: Vladimir Sementsov-Ogievskiy Cc: Stefan Hajnoczi Cc: Thomas Huth Signed-off-by: Denis V. Lunev Message-ID: <20260811173857.396571-4-den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/dirty-bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 13a1979755..9fda3a4b98 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -612,7 +612,7 @@ uint64_t bdrv_dirty_bitmap_serialization_coverage(int serialized_chunk_size, const BdrvDirtyBitmap *bitmap) { uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap); - uint64_t limit = granularity * (serialized_chunk_size << 3); + uint64_t limit = granularity * ((uint64_t)serialized_chunk_size << 3); assert(QEMU_IS_ALIGNED(limit, bdrv_dirty_bitmap_serialization_align(bitmap))); From 3181e53c13a1a68e2b54c94b1766f8e384c01b4c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 15:51:33 -0700 Subject: [PATCH 351/627] tcg/optimize: INDEX_op_mul is commutative MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: qemu-stable@nongnu.org Fixes: 7a2f7084525 ("tcg/optimize: Sink commutative operand swapping into fold functions") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index fcdef25bee..ed2ff32ed2 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2152,7 +2152,7 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) static bool fold_mul(OptContext *ctx, TCGOp *op) { - if (fold_const2(ctx, op) || + if (fold_const2_commutative(ctx, op) || fold_xi_to_i(ctx, op, 0) || fold_xi_to_x(ctx, op, 1)) { return true; From 5fe51606146cbf04dac07bf27256febbe56881e7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 14:15:00 -0700 Subject: [PATCH 352/627] tcg/optimize: Fix s_mask computation for shifts Skip s_mask computation for logical right shift. Cc: qemu-stable@nongnu.org Fixes: 93a967fbb57 ("tcg/optimize: Propagate sign info for shifting") Reported-by: Jacob Young Signed-off-by: Richard Henderson --- tcg/optimize.c | 11 ++++++++++- tests/tcg/i386/test-i386-opt-shr.c | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/i386/test-i386-opt-shr.c diff --git a/tcg/optimize.c b/tcg/optimize.c index ed2ff32ed2..d12babad88 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2656,8 +2656,17 @@ static bool fold_shift(OptContext *ctx, TCGOp *op) z_mask = do_constant_folding(op->opc, ctx->type, z_mask, sh); o_mask = do_constant_folding(op->opc, ctx->type, o_mask, sh); - s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh); + if (op->opc == INDEX_op_shr) { + /* + * Logical right shift will force the sign bit zero. + * Don't bother computing s_mask and let fold_masks + * recompute from z_mask. + */ + return fold_masks_zo(ctx, op, z_mask, o_mask); + } + + s_mask = do_constant_folding(op->opc, ctx->type, s_mask, sh); return fold_masks_zos(ctx, op, z_mask, o_mask, s_mask); } diff --git a/tests/tcg/i386/test-i386-opt-shr.c b/tests/tcg/i386/test-i386-opt-shr.c new file mode 100644 index 0000000000..9fb8d42022 --- /dev/null +++ b/tests/tcg/i386/test-i386-opt-shr.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Regression test for tcg optimize vs sign bit repetition counting. */ + +#include + +int main() +{ +#ifndef __x86_64__ + char test; + + asm("movw $0x4000, %%ax\n\t" + "addw %%ax, %%ax\n\t" + "cwtl\n\t" + "shrl %%eax\n\t" + "cmpw $-0x3fff, %%ax\n\t" + "setnl %%al" + : "=a"(test)); + assert(!test); +#endif + return 0; +} From 784b7f28e2761fbd3c753883be949eb3d1ffe228 Mon Sep 17 00:00:00 2001 From: Ilya Chichkov Date: Fri, 14 Aug 2026 17:21:59 +0300 Subject: [PATCH 353/627] accel/tcg: Allow overlapping reads in record_save record_save() assumed that a target reads the bytes of an insn as a strictly ascending sequence of adjacent chunks, and asserted that each read begins exactly where the previous one ended. That assumption no longer holds for riscv. Since f9eaa1542b ("target/riscv: support atomic instruction fetch (Ziccif)"), decode_opc() loads a full aligned word whenever pc is 4-byte aligned, even when the insn turns out to be a 2-byte compressed one, so the record may already hold bytes past the end of the insn being translated. When such a compressed insn sits at page offset 0xffc, pc_next becomes 0xffe, which is within MAX_INSN_LEN of the end of the page, and riscv_tr_translate_insn() probes the next insn to decide whether it would cross the page boundary. That probe reads at offset 2 while the record already covers [0,4), and the assert fires: qemu-system-riscv32: accel/tcg/translator.c:395: record_save: Assertion `offset == db->record_start + db->record_len' failed. record_save() is only reached when the insn is fetched from MMIO, so this is visible on boards that execute code from a region created with memory_region_init_io(), such as an XIP flash window mapped over a serial flash controller. Both sides of the collision are correct: the wide fetch is required for Ziccif atomicity, and the probe is required for correct fault reporting at a page boundary, per 00c07344fa ("target/riscv: Make translator stop before the end of a page"). Unlike a86d3352ab ("target/riscv: do not use translator_ldl in opcode_at"), where a non-translation caller had no business using translator_ld*, the probe here is a genuine translation read whose bytes must be recorded. Relax the invariant instead. Keep requiring that a read neither moves backwards nor leaves a gap, but let a read overlapping the recorded range extend it only by the bytes past its end. Cc: qemu-stable@nongnu.org Fixes: f9eaa1542b ("target/riscv: support atomic instruction fetch (Ziccif)") Signed-off-by: Ilya Chichkov Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20260814142159.3800744-1-ilya.chichkov.dev@gmail.com> --- accel/tcg/translator.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index cd7d079fe0..57daded60f 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -387,14 +387,22 @@ static void record_save(DisasContextBase *db, vaddr pc, * Either the first or second page may be I/O. If it is the second, * then the first byte we need to record will be at a non-zero offset. * In either case, we should not need to record but a single insn. + * + * A read may re-read bytes that are already recorded: a target may + * fetch a whole aligned word to decode an insn (e.g. riscv Ziccif), + * then probe the following insn, which lies within that same word. + * Such a read extends the record only by the bytes past its end. */ if (db->record_len == 0) { db->record_start = offset; db->record_len = size; } else { - assert(offset == db->record_start + db->record_len); - assert(db->record_len + size <= sizeof(db->record)); - db->record_len += size; + int end = offset - db->record_start + size; + + assert(offset >= db->record_start); + assert(offset <= db->record_start + db->record_len); + assert(end <= sizeof(db->record)); + db->record_len = MAX(db->record_len, end); } memcpy(db->record + (offset - db->record_start), from, size); From e131c28b6eb24c0b7f7f21591b2b2c7568267337 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 16:06:10 -0700 Subject: [PATCH 354/627] tcg: Return success from tcg_region_alloc__locked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invert the sense of the boolean result from 'error' to 'success'. Tested-by: Yogesh Vyas Reviewed-by: Yogesh Vyas Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/region.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tcg/region.c b/tcg/region.c index 5d4be1453b..2161d961d9 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -360,11 +360,11 @@ static void tcg_region_assign(TCGContext *s, size_t curr_region) static bool tcg_region_alloc__locked(TCGContext *s) { if (region.current == region.n) { - return true; + return false; } tcg_region_assign(s, region.current); region.current++; - return false; + return true; } /* @@ -373,17 +373,17 @@ static bool tcg_region_alloc__locked(TCGContext *s) */ bool tcg_region_alloc(TCGContext *s) { - bool err; + bool ok; /* read the region size now; alloc__locked will overwrite it on success */ size_t size_full = s->code_gen_buffer_size; qemu_mutex_lock(®ion.lock); - err = tcg_region_alloc__locked(s); - if (!err) { + ok = tcg_region_alloc__locked(s); + if (ok) { region.agg_size_full += size_full - TCG_HIGHWATER; } qemu_mutex_unlock(®ion.lock); - return err; + return !ok; } /* @@ -392,8 +392,8 @@ bool tcg_region_alloc(TCGContext *s) */ static void tcg_region_initial_alloc__locked(TCGContext *s) { - bool err = tcg_region_alloc__locked(s); - g_assert(!err); + bool ok = tcg_region_alloc__locked(s); + g_assert(ok); } void tcg_region_initial_alloc(TCGContext *s) From fcdbc78ad4dea4b6baac581be5f7350ce47dc218 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 16:08:40 -0700 Subject: [PATCH 355/627] tcg: Return success from tcg_region_alloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invert the sense of the boolean result from 'error' to 'success'. Tested-by: Yogesh Vyas Reviewed-by: Yogesh Vyas Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/region.c | 4 ++-- tcg/tcg.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tcg/region.c b/tcg/region.c index 2161d961d9..57ca742357 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -369,7 +369,7 @@ static bool tcg_region_alloc__locked(TCGContext *s) /* * Request a new region once the one in use has filled up. - * Returns true on error. + * Returns true on success. */ bool tcg_region_alloc(TCGContext *s) { @@ -383,7 +383,7 @@ bool tcg_region_alloc(TCGContext *s) region.agg_size_full += size_full - TCG_HIGHWATER; } qemu_mutex_unlock(®ion.lock); - return !ok; + return ok; } /* diff --git a/tcg/tcg.c b/tcg/tcg.c index 1e77f2365a..af15c3d63e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1835,7 +1835,7 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s) next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); if (unlikely(next > s->code_gen_highwater)) { - if (tcg_region_alloc(s)) { + if (!tcg_region_alloc(s)) { return NULL; } goto retry; From f5d2d8532f3c3cefb644fe9c1866a21b75f76faf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 17:11:28 -0700 Subject: [PATCH 356/627] tcg: Defer tb_flush when initial thread region alloc fails A vCPU hotplug may happen at any time. When the new thread is started, the region pool may be exhausted. Do not abort. Rename tcg_region_thread_initial_alloc to differentiate it from tcg_region_initial_alloc__locked. The renamed function now uses tcg_region_alloc__locked and is prepared for failure. In tcg_tb_alloc, allow code_gen_ptr to be NULL. Treat that as any other region exhaustion. Reorg with while instead of goto. Tested-by: Yogesh Vyas Reviewed-by: Yogesh Vyas Reported-by: Anushree Mathur Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2984 Signed-off-by: Richard Henderson --- tcg/region.c | 24 ++++++++++++++++++++++-- tcg/tcg-internal.h | 2 +- tcg/tcg.c | 22 ++++++++++++++-------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/tcg/region.c b/tcg/region.c index 57ca742357..1145f35085 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -396,11 +396,31 @@ static void tcg_region_initial_alloc__locked(TCGContext *s) g_assert(ok); } -void tcg_region_initial_alloc(TCGContext *s) +void tcg_region_thread_initial_alloc(TCGContext *s) { + bool ok; + qemu_mutex_lock(®ion.lock); - tcg_region_initial_alloc__locked(s); + ok = tcg_region_alloc__locked(s); qemu_mutex_unlock(®ion.lock); + + /* + * A vCPU hotplug may happen at any time. When the new thread is + * started, the region pool may be exhausted. At this point in + * the new thread call stack, we are not in a position to fix this. + * Leave code_gen_ptr NULL, so that this thread's first call to + * tcg_tb_alloc() returns NULL, so that the translator performs + * a tb_flush() and retry. + * + * During the tb_flush(), tcg_region_reset_all() will assign a + * new region to all contexts, including this one. + */ + if (!ok) { + s->code_gen_buffer = NULL; + s->code_gen_ptr = NULL; + s->code_gen_buffer_size = 0; + s->code_gen_highwater = NULL; + } } /* Call from a safe-work context */ diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index c0997ab224..e35440dc8c 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -42,7 +42,7 @@ extern unsigned int tcg_max_ctxs; void tcg_region_init(size_t tb_size, int splitwx, unsigned max_threads); bool tcg_region_alloc(TCGContext *s); -void tcg_region_initial_alloc(TCGContext *s); +void tcg_region_thread_initial_alloc(TCGContext *s); void tcg_region_prologue_set(TCGContext *s); static inline void *tcg_call_func(TCGOp *op) diff --git a/tcg/tcg.c b/tcg/tcg.c index af15c3d63e..db43589fa2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1279,7 +1279,7 @@ void tcg_register_thread(void) qatomic_set(&tcg_ctxs[n], s); if (n > 0) { - tcg_region_initial_alloc(s); + tcg_region_thread_initial_alloc(s); } tcg_ctx = s; @@ -1830,18 +1830,24 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s) TranslationBlock *tb; void *next; - retry: - tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); - next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); + while (1) { + tb = (void *)ROUND_UP((uintptr_t)s->code_gen_ptr, align); - if (unlikely(next > s->code_gen_highwater)) { + /* + * Note that code_gen_ptr can be NULL after vCPU hotplug. + * See tcg_region_thread_initial_alloc. + */ + if (tb) { + next = (void *)ROUND_UP((uintptr_t)(tb + 1), align); + if (next <= s->code_gen_highwater) { + qatomic_set(&s->code_gen_ptr, next); + return tb; + } + } if (!tcg_region_alloc(s)) { return NULL; } - goto retry; } - qatomic_set(&s->code_gen_ptr, next); - return tb; } void tcg_prologue_init(void) From 3f3a1ea472d1fc25ecf70087e0a33e57c7f191f4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 15:37:38 -0700 Subject: [PATCH 357/627] tcg: Fix opcode dump for bswap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use an array of char for bswap_flag_name, so some entries in the array are non-null but empty. Check that. Fixes: 587195bd590 ("tcg: Add flags argument to bswap opcodes") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index db43589fa2..937d0c8fd7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2957,7 +2957,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) if (flags < ARRAY_SIZE(bswap_flag_name)) { name = bswap_flag_name[flags]; } - if (name) { + if (name && name[0]) { col += ne_fprintf(f, ",%s", name); } else { col += ne_fprintf(f, ",$0x%" TCG_PRIlx, flags); From c2ca3737400ebf9432bf14fc59db69538868466d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 10:55:05 -0700 Subject: [PATCH 358/627] tcg: Add tcg_gen_revbit{8,32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add generic expanders for reversing bits within a word. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/tcg-op-common.h | 5 +++ include/tcg/tcg-op.h | 7 ++++ tcg/tcg-op.c | 76 +++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index 1fe342db0d..f7b6aadb50 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -164,6 +164,8 @@ void tcg_gen_smax_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_umin_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_umax_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_abs_i32(TCGv_i32, TCGv_i32); +void tcg_gen_revbit8_i32(TCGv_i32 ret, TCGv_i32 arg); +void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg); /* Replicate a value of size @vece from @in to all the lanes in @out */ void tcg_gen_dup_i32(unsigned vece, TCGv_i32 out, TCGv_i32 in); @@ -275,6 +277,9 @@ void tcg_gen_smax_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_umin_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_umax_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_abs_i64(TCGv_i64, TCGv_i64); +void tcg_gen_revbit8_i64(TCGv_i64 ret, TCGv_i64 arg); +void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); +void tcg_gen_revbit64_i64(TCGv_i64 ret, TCGv_i64 arg); /* Replicate a value of size @vece from @in to all the lanes in @out */ void tcg_gen_dup_i64(unsigned vece, TCGv_i64 out, TCGv_i64 in); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 96a5af1a29..568b78fe81 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -115,6 +115,10 @@ typedef TCGv_i64 TCGv; #define tcg_gen_bswap_tl tcg_gen_bswap64_i64 #define tcg_gen_hswap_tl tcg_gen_hswap_i64 #define tcg_gen_wswap_tl tcg_gen_wswap_i64 +#define tcg_gen_revbit8_tl tcg_gen_revbit8_i64 +#define tcg_gen_revbit32_tl tcg_gen_revbit32_i64 +#define tcg_gen_revbit64_tl tcg_gen_revbit64_i64 +#define tcg_gen_revbit_tl tcg_gen_revbit64_i64 #define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 #define tcg_gen_extr_i64_tl tcg_gen_extr32_i64 #define tcg_gen_andc_tl tcg_gen_andc_i64 @@ -234,6 +238,9 @@ typedef TCGv_i64 TCGv; #define tcg_gen_bswap32_tl(D, S, F) tcg_gen_bswap32_i32(D, S) #define tcg_gen_bswap_tl tcg_gen_bswap32_i32 #define tcg_gen_hswap_tl tcg_gen_hswap_i32 +#define tcg_gen_revbit8_tl tcg_gen_revbit8_i32 +#define tcg_gen_revbit32_tl(D, S, F) tcg_gen_revbit32_i32(D, S) +#define tcg_gen_revbit_tl tcg_gen_revbit32_i32 #define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 #define tcg_gen_extr_i64_tl tcg_gen_extr_i64_i32 #define tcg_gen_andc_tl tcg_gen_andc_i32 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index bbcb510c76..3d28280785 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1160,6 +1160,45 @@ void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) tcg_gen_extract_i32(ret, arg, 0, 16); } +/* + * Internal helper for bit and byte reversal. + * Given a repeating matched block of 1's and 0's, swap the bits within + * those two blocks. E.g. mask=00ff00ff, shift the input bits left and + * right 8 bits. + */ +static void gen_bitswap_i32(TCGv_i32 ret, TCGv_i32 arg, uint32_t mask) +{ + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); + int sh = cto32(mask); + + tcg_gen_andi_i32(t0, arg, mask); + tcg_gen_shri_i32(t1, arg, sh); + tcg_gen_shli_i32(t0, t0, sh); + tcg_gen_andi_i32(t1, t1, mask); + tcg_gen_or_i32(ret, t0, t1); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); +} + +/* Similarly for 64-bit operands. */ +static void gen_bitswap_i64(TCGv_i64 ret, TCGv_i64 arg, uint64_t mask) +{ + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + TCGv_i64 t1 = tcg_temp_ebb_new_i64(); + int sh = cto64(mask); + + tcg_gen_andi_i64(t0, arg, mask); + tcg_gen_shri_i64(t1, arg, sh); + tcg_gen_shli_i64(t0, t0, sh); + tcg_gen_andi_i64(t1, t1, mask); + tcg_gen_or_i64(ret, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + /* * bswap16_i32: 16-bit byte swap on the low bits of a 32-bit value. * @@ -1244,6 +1283,19 @@ void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg) tcg_gen_rotli_i32(ret, arg, 16); } +void tcg_gen_revbit8_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + gen_bitswap_i32(ret, arg, 0x55555555u); + gen_bitswap_i32(ret, ret, 0x33333333u); + gen_bitswap_i32(ret, ret, 0x0f0f0f0fu); +} + +void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg) +{ + tcg_gen_revbit8_i32(ret, arg); + tcg_gen_bswap32_i32(ret, ret); +} + void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); @@ -1869,6 +1921,30 @@ void tcg_gen_wswap_i64(TCGv_i64 ret, TCGv_i64 arg) tcg_gen_rotli_i64(ret, arg, 32); } +void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) +{ + /* Only one extension flag may be present. */ + tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); + + gen_bitswap_i64(ret, arg, 0x55555555ull); + gen_bitswap_i64(ret, ret, 0x33333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0full); + tcg_gen_bswap32_i64(ret, ret, flags | TCG_BSWAP_IZ); +} + +void tcg_gen_revbit8_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + gen_bitswap_i64(ret, arg, 0x5555555555555555ull); + gen_bitswap_i64(ret, ret, 0x3333333333333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full); +} + +void tcg_gen_revbit64_i64(TCGv_i64 ret, TCGv_i64 arg) +{ + tcg_gen_revbit8_i64(ret, arg); + tcg_gen_bswap64_i64(ret, ret); +} + void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) { if (tcg_op_supported(INDEX_op_not, TCG_TYPE_I64, 0)) { From 288d39e26d48ed26e4f786ddb3a25eef0bca9f56 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 09:08:31 -0700 Subject: [PATCH 359/627] tcg: Simplify bswap/hswap expansion using bitswap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 72 ++++++---------------------------------------------- 1 file changed, 8 insertions(+), 64 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 3d28280785..c24a7962fc 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1252,23 +1252,8 @@ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) if (tcg_op_supported(INDEX_op_bswap32, TCG_TYPE_I32, 0)) { tcg_gen_op3i_i32(INDEX_op_bswap32, ret, arg, 0); } else { - TCGv_i32 t0 = tcg_temp_ebb_new_i32(); - TCGv_i32 t1 = tcg_temp_ebb_new_i32(); - TCGv_i32 t2 = tcg_constant_i32(0x00ff00ff); - - /* arg = abcd */ - tcg_gen_shri_i32(t0, arg, 8); /* t0 = .abc */ - tcg_gen_and_i32(t1, arg, t2); /* t1 = .b.d */ - tcg_gen_and_i32(t0, t0, t2); /* t0 = .a.c */ - tcg_gen_shli_i32(t1, t1, 8); /* t1 = b.d. */ - tcg_gen_or_i32(ret, t0, t1); /* ret = badc */ - - tcg_gen_shri_i32(t0, ret, 16); /* t0 = ..ba */ - tcg_gen_shli_i32(t1, ret, 16); /* t1 = dc.. */ - tcg_gen_or_i32(ret, t0, t1); /* ret = dcba */ - - tcg_temp_free_i32(t0); - tcg_temp_free_i32(t1); + gen_bitswap_i32(ret, arg, 0x00ff00ff); + tcg_gen_hswap_i32(ret, ret); } } @@ -1823,14 +1808,9 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - TCGv_i64 t2 = tcg_constant_i64(0x00ff00ff); - /* arg = xxxxabcd */ - tcg_gen_shri_i64(t0, arg, 8); /* t0 = .xxxxabc */ - tcg_gen_and_i64(t1, arg, t2); /* t1 = .....b.d */ - tcg_gen_and_i64(t0, t0, t2); /* t0 = .....a.c */ - tcg_gen_shli_i64(t1, t1, 8); /* t1 = ....b.d. */ - tcg_gen_or_i64(ret, t0, t1); /* ret = ....badc */ + /* arg = xxxxabcd */ + gen_bitswap_i64(ret, arg, 0x00ff00ff); /* ret = ....badc */ tcg_gen_shli_i64(t1, ret, 48); /* t1 = dc...... */ tcg_gen_shri_i64(t0, ret, 16); /* t0 = ......ba */ @@ -1857,32 +1837,8 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) if (tcg_op_supported(INDEX_op_bswap64, TCG_TYPE_I64, 0)) { tcg_gen_op3i_i64(INDEX_op_bswap64, ret, arg, 0); } else { - TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - TCGv_i64 t2 = tcg_temp_ebb_new_i64(); - - /* arg = abcdefgh */ - tcg_gen_movi_i64(t2, 0x00ff00ff00ff00ffull); - tcg_gen_shri_i64(t0, arg, 8); /* t0 = .abcdefg */ - tcg_gen_and_i64(t1, arg, t2); /* t1 = .b.d.f.h */ - tcg_gen_and_i64(t0, t0, t2); /* t0 = .a.c.e.g */ - tcg_gen_shli_i64(t1, t1, 8); /* t1 = b.d.f.h. */ - tcg_gen_or_i64(ret, t0, t1); /* ret = badcfehg */ - - tcg_gen_movi_i64(t2, 0x0000ffff0000ffffull); - tcg_gen_shri_i64(t0, ret, 16); /* t0 = ..badcfe */ - tcg_gen_and_i64(t1, ret, t2); /* t1 = ..dc..hg */ - tcg_gen_and_i64(t0, t0, t2); /* t0 = ..ba..fe */ - tcg_gen_shli_i64(t1, t1, 16); /* t1 = dc..hg.. */ - tcg_gen_or_i64(ret, t0, t1); /* ret = dcbahgfe */ - - tcg_gen_shri_i64(t0, ret, 32); /* t0 = ....dcba */ - tcg_gen_shli_i64(t1, ret, 32); /* t1 = hgfe.... */ - tcg_gen_or_i64(ret, t0, t1); /* ret = hgfedcba */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); + gen_bitswap_i64(ret, arg, 0x00ff00ff00ff00ffull); + tcg_gen_hswap_i64(ret, ret); } } @@ -1894,20 +1850,8 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) */ void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg) { - uint64_t m = 0x0000ffff0000ffffull; - TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - - /* arg = abcdefgh */ - tcg_gen_rotli_i64(t1, arg, 32); /* t1 = efghabcd */ - tcg_gen_andi_i64(t0, t1, m); /* t0 = ..gh..cd */ - tcg_gen_shli_i64(t0, t0, 16); /* t0 = gh..cd.. */ - tcg_gen_shri_i64(t1, t1, 16); /* t1 = ..efghab */ - tcg_gen_andi_i64(t1, t1, m); /* t1 = ..ef..ab */ - tcg_gen_or_i64(ret, t0, t1); /* ret = ghefcdab */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + gen_bitswap_i64(ret, ret, 0x0000ffff0000ffffull); + tcg_gen_wswap_i64(ret, ret); } /* From ab86f82ba9f190d3e9a46f6f354333f0b29ee905 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 11:09:58 -0700 Subject: [PATCH 360/627] target/arm: Use generic tcg_gen_revbit* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/arm/tcg/helper-a64-defs.h | 1 - target/arm/tcg/helper-a64.c | 5 ----- target/arm/tcg/helper-defs.h | 1 - target/arm/tcg/op_helper.c | 5 ----- target/arm/tcg/translate-a64.c | 4 ++-- target/arm/tcg/translate.c | 2 +- 6 files changed, 3 insertions(+), 15 deletions(-) diff --git a/target/arm/tcg/helper-a64-defs.h b/target/arm/tcg/helper-a64-defs.h index 0e56e00f45..12f58c6a44 100644 --- a/target/arm/tcg/helper-a64-defs.h +++ b/target/arm/tcg/helper-a64-defs.h @@ -18,7 +18,6 @@ */ DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64) -DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_2(msr_i_spsel, void, env, i32) DEF_HELPER_2(msr_i_daifset, void, env, i32) DEF_HELPER_2(msr_i_daifclear, void, env, i32) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 05ab9ab6d3..9d805231a0 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -69,11 +69,6 @@ int64_t HELPER(sdiv64)(int64_t num, int64_t den) return num / den; } -uint64_t HELPER(rbit64)(uint64_t x) -{ - return revbit64(x); -} - void HELPER(msr_i_spsel)(CPUARMState *env, uint32_t imm) { update_spsel(env, imm); diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index 0077aeb4e2..42376af2c6 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -10,7 +10,6 @@ DEF_HELPER_3(add_usaturate, i32, env, i32, i32) DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_RWG, s32, env, s32, s32) DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_RWG, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32) #define PAS_OP(pfx) \ DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index c4433be2ed..857e897a48 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -172,11 +172,6 @@ uint32_t HELPER(udiv)(CPUARMState *env, uint32_t num, uint32_t den) return num / den; } -uint32_t HELPER(rbit)(uint32_t x) -{ - return revbit32(x); -} - uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t res = a + b; diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 1780490065..4f9a93950b 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8963,7 +8963,7 @@ static void gen_wrap2_i32(TCGv_i64 d, TCGv_i64 n, NeonGenOneOpFn fn) static void gen_rbit32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) { - gen_wrap2_i32(tcg_rd, tcg_rn, gen_helper_rbit); + tcg_gen_revbit32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ); } static void gen_rev16_xx(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 mask) @@ -8998,7 +8998,7 @@ static void gen_rev32(TCGv_i64 tcg_rd, TCGv_i64 tcg_rn) tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32); } -TRANS(RBIT, gen_rr, a->rd, a->rn, a->sf ? gen_helper_rbit64 : gen_rbit32) +TRANS(RBIT, gen_rr, a->rd, a->rn, a->sf ? tcg_gen_revbit64_i64 : gen_rbit32) TRANS(REV16, gen_rr, a->rd, a->rn, a->sf ? gen_rev16_64 : gen_rev16_32) TRANS(REV32, gen_rr, a->rd, a->rn, a->sf ? gen_rev32 : gen_rev_32) TRANS(REV64, gen_rr, a->rd, a->rn, tcg_gen_bswap64_i64) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 055f3c5b40..1770428d3c 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -4835,7 +4835,7 @@ static bool trans_RBIT(DisasContext *s, arg_rr *a) if (!ENABLE_ARCH_6T2) { return false; } - return op_rr(s, a, gen_helper_rbit); + return op_rr(s, a, tcg_gen_revbit32_i32); } /* From 8c7ba1cedffb55827165d47f9216b24dccbd34e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 11:29:30 -0700 Subject: [PATCH 361/627] target/loongarch: Use generic tcg_gen_revbit* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Song Gao <17746591750@163.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/loongarch/tcg/helper.h | 4 ---- .../loongarch/tcg/insn_trans/trans_bit.c.inc | 13 ++++++++---- target/loongarch/tcg/op_helper.c | 21 ------------------- 3 files changed, 9 insertions(+), 29 deletions(-) diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index 8a6c62f116..e76c73c775 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -5,10 +5,6 @@ DEF_HELPER_2(raise_exception, noreturn, env, i32) -DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) - DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) diff --git a/target/loongarch/tcg/insn_trans/trans_bit.c.inc b/target/loongarch/tcg/insn_trans/trans_bit.c.inc index ee5fa003ce..b91bb7eaa6 100644 --- a/target/loongarch/tcg/insn_trans/trans_bit.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_bit.c.inc @@ -178,6 +178,11 @@ static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); } +static void gen_bitrev_w(TCGv dest, TCGv src) +{ + tcg_gen_revbit32_tl(dest, src, TCG_BSWAP_OS); +} + TRANS(ext_w_h, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) TRANS(ext_w_b, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) TRANS(clo_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) @@ -194,10 +199,10 @@ TRANS(revb_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) TRANS(revb_d, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) TRANS(revh_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) TRANS(revh_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) -TRANS(bitrev_4b, ALL, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) -TRANS(bitrev_8b, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) -TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) -TRANS(bitrev_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +TRANS(bitrev_4b, ALL, gen_rr, EXT_NONE, EXT_SIGN, tcg_gen_revbit8_i64) +TRANS(bitrev_8b, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_revbit8_i64) +TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_bitrev_w) +TRANS(bitrev_d, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_revbit64_i64) TRANS(maskeqz, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) TRANS(masknez, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) TRANS(bytepick_w, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c index e63ac66daa..f41f0cb1e6 100644 --- a/target/loongarch/tcg/op_helper.c +++ b/target/loongarch/tcg/op_helper.c @@ -22,27 +22,6 @@ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) do_raise_exception(env, exception, GETPC()); } -target_ulong helper_bitrev_w(target_ulong rj) -{ - return (int32_t)revbit32(rj); -} - -target_ulong helper_bitrev_d(target_ulong rj) -{ - return revbit64(rj); -} - -target_ulong helper_bitswap(target_ulong v) -{ - v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | - ((v & (target_ulong)0x5555555555555555ULL) << 1); - v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | - ((v & (target_ulong)0x3333333333333333ULL) << 2); - v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | - ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); - return v; -} - /* loongarch assert op */ void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) { From 8b416699c88f78c56eb668b18d40876034857542 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 12:04:53 -0700 Subject: [PATCH 362/627] target/mips: Expand octeon reflections inline Use tcg_gen_revbit64_i64 instead of out-of-line helpers. Reviewed-by: Anton Johansson Signed-off-by: Richard Henderson --- target/mips/helper.h | 7 ----- target/mips/tcg/octeon_crypto.c | 35 --------------------- target/mips/tcg/octeon_translate.c | 49 ++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 48 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 786117813a..779b87101d 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -27,10 +27,6 @@ DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32) /* Octeon COP2 selector operation helpers. */ DEF_HELPER_1(octeon_cp2_mf_crc_iv_reflect, i64, env) -DEF_HELPER_1(octeon_cp2_mf_gfm_mul_reflect0, i64, env) -DEF_HELPER_1(octeon_cp2_mf_gfm_mul_reflect1, i64, env) -DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect0, i64, env) -DEF_HELPER_1(octeon_cp2_mf_gfm_resinp_reflect1, i64, env) DEF_HELPER_2(octeon_cp2_mt_crc_write_iv_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_polynomial_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_byte, void, env, i64) @@ -43,9 +39,6 @@ DEF_HELPER_2(octeon_cp2_mt_crc_write_dword, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_var, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_dword_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_crc_write_var_reflect, void, env, i64) -DEF_HELPER_2(octeon_cp2_mt_gfm_mul_reflect0, void, env, i64) -DEF_HELPER_2(octeon_cp2_mt_gfm_mul_reflect1, void, env, i64) -DEF_HELPER_2(octeon_cp2_mt_gfm_xor0_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1_reflect, void, env, i64) DEF_HELPER_2(octeon_cp2_mt_gfm_xormul1, void, env, i64) DEF_HELPER_1(octeon_cp2_mt_sha3_startop, void, env) diff --git a/target/mips/tcg/octeon_crypto.c b/target/mips/tcg/octeon_crypto.c index fbf80be2a5..118397e632 100644 --- a/target/mips/tcg/octeon_crypto.c +++ b/target/mips/tcg/octeon_crypto.c @@ -2127,41 +2127,6 @@ uint64_t helper_octeon_cp2_mf_crc_iv_reflect(CPUMIPSState *env) return octeon_crc_reflect32_by_byte(env->octeon_crypto.crc_iv); } -uint64_t helper_octeon_cp2_mf_gfm_mul_reflect0(CPUMIPSState *env) -{ - return revbit64(env->octeon_crypto.gfm_mul[0]); -} - -uint64_t helper_octeon_cp2_mf_gfm_mul_reflect1(CPUMIPSState *env) -{ - return revbit64(env->octeon_crypto.gfm_mul[1]); -} - -uint64_t helper_octeon_cp2_mf_gfm_resinp_reflect0(CPUMIPSState *env) -{ - return revbit64(env->octeon_crypto.gfm_resinp[0]); -} - -uint64_t helper_octeon_cp2_mf_gfm_resinp_reflect1(CPUMIPSState *env) -{ - return revbit64(env->octeon_crypto.gfm_resinp[1]); -} - -void helper_octeon_cp2_mt_gfm_mul_reflect0(CPUMIPSState *env, uint64_t value) -{ - env->octeon_crypto.gfm_mul[0] = revbit64(value); -} - -void helper_octeon_cp2_mt_gfm_mul_reflect1(CPUMIPSState *env, uint64_t value) -{ - env->octeon_crypto.gfm_mul[1] = revbit64(value); -} - -void helper_octeon_cp2_mt_gfm_xor0_reflect(CPUMIPSState *env, uint64_t value) -{ - env->octeon_crypto.gfm_resinp[0] ^= revbit64(value); -} - static void octeon_gfm_xormul1_common(MIPSOcteonCryptoState *crypto, uint64_t value) { diff --git a/target/mips/tcg/octeon_translate.c b/target/mips/tcg/octeon_translate.c index a0db6630c7..b689adb46b 100644 --- a/target/mips/tcg/octeon_translate.c +++ b/target/mips/tcg/octeon_translate.c @@ -28,6 +28,8 @@ TRANS(NAME, trans_octeon_cp2_mf_hsh_pair, \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) +#define CP2_MF_REFLECT(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mf_reflect, OCTEON_CRYPTO_OFFSET(FIELD)) #define CP2_MF_HELPER(NAME, SUFFIX) \ TRANS(NAME, trans_octeon_cp2_mf_helper, \ gen_helper_octeon_cp2_mf_ ## SUFFIX) @@ -44,6 +46,8 @@ TRANS(NAME, trans_octeon_cp2_mt_hsh_pair, \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX)]), \ OCTEON_CRYPTO_OFFSET(FIELD[2 * (INDEX) + 1])) +#define CP2_MT_REFLECT(NAME, FIELD) \ + TRANS(NAME, trans_octeon_cp2_mt_reflect, OCTEON_CRYPTO_OFFSET(FIELD)) #define CP2_MT_HELPER(NAME, SUFFIX) \ TRANS(NAME, trans_octeon_cp2_mt_helper, \ gen_helper_octeon_cp2_mt_ ## SUFFIX) @@ -110,6 +114,17 @@ static bool trans_octeon_cp2_mf_hsh_pair(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mf_reflect(DisasContext *ctx, arg_cp2 *a, + int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + tcg_gen_ld_i64(value, tcg_env, offset); + tcg_gen_revbit64_i64(value, value); + gen_store_gpr(value, a->rt); + return true; +} + static bool trans_octeon_cp2_mf_helper(DisasContext *ctx, arg_cp2 *a, void (*gen_helper)(TCGv_i64, TCGv_env)) { @@ -183,6 +198,17 @@ static bool trans_octeon_cp2_mt_xor_i64(DisasContext *ctx, arg_cp2 *a, return true; } +static bool trans_octeon_cp2_mt_reflect(DisasContext *ctx, arg_cp2 *a, + int offset) +{ + TCGv_i64 value = tcg_temp_new_i64(); + + gen_load_gpr(value, a->rt); + tcg_gen_revbit64_i64(value, value); + tcg_gen_st_i64(value, tcg_env, offset); + return true; +} + static bool trans_octeon_cp2_mt_helper(DisasContext *ctx, arg_cp2 *a, void (*gen_helper)(TCGv_env, TCGv_i64)) { @@ -200,6 +226,17 @@ static bool trans_octeon_cp2_mt_helper_env(DisasContext *ctx, arg_cp2 *a, return true; } +static void gen_helper_octeon_cp2_mt_gfm_xor0_reflect(TCGv_env t_env, + TCGv_i64 value) +{ + TCGv_i64 resinp = tcg_temp_new_i64(); + + tcg_gen_revbit64_i64(value, value); + tcg_gen_ld_i64(resinp, t_env, OCTEON_CRYPTO_OFFSET(gfm_resinp[0])); + tcg_gen_xor_i64(resinp, resinp, value); + tcg_gen_st_i64(resinp, t_env, OCTEON_CRYPTO_OFFSET(gfm_resinp[0])); +} + CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT0, hsh_dat, 0); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT1, hsh_dat, 1); CP2_MF_HSH_PAIR(CVM_MF_HSH_DAT2, hsh_dat, 2); @@ -241,10 +278,10 @@ CP2_MF_I64(CVM_MF_LLM_DATA1, llm_data[1]); CP2_MF_HELPER(CVM_MF_CRC_IV_REFLECT, crc_iv_reflect); CP2_MF_I64(CVM_MF_SHA3_DAT24, sha3_dat24); -CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT0, gfm_mul_reflect0); -CP2_MF_HELPER(CVM_MF_GFM_MUL_REFLECT1, gfm_mul_reflect1); -CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT0, gfm_resinp_reflect0); -CP2_MF_HELPER(CVM_MF_GFM_RESINP_REFLECT1, gfm_resinp_reflect1); +CP2_MF_REFLECT(CVM_MF_GFM_MUL_REFLECT0, gfm_mul[0]) +CP2_MF_REFLECT(CVM_MF_GFM_MUL_REFLECT1, gfm_mul[1]) +CP2_MF_REFLECT(CVM_MF_GFM_RESINP_REFLECT0, gfm_resinp[0]) +CP2_MF_REFLECT(CVM_MF_GFM_RESINP_REFLECT1, gfm_resinp[1]) CP2_MF_I64(CVM_MF_HSH_DATW0, hsh_dat[0]); CP2_MF_I64(CVM_MF_HSH_DATW1, hsh_dat[1]); CP2_MF_I64(CVM_MF_HSH_DATW2, hsh_dat[2]); @@ -281,8 +318,8 @@ CP2_MT_HSH_PAIR(CVM_MT_HSH_IV0, hsh_iv, 0); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV1, hsh_iv, 1); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV2, hsh_iv, 2); CP2_MT_HSH_PAIR(CVM_MT_HSH_IV3, hsh_iv, 3); -CP2_MT_HELPER(CVM_MT_GFM_MUL_REFLECT0, gfm_mul_reflect0); -CP2_MT_HELPER(CVM_MT_GFM_MUL_REFLECT1, gfm_mul_reflect1); +CP2_MT_REFLECT(CVM_MT_GFM_MUL_REFLECT0, gfm_mul[0]); +CP2_MT_REFLECT(CVM_MT_GFM_MUL_REFLECT1, gfm_mul[1]); CP2_MT_HELPER(CVM_MT_GFM_XOR0_REFLECT, gfm_xor0_reflect); CP2_MT_I64(CVM_MT_3DES_KEY0, des3_key[0]); CP2_MT_I64(CVM_MT_3DES_KEY1, des3_key[1]); From 0a897b9c0c7e745a32ebfa363ebe9cc0218fb6cc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 09:42:10 -0700 Subject: [PATCH 363/627] target/riscv: Use generic tcg_gen_revbit8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/riscv/helper.h | 1 - target/riscv/tcg/bitmanip_helper.c | 15 --------------- target/riscv/tcg/insn_trans/trans_rvb.c.inc | 2 +- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 542b7c264f..4fc2d3a155 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -79,7 +79,6 @@ DEF_HELPER_FLAGS_2(froundnx_d, TCG_CALL_NO_RWG_SE, i64, env, i64) /* Bitmanip */ DEF_HELPER_FLAGS_2(clmul, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_FLAGS_2(clmulr, TCG_CALL_NO_RWG_SE, tl, tl, tl) -DEF_HELPER_FLAGS_1(brev8, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(unzip, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(zip, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(xperm4, TCG_CALL_NO_RWG_SE, tl, tl, tl) diff --git a/target/riscv/tcg/bitmanip_helper.c b/target/riscv/tcg/bitmanip_helper.c index 1156a87dd3..d8d94bca7b 100644 --- a/target/riscv/tcg/bitmanip_helper.c +++ b/target/riscv/tcg/bitmanip_helper.c @@ -52,21 +52,6 @@ target_ulong HELPER(clmulr)(target_ulong rs1, target_ulong rs2) return result; } -static inline target_ulong do_swap(target_ulong x, uint64_t mask, int shift) -{ - return ((x & mask) << shift) | ((x & ~mask) >> shift); -} - -target_ulong HELPER(brev8)(target_ulong rs1) -{ - target_ulong x = rs1; - - x = do_swap(x, 0x5555555555555555ull, 1); - x = do_swap(x, 0x3333333333333333ull, 2); - x = do_swap(x, 0x0f0f0f0f0f0f0f0full, 4); - return x; -} - static const uint64_t shuf_masks[] = { dup_const(MO_8, 0x44), dup_const(MO_8, 0x30), diff --git a/target/riscv/tcg/insn_trans/trans_rvb.c.inc b/target/riscv/tcg/insn_trans/trans_rvb.c.inc index e4dcc7c991..3e74be223b 100644 --- a/target/riscv/tcg/insn_trans/trans_rvb.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvb.c.inc @@ -522,7 +522,7 @@ static void gen_packw(TCGv ret, TCGv src1, TCGv src2) static bool trans_brev8(DisasContext *ctx, arg_brev8 *a) { REQUIRE_ZBKB(ctx); - return gen_unary(ctx, a, EXT_NONE, gen_helper_brev8); + return gen_unary(ctx, a, EXT_NONE, tcg_gen_revbit8_tl); } static bool trans_pack(DisasContext *ctx, arg_pack *a) From db1c58d777088b4c0de124c7b4d21d7b7d3adbab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 15:35:50 -0700 Subject: [PATCH 364/627] tcg: Add revbit{8,32,64} opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the plumbing, but not yet implemented for any host. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 16 ++++++++ include/tcg/tcg-opc.h | 3 ++ tcg/aarch64/tcg-target.c.inc | 12 ++++++ tcg/loongarch64/tcg-target.c.inc | 12 ++++++ tcg/ppc64/tcg-target.c.inc | 12 ++++++ tcg/riscv64/tcg-target.c.inc | 12 ++++++ tcg/s390x/tcg-target.c.inc | 12 ++++++ tcg/sparc64/tcg-target.c.inc | 12 ++++++ tcg/tcg-op.c | 66 +++++++++++++++++++++++++------- tcg/tcg.c | 7 ++++ tcg/tci/tcg-target.c.inc | 12 ++++++ tcg/x86_64/tcg-target.c.inc | 12 ++++++ 12 files changed, 174 insertions(+), 14 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 92ef127c80..f2e9255dd9 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -495,6 +495,22 @@ Misc into 32-bit output *t0*. Depending on the host, this may be a simple shift, or may require additional canonicalization. + * - revbit8 *dest*, *t1* + + - | Reverse the 8 bits within each byte of input *t1* with + | output in *dest*; the byte order is unchanged. + + * - revbit32 *dest*, *t1*, *flags* + + - | Reverse the 32 bits of the lower 32 bits of input *t1* + | with output in *dest*. On TCG_TYPE_I64, *flags* control + | any required sign or zero extension of the result in + | the same way as for bswap32. + | On TCG_TYPE_I32, *flags* should be zero. + + * - revbit64 *dest*, *t1* + + - | Reverse the 64 bits of input *t1* with output in *dest*. Conditional moves ----------------- diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 61f1c28858..13c7f17f76 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -79,6 +79,9 @@ DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) +DEF(revbit8, 1, 1, 0, TCG_OPF_INT) +DEF(revbit32, 1, 1, 1, TCG_OPF_INT) +DEF(revbit64, 1, 1, 0, TCG_OPF_INT) DEF(rotl, 1, 2, 0, TCG_OPF_INT) DEF(rotr, 1, 2, 0, TCG_OPF_INT) DEF(sar, 1, 2, 0, TCG_OPF_INT) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index cc9c2a5158..0afa988087 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2652,6 +2652,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_XZR, a1); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 182dcfd5eb..97ed51d99c 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1866,6 +1866,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); diff --git a/tcg/ppc64/tcg-target.c.inc b/tcg/ppc64/tcg-target.c.inc index b54afa0b6d..07dff67e84 100644 --- a/tcg/ppc64/tcg-target.c.inc +++ b/tcg/ppc64/tcg-target.c.inc @@ -3421,6 +3421,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out32(s, NEG | RT(a0) | RA(a1)); diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc index 76dd4fca97..687146e0b0 100644 --- a/tcg/riscv64/tcg-target.c.inc +++ b/tcg/riscv64/tcg-target.c.inc @@ -2469,6 +2469,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 84a9e73a46..c481745c3f 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3020,6 +3020,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { if (type == TCG_TYPE_I32) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 5e5c3f1cda..d6ed9d3362 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1947,6 +1947,18 @@ static const TCGOutOpUnary outop_bswap64 = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_G0, a1); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c24a7962fc..c302a484cd 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1270,15 +1270,26 @@ void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_revbit8_i32(TCGv_i32 ret, TCGv_i32 arg) { - gen_bitswap_i32(ret, arg, 0x55555555u); - gen_bitswap_i32(ret, ret, 0x33333333u); - gen_bitswap_i32(ret, ret, 0x0f0f0f0fu); + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I32, 0)) { + tcg_gen_op2_i32(INDEX_op_revbit8, ret, arg); + } else if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I32, 0)) { + tcg_gen_op2_i32(INDEX_op_revbit32, ret, arg); + tcg_gen_bswap32_i32(ret, ret); + } else { + gen_bitswap_i32(ret, arg, 0x55555555u); + gen_bitswap_i32(ret, ret, 0x33333333u); + gen_bitswap_i32(ret, ret, 0x0f0f0f0fu); + } } void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg) { - tcg_gen_revbit8_i32(ret, arg); - tcg_gen_bswap32_i32(ret, ret); + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I32, 0)) { + tcg_gen_op3i_i32(INDEX_op_revbit32, ret, arg, 0); + } else { + tcg_gen_revbit8_i32(ret, arg); + tcg_gen_bswap32_i32(ret, ret); + } } void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) @@ -1870,23 +1881,50 @@ void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) /* Only one extension flag may be present. */ tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); - gen_bitswap_i64(ret, arg, 0x55555555ull); - gen_bitswap_i64(ret, ret, 0x33333333ull); - gen_bitswap_i64(ret, ret, 0x0f0f0f0full); - tcg_gen_bswap32_i64(ret, ret, flags | TCG_BSWAP_IZ); + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_revbit32, ret, arg, flags); + } else if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg); + if (flags & TCG_BSWAP_OS) { + tcg_gen_sari_i64(ret, ret, 32); + } else { + tcg_gen_shri_i64(ret, ret, 32); + } + } else { + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_revbit8, ret, arg); + } else { + gen_bitswap_i64(ret, arg, 0x55555555ull); + gen_bitswap_i64(ret, ret, 0x33333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0full); + flags |= TCG_BSWAP_IZ; + } + tcg_gen_bswap32_i64(ret, ret, flags); + } } void tcg_gen_revbit8_i64(TCGv_i64 ret, TCGv_i64 arg) { - gen_bitswap_i64(ret, arg, 0x5555555555555555ull); - gen_bitswap_i64(ret, ret, 0x3333333333333333ull); - gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full); + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_revbit8, ret, arg); + } else if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg); + tcg_gen_bswap64_i64(ret, ret); + } else { + gen_bitswap_i64(ret, arg, 0x5555555555555555ull); + gen_bitswap_i64(ret, ret, 0x3333333333333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full); + } } void tcg_gen_revbit64_i64(TCGv_i64 ret, TCGv_i64 arg) { - tcg_gen_revbit8_i64(ret, arg); - tcg_gen_bswap64_i64(ret, ret); + if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg); + } else { + tcg_gen_revbit8_i64(ret, arg); + tcg_gen_bswap64_i64(ret, ret); + } } void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) diff --git a/tcg/tcg.c b/tcg/tcg.c index 937d0c8fd7..8a324ce885 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1203,6 +1203,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_qemu_st2, TCGOutOpQemuLdSt2, outop_qemu_st2), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_revbit32, TCGOutOpBswap, outop_revbit32), OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), @@ -1230,6 +1231,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u), OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s), + OUTOP(INDEX_op_revbit8, TCGOutOpUnary, outop_revbit8), + OUTOP(INDEX_op_revbit64, TCGOutOpUnary, outop_revbit64), OUTOP(INDEX_op_st32, TCGOutOpStore, outop_st), }; @@ -2950,6 +2953,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) case INDEX_op_bswap16: case INDEX_op_bswap32: case INDEX_op_bswap64: + case INDEX_op_revbit32: { TCGArg flags = op->args[k]; const char *name = NULL; @@ -5581,6 +5585,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_ctpop: case INDEX_op_neg: case INDEX_op_not: + case INDEX_op_revbit8: + case INDEX_op_revbit64: { const TCGOutOpUnary *out = container_of(all_outop[op->opc], TCGOutOpUnary, base); @@ -5593,6 +5599,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_bswap16: case INDEX_op_bswap32: + case INDEX_op_revbit32: { const TCGOutOpBswap *out = container_of(all_outop[op->opc], TCGOutOpBswap, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1b22c70616..1b61668517 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -959,6 +959,18 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); diff --git a/tcg/x86_64/tcg-target.c.inc b/tcg/x86_64/tcg-target.c.inc index 1fc45e4ec6..37acba9045 100644 --- a/tcg/x86_64/tcg-target.c.inc +++ b/tcg/x86_64/tcg-target.c.inc @@ -1290,6 +1290,18 @@ static inline void tcg_out_bswap64(TCGContext *s, int reg) tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0); } +static const TCGOutOpUnary outop_revbit8 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_arithi(TCGContext *s, int c, int r0, tcg_target_long val, int cf) { From d53c3e911c97c007995b79562ed695e5db0d8c29 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 15:36:35 -0700 Subject: [PATCH 365/627] tcg/optimize: Handle revbit{8,32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are nearly identical to bswap, so reuse fold_bswap. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 77 +++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index d12babad88..facf4c1e0f 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -534,6 +534,20 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, case INDEX_op_bswap64: return bswap64(x); + case INDEX_op_revbit8: + /* Note the host-utils.h revbit8 operates on uint8_t. */ + if (type == TCG_TYPE_I32) { + return bswap32(revbit32(x)); + } + return bswap64(revbit64(x)); + + case INDEX_op_revbit32: + x = revbit32(x); + return y & TCG_BSWAP_OS ? (int32_t)x : x; + + case INDEX_op_revbit64: + return revbit64(x); + case INDEX_op_ext_i32_i64: return (int32_t)x; @@ -1483,7 +1497,26 @@ static bool fold_bswap(OptContext *ctx, TCGOp *op) { uint64_t z_mask, o_mask, s_mask; TempOptInfo *t1 = arg_info(op->args[1]); - int flags = op->args[2]; + int flags = 0; + + switch (op->opc) { + case INDEX_op_bswap16: + flags = op->args[2]; + s_mask = INT16_MIN; + break; + case INDEX_op_bswap32: + case INDEX_op_revbit32: + flags = op->args[2]; + s_mask = INT32_MIN; + break; + case INDEX_op_bswap64: + case INDEX_op_revbit8: + case INDEX_op_revbit64: + s_mask = 0; + break; + default: + g_assert_not_reached(); + } if (ti_is_const(t1)) { return tcg_opt_gen_movi(ctx, op, op->args[0], @@ -1491,39 +1524,16 @@ static bool fold_bswap(OptContext *ctx, TCGOp *op) ti_const_val(t1), flags)); } - z_mask = t1->z_mask; - o_mask = t1->o_mask; - s_mask = 0; + z_mask = do_constant_folding(op->opc, ctx->type, t1->z_mask, flags); + o_mask = do_constant_folding(op->opc, ctx->type, t1->o_mask, flags); - switch (op->opc) { - case INDEX_op_bswap16: - z_mask = bswap16(z_mask); - o_mask = bswap16(o_mask); - if (flags & TCG_BSWAP_OS) { - z_mask = (int16_t)z_mask; - o_mask = (int16_t)o_mask; - s_mask = INT16_MIN; - } else if (!(flags & TCG_BSWAP_OZ)) { - z_mask |= MAKE_64BIT_MASK(16, 48); + if (flags & TCG_BSWAP_OS) { + /* s_mask set */ + } else { + if (!(flags & TCG_BSWAP_OZ)) { + z_mask |= s_mask << 1; } - break; - case INDEX_op_bswap32: - z_mask = bswap32(z_mask); - o_mask = bswap32(o_mask); - if (flags & TCG_BSWAP_OS) { - z_mask = (int32_t)z_mask; - o_mask = (int32_t)o_mask; - s_mask = INT32_MIN; - } else if (!(flags & TCG_BSWAP_OZ)) { - z_mask |= MAKE_64BIT_MASK(32, 32); - } - break; - case INDEX_op_bswap64: - z_mask = bswap64(z_mask); - o_mask = bswap64(o_mask); - break; - default: - g_assert_not_reached(); + s_mask = 0; } return fold_masks_zos(ctx, op, z_mask, o_mask, s_mask); @@ -3104,6 +3114,9 @@ void tcg_optimize(TCGContext *s) case INDEX_op_bswap16: case INDEX_op_bswap32: case INDEX_op_bswap64: + case INDEX_op_revbit8: + case INDEX_op_revbit32: + case INDEX_op_revbit64: done = fold_bswap(&ctx, op); break; case INDEX_op_clz: From a8687b8632a9dfe6dff094615e030480a950ffd0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 22:59:22 +0000 Subject: [PATCH 366/627] tcg/aarch64: Implement revbit{32,64} Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 0afa988087..80995403e4 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2656,12 +2656,28 @@ static const TCGOutOpUnary outop_revbit8 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_revbit32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_insn(s, rr_sf, RBIT, TCG_TYPE_I32, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, a0, a0); + } +} + static const TCGOutOpBswap outop_revbit32 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_revbit32, }; +static void tgen_revbit64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_insn(s, rr_sf, RBIT, TCG_TYPE_I64, a0, a1); +} + static const TCGOutOpUnary outop_revbit64 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_revbit64, }; static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) From 3e73eda07860439e1c0aae8d18f5cd880995990a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 16:33:52 -0700 Subject: [PATCH 367/627] tcg/loongarch64: Import REVBIT insns Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-insn-defs.c.inc | 960 +++++++++++++++------------- 1 file changed, 503 insertions(+), 457 deletions(-) diff --git a/tcg/loongarch64/tcg-insn-defs.c.inc b/tcg/loongarch64/tcg-insn-defs.c.inc index 6bb8656fd8..e907fc755f 100644 --- a/tcg/loongarch64/tcg-insn-defs.c.inc +++ b/tcg/loongarch64/tcg-insn-defs.c.inc @@ -4,7 +4,7 @@ * * This file is auto-generated by genqemutcgdefs from * https://github.com/loongson-community/loongarch-opcodes, - * from commit 7f353fb69bd99ce6edfad7ad63948c4bb526f0bf. + * from commit 1b95bb8c443ad71e266120fd97bd227df2d8ecfc. * DO NOT EDIT. */ @@ -18,6 +18,10 @@ typedef enum { OPC_REVB_2H = 0x00003000, OPC_REVB_2W = 0x00003800, OPC_REVB_D = 0x00003c00, + OPC_REVBIT_4B = 0x00004800, + OPC_REVBIT_8B = 0x00004c00, + OPC_REVBIT_W = 0x00005000, + OPC_REVBIT_D = 0x00005400, OPC_SEXT_H = 0x00005800, OPC_SEXT_B = 0x00005c00, OPC_ADD_W = 0x00100000, @@ -545,14 +549,14 @@ typedef enum { OPC_XVLDI = 0x77e00000, } LoongArchInsn; -static int32_t __attribute__((unused)) -encode_d_slot(LoongArchInsn opc, uint32_t d) +static int32_t __attribute__((unused)) encode_d_slot(LoongArchInsn opc, + uint32_t d) { return opc | d; } -static int32_t __attribute__((unused)) -encode_dj_slots(LoongArchInsn opc, uint32_t d, uint32_t j) +static int32_t __attribute__((unused)) encode_dj_slots(LoongArchInsn opc, + uint32_t d, uint32_t j) { return opc | d | j << 5; } @@ -563,43 +567,43 @@ encode_djk_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k) return opc | d | j << 5 | k << 10; } -static int32_t __attribute__((unused)) -encode_djka_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, - uint32_t a) +static int32_t __attribute__((unused)) encode_djka_slots(LoongArchInsn opc, + uint32_t d, uint32_t j, + uint32_t k, uint32_t a) { return opc | d | j << 5 | k << 10 | a << 15; } -static int32_t __attribute__((unused)) -encode_djkm_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, - uint32_t m) +static int32_t __attribute__((unused)) encode_djkm_slots(LoongArchInsn opc, + uint32_t d, uint32_t j, + uint32_t k, uint32_t m) { return opc | d | j << 5 | k << 10 | m << 16; } -static int32_t __attribute__((unused)) -encode_djkn_slots(LoongArchInsn opc, uint32_t d, uint32_t j, uint32_t k, - uint32_t n) +static int32_t __attribute__((unused)) encode_djkn_slots(LoongArchInsn opc, + uint32_t d, uint32_t j, + uint32_t k, uint32_t n) { return opc | d | j << 5 | k << 10 | n << 18; } -static int32_t __attribute__((unused)) -encode_dk_slots(LoongArchInsn opc, uint32_t d, uint32_t k) +static int32_t __attribute__((unused)) encode_dk_slots(LoongArchInsn opc, + uint32_t d, uint32_t k) { return opc | d | k << 10; } -static int32_t __attribute__((unused)) -encode_dfj_insn(LoongArchInsn opc, TCGReg d, TCGReg fj) +static int32_t __attribute__((unused)) encode_dfj_insn(LoongArchInsn opc, + TCGReg d, TCGReg fj) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(fj >= 0x20 && fj <= 0x3f); return encode_dj_slots(opc, d, fj & 0x1f); } -static int32_t __attribute__((unused)) -encode_dj_insn(LoongArchInsn opc, TCGReg d, TCGReg j) +static int32_t __attribute__((unused)) encode_dj_insn(LoongArchInsn opc, + TCGReg d, TCGReg j) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -669,9 +673,10 @@ encode_djuk5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5) return encode_djk_slots(opc, d, j, uk5); } -static int32_t __attribute__((unused)) -encode_djuk5um5_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk5, - uint32_t um5) +static int32_t __attribute__((unused)) encode_djuk5um5_insn(LoongArchInsn opc, + TCGReg d, TCGReg j, + uint32_t uk5, + uint32_t um5) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -689,9 +694,10 @@ encode_djuk6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6) return encode_djk_slots(opc, d, j, uk6); } -static int32_t __attribute__((unused)) -encode_djuk6um6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6, - uint32_t um6) +static int32_t __attribute__((unused)) encode_djuk6um6_insn(LoongArchInsn opc, + TCGReg d, TCGReg j, + uint32_t uk6, + uint32_t um6) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -700,16 +706,16 @@ encode_djuk6um6_insn(LoongArchInsn opc, TCGReg d, TCGReg j, uint32_t uk6, return encode_djkm_slots(opc, d, j, uk6, um6); } -static int32_t __attribute__((unused)) -encode_dsj20_insn(LoongArchInsn opc, TCGReg d, int32_t sj20) +static int32_t __attribute__((unused)) encode_dsj20_insn(LoongArchInsn opc, + TCGReg d, int32_t sj20) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(sj20 >= -0x80000 && sj20 <= 0x7ffff); return encode_dj_slots(opc, d, sj20 & 0xfffff); } -static int32_t __attribute__((unused)) -encode_dtj_insn(LoongArchInsn opc, TCGReg d, TCGReg tj) +static int32_t __attribute__((unused)) encode_dtj_insn(LoongArchInsn opc, + TCGReg d, TCGReg tj) { tcg_debug_assert(d >= 0 && d <= 0x1f); tcg_debug_assert(tj >= 0 && tj <= 0x3); @@ -770,16 +776,16 @@ encode_dxjuk3_insn(LoongArchInsn opc, TCGReg d, TCGReg xj, uint32_t uk3) return encode_djk_slots(opc, d, xj & 0x1f, uk3); } -static int32_t __attribute__((unused)) -encode_fdfj_insn(LoongArchInsn opc, TCGReg fd, TCGReg fj) +static int32_t __attribute__((unused)) encode_fdfj_insn(LoongArchInsn opc, + TCGReg fd, TCGReg fj) { tcg_debug_assert(fd >= 0x20 && fd <= 0x3f); tcg_debug_assert(fj >= 0x20 && fj <= 0x3f); return encode_dj_slots(opc, fd & 0x1f, fj & 0x1f); } -static int32_t __attribute__((unused)) -encode_fdj_insn(LoongArchInsn opc, TCGReg fd, TCGReg j) +static int32_t __attribute__((unused)) encode_fdj_insn(LoongArchInsn opc, + TCGReg fd, TCGReg j) { tcg_debug_assert(fd >= 0x20 && fd <= 0x3f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -804,37 +810,37 @@ encode_fdjsk12_insn(LoongArchInsn opc, TCGReg fd, TCGReg j, int32_t sk12) return encode_djk_slots(opc, fd & 0x1f, j, sk12 & 0xfff); } -static int32_t __attribute__((unused)) -encode_sd10k16_insn(LoongArchInsn opc, int32_t sd10k16) +static int32_t __attribute__((unused)) encode_sd10k16_insn(LoongArchInsn opc, + int32_t sd10k16) { tcg_debug_assert(sd10k16 >= -0x2000000 && sd10k16 <= 0x1ffffff); return encode_dk_slots(opc, (sd10k16 >> 16) & 0x3ff, sd10k16 & 0xffff); } -static int32_t __attribute__((unused)) -encode_sd5k16_insn(LoongArchInsn opc, int32_t sd5k16) +static int32_t __attribute__((unused)) encode_sd5k16_insn(LoongArchInsn opc, + int32_t sd5k16) { tcg_debug_assert(sd5k16 >= -0x100000 && sd5k16 <= 0xfffff); return encode_dk_slots(opc, (sd5k16 >> 16) & 0x1f, sd5k16 & 0xffff); } -static int32_t __attribute__((unused)) -encode_tdj_insn(LoongArchInsn opc, TCGReg td, TCGReg j) +static int32_t __attribute__((unused)) encode_tdj_insn(LoongArchInsn opc, + TCGReg td, TCGReg j) { tcg_debug_assert(td >= 0 && td <= 0x3); tcg_debug_assert(j >= 0 && j <= 0x1f); return encode_dj_slots(opc, td, j); } -static int32_t __attribute__((unused)) -encode_ud15_insn(LoongArchInsn opc, uint32_t ud15) +static int32_t __attribute__((unused)) encode_ud15_insn(LoongArchInsn opc, + uint32_t ud15) { tcg_debug_assert(ud15 <= 0x7fff); return encode_d_slot(opc, ud15); } -static int32_t __attribute__((unused)) -encode_vdj_insn(LoongArchInsn opc, TCGReg vd, TCGReg j) +static int32_t __attribute__((unused)) encode_vdj_insn(LoongArchInsn opc, + TCGReg vd, TCGReg j) { tcg_debug_assert(vd >= 0x20 && vd <= 0x3f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -974,8 +980,8 @@ encode_vdsj13_insn(LoongArchInsn opc, TCGReg vd, int32_t sj13) return encode_dj_slots(opc, vd & 0x1f, sj13 & 0x1fff); } -static int32_t __attribute__((unused)) -encode_vdvj_insn(LoongArchInsn opc, TCGReg vd, TCGReg vj) +static int32_t __attribute__((unused)) encode_vdvj_insn(LoongArchInsn opc, + TCGReg vd, TCGReg vj) { tcg_debug_assert(vd >= 0x20 && vd <= 0x3f); tcg_debug_assert(vj >= 0x20 && vj <= 0x3f); @@ -1083,8 +1089,8 @@ encode_vdvjvkva_insn(LoongArchInsn opc, TCGReg vd, TCGReg vj, TCGReg vk, return encode_djka_slots(opc, vd & 0x1f, vj & 0x1f, vk & 0x1f, va & 0x1f); } -static int32_t __attribute__((unused)) -encode_xdj_insn(LoongArchInsn opc, TCGReg xd, TCGReg j) +static int32_t __attribute__((unused)) encode_xdj_insn(LoongArchInsn opc, + TCGReg xd, TCGReg j) { tcg_debug_assert(xd >= 0x20 && xd <= 0x3f); tcg_debug_assert(j >= 0 && j <= 0x1f); @@ -1206,8 +1212,8 @@ encode_xdsj13_insn(LoongArchInsn opc, TCGReg xd, int32_t sj13) return encode_dj_slots(opc, xd & 0x1f, sj13 & 0x1fff); } -static int32_t __attribute__((unused)) -encode_xdxj_insn(LoongArchInsn opc, TCGReg xd, TCGReg xj) +static int32_t __attribute__((unused)) encode_xdxj_insn(LoongArchInsn opc, + TCGReg xd, TCGReg xj) { tcg_debug_assert(xd >= 0x20 && xd <= 0x3f); tcg_debug_assert(xj >= 0x20 && xj <= 0x3f); @@ -1316,523 +1322,555 @@ encode_xdxjxkxa_insn(LoongArchInsn opc, TCGReg xd, TCGReg xj, TCGReg xk, } /* Emits the `movgr2scr td, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_movgr2scr(TCGContext *s, TCGReg td, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_movgr2scr(TCGContext *s, + TCGReg td, TCGReg j) { tcg_out32(s, encode_tdj_insn(OPC_MOVGR2SCR, td, j)); } /* Emits the `movscr2gr d, tj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_movscr2gr(TCGContext *s, TCGReg d, TCGReg tj) +static void __attribute__((unused)) tcg_out_opc_movscr2gr(TCGContext *s, + TCGReg d, TCGReg tj) { tcg_out32(s, encode_dtj_insn(OPC_MOVSCR2GR, d, tj)); } /* Emits the `clz.w d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_clz_w(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_clz_w(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_CLZ_W, d, j)); } /* Emits the `ctz.w d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ctz_w(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_ctz_w(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_CTZ_W, d, j)); } /* Emits the `clz.d d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_clz_d(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_clz_d(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_CLZ_D, d, j)); } /* Emits the `ctz.d d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ctz_d(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_ctz_d(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_CTZ_D, d, j)); } /* Emits the `revb.2h d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_revb_2h(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_revb_2h(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_REVB_2H, d, j)); } /* Emits the `revb.2w d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_revb_2w(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_revb_2w(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_REVB_2W, d, j)); } /* Emits the `revb.d d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_revb_d(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_revb_d(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_REVB_D, d, j)); } +/* Emits the `revbit.4b d, j` instruction. */ +static void __attribute__((unused)) tcg_out_opc_revbit_4b(TCGContext *s, + TCGReg d, TCGReg j) +{ + tcg_out32(s, encode_dj_insn(OPC_REVBIT_4B, d, j)); +} + +/* Emits the `revbit.8b d, j` instruction. */ +static void __attribute__((unused)) tcg_out_opc_revbit_8b(TCGContext *s, + TCGReg d, TCGReg j) +{ + tcg_out32(s, encode_dj_insn(OPC_REVBIT_8B, d, j)); +} + +/* Emits the `revbit.w d, j` instruction. */ +static void __attribute__((unused)) tcg_out_opc_revbit_w(TCGContext *s, + TCGReg d, TCGReg j) +{ + tcg_out32(s, encode_dj_insn(OPC_REVBIT_W, d, j)); +} + +/* Emits the `revbit.d d, j` instruction. */ +static void __attribute__((unused)) tcg_out_opc_revbit_d(TCGContext *s, + TCGReg d, TCGReg j) +{ + tcg_out32(s, encode_dj_insn(OPC_REVBIT_D, d, j)); +} + /* Emits the `sext.h d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sext_h(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_sext_h(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_SEXT_H, d, j)); } /* Emits the `sext.b d, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sext_b(TCGContext *s, TCGReg d, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_sext_b(TCGContext *s, TCGReg d, + TCGReg j) { tcg_out32(s, encode_dj_insn(OPC_SEXT_B, d, j)); } /* Emits the `add.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_add_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_add_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ADD_W, d, j, k)); } /* Emits the `add.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_add_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_add_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ADD_D, d, j, k)); } /* Emits the `sub.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sub_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sub_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SUB_W, d, j, k)); } /* Emits the `sub.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sub_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sub_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SUB_D, d, j, k)); } /* Emits the `slt d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_slt(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_slt(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SLT, d, j, k)); } /* Emits the `sltu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sltu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sltu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SLTU, d, j, k)); } /* Emits the `maskeqz d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_maskeqz(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_maskeqz(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MASKEQZ, d, j, k)); } /* Emits the `masknez d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_masknez(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_masknez(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MASKNEZ, d, j, k)); } /* Emits the `nor d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_nor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_nor(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_NOR, d, j, k)); } /* Emits the `and d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_and(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_and(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_AND, d, j, k)); } /* Emits the `or d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_or(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_or(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_OR, d, j, k)); } /* Emits the `xor d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xor(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_xor(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_XOR, d, j, k)); } /* Emits the `orn d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_orn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_orn(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ORN, d, j, k)); } /* Emits the `andn d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_andn(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_andn(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ANDN, d, j, k)); } /* Emits the `sll.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sll_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sll_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SLL_W, d, j, k)); } /* Emits the `srl.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srl_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_srl_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SRL_W, d, j, k)); } /* Emits the `sra.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sra_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sra_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SRA_W, d, j, k)); } /* Emits the `sll.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sll_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sll_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SLL_D, d, j, k)); } /* Emits the `srl.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srl_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_srl_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SRL_D, d, j, k)); } /* Emits the `sra.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sra_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_sra_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_SRA_D, d, j, k)); } /* Emits the `rotr.b d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotr_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_rotr_b(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ROTR_B, d, j, k)); } /* Emits the `rotr.h d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotr_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_rotr_h(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ROTR_H, d, j, k)); } /* Emits the `rotr.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotr_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_rotr_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ROTR_W, d, j, k)); } /* Emits the `rotr.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotr_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_rotr_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_ROTR_D, d, j, k)); } /* Emits the `mul.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mul_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mul_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MUL_W, d, j, k)); } /* Emits the `mulh.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mulh_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mulh_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MULH_W, d, j, k)); } /* Emits the `mulh.wu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mulh_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mulh_wu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MULH_WU, d, j, k)); } /* Emits the `mul.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mul_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mul_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MUL_D, d, j, k)); } /* Emits the `mulh.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mulh_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mulh_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MULH_D, d, j, k)); } /* Emits the `mulh.du d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mulh_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mulh_du(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MULH_DU, d, j, k)); } /* Emits the `div.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_div_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_div_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_DIV_W, d, j, k)); } /* Emits the `mod.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mod_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mod_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MOD_W, d, j, k)); } /* Emits the `div.wu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_div_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_div_wu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_DIV_WU, d, j, k)); } /* Emits the `mod.wu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mod_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mod_wu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MOD_WU, d, j, k)); } /* Emits the `div.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_div_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_div_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_DIV_D, d, j, k)); } /* Emits the `mod.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mod_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mod_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MOD_D, d, j, k)); } /* Emits the `div.du d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_div_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_div_du(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_DIV_DU, d, j, k)); } /* Emits the `mod.du d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_mod_du(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_mod_du(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_MOD_DU, d, j, k)); } /* Emits the `slli.w d, j, uk5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_slli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) +static void __attribute__((unused)) tcg_out_opc_slli_w(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk5) { tcg_out32(s, encode_djuk5_insn(OPC_SLLI_W, d, j, uk5)); } /* Emits the `slli.d d, j, uk6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_slli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) +static void __attribute__((unused)) tcg_out_opc_slli_d(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk6) { tcg_out32(s, encode_djuk6_insn(OPC_SLLI_D, d, j, uk6)); } /* Emits the `srli.w d, j, uk5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srli_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) +static void __attribute__((unused)) tcg_out_opc_srli_w(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk5) { tcg_out32(s, encode_djuk5_insn(OPC_SRLI_W, d, j, uk5)); } /* Emits the `srli.d d, j, uk6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srli_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) +static void __attribute__((unused)) tcg_out_opc_srli_d(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk6) { tcg_out32(s, encode_djuk6_insn(OPC_SRLI_D, d, j, uk6)); } /* Emits the `srai.w d, j, uk5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srai_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) +static void __attribute__((unused)) tcg_out_opc_srai_w(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk5) { tcg_out32(s, encode_djuk5_insn(OPC_SRAI_W, d, j, uk5)); } /* Emits the `srai.d d, j, uk6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_srai_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) +static void __attribute__((unused)) tcg_out_opc_srai_d(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk6) { tcg_out32(s, encode_djuk6_insn(OPC_SRAI_D, d, j, uk6)); } /* Emits the `rotri.b d, j, uk3` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotri_b(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk3) +static void __attribute__((unused)) tcg_out_opc_rotri_b(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk3) { tcg_out32(s, encode_djuk3_insn(OPC_ROTRI_B, d, j, uk3)); } /* Emits the `rotri.h d, j, uk4` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotri_h(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk4) +static void __attribute__((unused)) tcg_out_opc_rotri_h(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk4) { tcg_out32(s, encode_djuk4_insn(OPC_ROTRI_H, d, j, uk4)); } /* Emits the `rotri.w d, j, uk5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotri_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5) +static void __attribute__((unused)) tcg_out_opc_rotri_w(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk5) { tcg_out32(s, encode_djuk5_insn(OPC_ROTRI_W, d, j, uk5)); } /* Emits the `rotri.d d, j, uk6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_rotri_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6) +static void __attribute__((unused)) tcg_out_opc_rotri_d(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk6) { tcg_out32(s, encode_djuk6_insn(OPC_ROTRI_D, d, j, uk6)); } /* Emits the `bstrins.w d, j, uk5, um5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bstrins_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, - uint32_t um5) +static void __attribute__((unused)) tcg_out_opc_bstrins_w(TCGContext *s, + TCGReg d, TCGReg j, + uint32_t uk5, + uint32_t um5) { tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRINS_W, d, j, uk5, um5)); } /* Emits the `bstrpick.w d, j, uk5, um5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bstrpick_w(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk5, - uint32_t um5) +static void __attribute__((unused)) tcg_out_opc_bstrpick_w(TCGContext *s, + TCGReg d, TCGReg j, + uint32_t uk5, + uint32_t um5) { tcg_out32(s, encode_djuk5um5_insn(OPC_BSTRPICK_W, d, j, uk5, um5)); } /* Emits the `bstrins.d d, j, uk6, um6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bstrins_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, - uint32_t um6) +static void __attribute__((unused)) tcg_out_opc_bstrins_d(TCGContext *s, + TCGReg d, TCGReg j, + uint32_t uk6, + uint32_t um6) { tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRINS_D, d, j, uk6, um6)); } /* Emits the `bstrpick.d d, j, uk6, um6` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bstrpick_d(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk6, - uint32_t um6) +static void __attribute__((unused)) tcg_out_opc_bstrpick_d(TCGContext *s, + TCGReg d, TCGReg j, + uint32_t uk6, + uint32_t um6) { tcg_out32(s, encode_djuk6um6_insn(OPC_BSTRPICK_D, d, j, uk6, um6)); } /* Emits the `fmov.d fd, fj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fmov_d(TCGContext *s, TCGReg fd, TCGReg fj) +static void __attribute__((unused)) tcg_out_opc_fmov_d(TCGContext *s, TCGReg fd, + TCGReg fj) { tcg_out32(s, encode_fdfj_insn(OPC_FMOV_D, fd, fj)); } /* Emits the `movgr2fr.d fd, j` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_movgr2fr_d(TCGContext *s, TCGReg fd, TCGReg j) +static void __attribute__((unused)) tcg_out_opc_movgr2fr_d(TCGContext *s, + TCGReg fd, TCGReg j) { tcg_out32(s, encode_fdj_insn(OPC_MOVGR2FR_D, fd, j)); } /* Emits the `movfr2gr.d d, fj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_movfr2gr_d(TCGContext *s, TCGReg d, TCGReg fj) +static void __attribute__((unused)) tcg_out_opc_movfr2gr_d(TCGContext *s, + TCGReg d, TCGReg fj) { tcg_out32(s, encode_dfj_insn(OPC_MOVFR2GR_D, d, fj)); } /* Emits the `slti d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_slti(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_slti(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_SLTI, d, j, sk12)); } /* Emits the `sltui d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_sltui(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_sltui(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_SLTUI, d, j, sk12)); } /* Emits the `addi.w d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_addi_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_addi_w(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ADDI_W, d, j, sk12)); } /* Emits the `addi.d d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_addi_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_addi_d(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ADDI_D, d, j, sk12)); } /* Emits the `cu52i.d d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_cu52i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_cu52i_d(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_CU52I_D, d, j, sk12)); } /* Emits the `andi d, j, uk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_andi(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) +static void __attribute__((unused)) tcg_out_opc_andi(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk12) { tcg_out32(s, encode_djuk12_insn(OPC_ANDI, d, j, uk12)); } /* Emits the `ori d, j, uk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) +static void __attribute__((unused)) tcg_out_opc_ori(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk12) { tcg_out32(s, encode_djuk12_insn(OPC_ORI, d, j, uk12)); } /* Emits the `xori d, j, uk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xori(TCGContext *s, TCGReg d, TCGReg j, uint32_t uk12) +static void __attribute__((unused)) tcg_out_opc_xori(TCGContext *s, TCGReg d, + TCGReg j, uint32_t uk12) { tcg_out32(s, encode_djuk12_insn(OPC_XORI, d, j, uk12)); } @@ -1845,9 +1883,9 @@ tcg_out_opc_vbitsel_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk, TCGReg va) } /* Emits the `xvbitsel.v xd, xj, xk, xa` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvbitsel_v(TCGContext *s, TCGReg xd, TCGReg xj, TCGReg xk, - TCGReg xa) +static void __attribute__((unused)) tcg_out_opc_xvbitsel_v(TCGContext *s, + TCGReg xd, TCGReg xj, + TCGReg xk, TCGReg xa) { tcg_out32(s, encode_xdxjxkxa_insn(OPC_XVBITSEL_V, xd, xj, xk, xa)); } @@ -1874,22 +1912,22 @@ tcg_out_opc_addu16i_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) } /* Emits the `lu12i.w d, sj20` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, int32_t sj20) +static void __attribute__((unused)) tcg_out_opc_lu12i_w(TCGContext *s, TCGReg d, + int32_t sj20) { tcg_out32(s, encode_dsj20_insn(OPC_LU12I_W, d, sj20)); } /* Emits the `cu32i.d d, sj20` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_cu32i_d(TCGContext *s, TCGReg d, int32_t sj20) +static void __attribute__((unused)) tcg_out_opc_cu32i_d(TCGContext *s, TCGReg d, + int32_t sj20) { tcg_out32(s, encode_dsj20_insn(OPC_CU32I_D, d, sj20)); } /* Emits the `pcaddu2i d, sj20` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_pcaddu2i(TCGContext *s, TCGReg d, int32_t sj20) +static void __attribute__((unused)) tcg_out_opc_pcaddu2i(TCGContext *s, + TCGReg d, int32_t sj20) { tcg_out32(s, encode_dsj20_insn(OPC_PCADDU2I, d, sj20)); } @@ -1916,134 +1954,134 @@ tcg_out_opc_pcaddu18i(TCGContext *s, TCGReg d, int32_t sj20) } /* Emits the `ld.b d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_b(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_B, d, j, sk12)); } /* Emits the `ld.h d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_h(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_H, d, j, sk12)); } /* Emits the `ld.w d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_w(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_W, d, j, sk12)); } /* Emits the `ld.d d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_d(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_D, d, j, sk12)); } /* Emits the `st.b d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_st_b(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_st_b(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ST_B, d, j, sk12)); } /* Emits the `st.h d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_st_h(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_st_h(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ST_H, d, j, sk12)); } /* Emits the `st.w d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_st_w(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_st_w(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ST_W, d, j, sk12)); } /* Emits the `st.d d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_st_d(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_st_d(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_ST_D, d, j, sk12)); } /* Emits the `ld.bu d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_bu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_bu(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_BU, d, j, sk12)); } /* Emits the `ld.hu d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_hu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_hu(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_HU, d, j, sk12)); } /* Emits the `ld.wu d, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ld_wu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_ld_wu(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_djsk12_insn(OPC_LD_WU, d, j, sk12)); } /* Emits the `fld.s fd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fld_s(TCGContext *s, TCGReg fd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_fld_s(TCGContext *s, TCGReg fd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_fdjsk12_insn(OPC_FLD_S, fd, j, sk12)); } /* Emits the `fst.s fd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fst_s(TCGContext *s, TCGReg fd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_fst_s(TCGContext *s, TCGReg fd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_fdjsk12_insn(OPC_FST_S, fd, j, sk12)); } /* Emits the `fld.d fd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fld_d(TCGContext *s, TCGReg fd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_fld_d(TCGContext *s, TCGReg fd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_fdjsk12_insn(OPC_FLD_D, fd, j, sk12)); } /* Emits the `fst.d fd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fst_d(TCGContext *s, TCGReg fd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_fst_d(TCGContext *s, TCGReg fd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_fdjsk12_insn(OPC_FST_D, fd, j, sk12)); } /* Emits the `vld vd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vld(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_vld(TCGContext *s, TCGReg vd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_vdjsk12_insn(OPC_VLD, vd, j, sk12)); } /* Emits the `vst vd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vst(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_vst(TCGContext *s, TCGReg vd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_vdjsk12_insn(OPC_VST, vd, j, sk12)); } /* Emits the `xvld xd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvld(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_xvld(TCGContext *s, TCGReg xd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_xdjsk12_insn(OPC_XVLD, xd, j, sk12)); } /* Emits the `xvst xd, j, sk12` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvst(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk12) +static void __attribute__((unused)) tcg_out_opc_xvst(TCGContext *s, TCGReg xd, + TCGReg j, int32_t sk12) { tcg_out32(s, encode_xdjsk12_insn(OPC_XVST, xd, j, sk12)); } @@ -2077,33 +2115,37 @@ tcg_out_opc_vldrepl_b(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk12) } /* Emits the `vstelm.d vd, j, sk8, un1` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vstelm_d(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk8, - uint32_t un1) +static void __attribute__((unused)) tcg_out_opc_vstelm_d(TCGContext *s, + TCGReg vd, TCGReg j, + int32_t sk8, + uint32_t un1) { tcg_out32(s, encode_vdjsk8un1_insn(OPC_VSTELM_D, vd, j, sk8, un1)); } /* Emits the `vstelm.w vd, j, sk8, un2` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vstelm_w(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk8, - uint32_t un2) +static void __attribute__((unused)) tcg_out_opc_vstelm_w(TCGContext *s, + TCGReg vd, TCGReg j, + int32_t sk8, + uint32_t un2) { tcg_out32(s, encode_vdjsk8un2_insn(OPC_VSTELM_W, vd, j, sk8, un2)); } /* Emits the `vstelm.h vd, j, sk8, un3` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vstelm_h(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk8, - uint32_t un3) +static void __attribute__((unused)) tcg_out_opc_vstelm_h(TCGContext *s, + TCGReg vd, TCGReg j, + int32_t sk8, + uint32_t un3) { tcg_out32(s, encode_vdjsk8un3_insn(OPC_VSTELM_H, vd, j, sk8, un3)); } /* Emits the `vstelm.b vd, j, sk8, un4` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vstelm_b(TCGContext *s, TCGReg vd, TCGReg j, int32_t sk8, - uint32_t un4) +static void __attribute__((unused)) tcg_out_opc_vstelm_b(TCGContext *s, + TCGReg vd, TCGReg j, + int32_t sk8, + uint32_t un4) { tcg_out32(s, encode_vdjsk8un4_insn(OPC_VSTELM_B, vd, j, sk8, un4)); } @@ -2137,306 +2179,310 @@ tcg_out_opc_xvldrepl_b(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk12) } /* Emits the `xvstelm.d xd, j, sk8, un2` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvstelm_d(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk8, - uint32_t un2) +static void __attribute__((unused)) tcg_out_opc_xvstelm_d(TCGContext *s, + TCGReg xd, TCGReg j, + int32_t sk8, + uint32_t un2) { tcg_out32(s, encode_xdjsk8un2_insn(OPC_XVSTELM_D, xd, j, sk8, un2)); } /* Emits the `xvstelm.w xd, j, sk8, un3` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvstelm_w(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk8, - uint32_t un3) +static void __attribute__((unused)) tcg_out_opc_xvstelm_w(TCGContext *s, + TCGReg xd, TCGReg j, + int32_t sk8, + uint32_t un3) { tcg_out32(s, encode_xdjsk8un3_insn(OPC_XVSTELM_W, xd, j, sk8, un3)); } /* Emits the `xvstelm.h xd, j, sk8, un4` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvstelm_h(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk8, - uint32_t un4) +static void __attribute__((unused)) tcg_out_opc_xvstelm_h(TCGContext *s, + TCGReg xd, TCGReg j, + int32_t sk8, + uint32_t un4) { tcg_out32(s, encode_xdjsk8un4_insn(OPC_XVSTELM_H, xd, j, sk8, un4)); } /* Emits the `xvstelm.b xd, j, sk8, un5` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvstelm_b(TCGContext *s, TCGReg xd, TCGReg j, int32_t sk8, - uint32_t un5) +static void __attribute__((unused)) tcg_out_opc_xvstelm_b(TCGContext *s, + TCGReg xd, TCGReg j, + int32_t sk8, + uint32_t un5) { tcg_out32(s, encode_xdjsk8un5_insn(OPC_XVSTELM_B, xd, j, sk8, un5)); } /* Emits the `ldx.b d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_b(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_B, d, j, k)); } /* Emits the `ldx.h d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_h(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_H, d, j, k)); } /* Emits the `ldx.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_W, d, j, k)); } /* Emits the `ldx.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_D, d, j, k)); } /* Emits the `stx.b d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_stx_b(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_stx_b(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_STX_B, d, j, k)); } /* Emits the `stx.h d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_stx_h(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_stx_h(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_STX_H, d, j, k)); } /* Emits the `stx.w d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_stx_w(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_stx_w(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_STX_W, d, j, k)); } /* Emits the `stx.d d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_stx_d(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_stx_d(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_STX_D, d, j, k)); } /* Emits the `ldx.bu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_bu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_bu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_BU, d, j, k)); } /* Emits the `ldx.hu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_hu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_hu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_HU, d, j, k)); } /* Emits the `ldx.wu d, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ldx_wu(TCGContext *s, TCGReg d, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_ldx_wu(TCGContext *s, TCGReg d, + TCGReg j, TCGReg k) { tcg_out32(s, encode_djk_insn(OPC_LDX_WU, d, j, k)); } /* Emits the `fldx.s fd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fldx_s(TCGContext *s, TCGReg fd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_fldx_s(TCGContext *s, TCGReg fd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_fdjk_insn(OPC_FLDX_S, fd, j, k)); } /* Emits the `fldx.d fd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fldx_d(TCGContext *s, TCGReg fd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_fldx_d(TCGContext *s, TCGReg fd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_fdjk_insn(OPC_FLDX_D, fd, j, k)); } /* Emits the `fstx.s fd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fstx_s(TCGContext *s, TCGReg fd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_fstx_s(TCGContext *s, TCGReg fd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_fdjk_insn(OPC_FSTX_S, fd, j, k)); } /* Emits the `fstx.d fd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_fstx_d(TCGContext *s, TCGReg fd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_fstx_d(TCGContext *s, TCGReg fd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_fdjk_insn(OPC_FSTX_D, fd, j, k)); } /* Emits the `vldx vd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vldx(TCGContext *s, TCGReg vd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_vldx(TCGContext *s, TCGReg vd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_vdjk_insn(OPC_VLDX, vd, j, k)); } /* Emits the `vstx vd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vstx(TCGContext *s, TCGReg vd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_vstx(TCGContext *s, TCGReg vd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_vdjk_insn(OPC_VSTX, vd, j, k)); } /* Emits the `xvldx xd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvldx(TCGContext *s, TCGReg xd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_xvldx(TCGContext *s, TCGReg xd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_xdjk_insn(OPC_XVLDX, xd, j, k)); } /* Emits the `xvstx xd, j, k` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvstx(TCGContext *s, TCGReg xd, TCGReg j, TCGReg k) +static void __attribute__((unused)) tcg_out_opc_xvstx(TCGContext *s, TCGReg xd, + TCGReg j, TCGReg k) { tcg_out32(s, encode_xdjk_insn(OPC_XVSTX, xd, j, k)); } /* Emits the `dbar ud15` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_dbar(TCGContext *s, uint32_t ud15) +static void __attribute__((unused)) tcg_out_opc_dbar(TCGContext *s, + uint32_t ud15) { tcg_out32(s, encode_ud15_insn(OPC_DBAR, ud15)); } /* Emits the `jiscr0 sd5k16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_jiscr0(TCGContext *s, int32_t sd5k16) +static void __attribute__((unused)) tcg_out_opc_jiscr0(TCGContext *s, + int32_t sd5k16) { tcg_out32(s, encode_sd5k16_insn(OPC_JISCR0, sd5k16)); } /* Emits the `jiscr1 sd5k16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_jiscr1(TCGContext *s, int32_t sd5k16) +static void __attribute__((unused)) tcg_out_opc_jiscr1(TCGContext *s, + int32_t sd5k16) { tcg_out32(s, encode_sd5k16_insn(OPC_JISCR1, sd5k16)); } /* Emits the `jirl d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_jirl(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_jirl(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_JIRL, d, j, sk16)); } /* Emits the `b sd10k16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_b(TCGContext *s, int32_t sd10k16) +static void __attribute__((unused)) tcg_out_opc_b(TCGContext *s, + int32_t sd10k16) { tcg_out32(s, encode_sd10k16_insn(OPC_B, sd10k16)); } /* Emits the `bl sd10k16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bl(TCGContext *s, int32_t sd10k16) +static void __attribute__((unused)) tcg_out_opc_bl(TCGContext *s, + int32_t sd10k16) { tcg_out32(s, encode_sd10k16_insn(OPC_BL, sd10k16)); } /* Emits the `beq d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_beq(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_beq(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BEQ, d, j, sk16)); } /* Emits the `bne d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bne(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_bne(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BNE, d, j, sk16)); } /* Emits the `bgt d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bgt(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_bgt(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BGT, d, j, sk16)); } /* Emits the `ble d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_ble(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_ble(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BLE, d, j, sk16)); } /* Emits the `bgtu d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bgtu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_bgtu(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BGTU, d, j, sk16)); } /* Emits the `bleu d, j, sk16` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_bleu(TCGContext *s, TCGReg d, TCGReg j, int32_t sk16) +static void __attribute__((unused)) tcg_out_opc_bleu(TCGContext *s, TCGReg d, + TCGReg j, int32_t sk16) { tcg_out32(s, encode_djsk16_insn(OPC_BLEU, d, j, sk16)); } /* Emits the `vseq.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vseq_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vseq_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSEQ_B, vd, vj, vk)); } /* Emits the `vseq.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vseq_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vseq_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSEQ_H, vd, vj, vk)); } /* Emits the `vseq.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vseq_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vseq_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSEQ_W, vd, vj, vk)); } /* Emits the `vseq.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vseq_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vseq_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSEQ_D, vd, vj, vk)); } /* Emits the `vsle.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsle_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsle_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLE_B, vd, vj, vk)); } /* Emits the `vsle.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsle_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsle_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLE_H, vd, vj, vk)); } /* Emits the `vsle.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsle_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsle_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLE_W, vd, vj, vk)); } /* Emits the `vsle.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsle_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsle_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLE_D, vd, vj, vk)); } @@ -2470,29 +2516,29 @@ tcg_out_opc_vsle_du(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) } /* Emits the `vslt.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vslt_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vslt_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLT_B, vd, vj, vk)); } /* Emits the `vslt.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vslt_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vslt_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLT_H, vd, vj, vk)); } /* Emits the `vslt.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vslt_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vslt_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLT_W, vd, vj, vk)); } /* Emits the `vslt.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vslt_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vslt_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLT_D, vd, vj, vk)); } @@ -2526,57 +2572,57 @@ tcg_out_opc_vslt_du(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) } /* Emits the `vadd.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vadd_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vadd_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VADD_B, vd, vj, vk)); } /* Emits the `vadd.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vadd_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vadd_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VADD_H, vd, vj, vk)); } /* Emits the `vadd.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vadd_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vadd_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VADD_W, vd, vj, vk)); } /* Emits the `vadd.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vadd_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vadd_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VADD_D, vd, vj, vk)); } /* Emits the `vsub.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsub_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsub_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSUB_B, vd, vj, vk)); } /* Emits the `vsub.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsub_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsub_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSUB_H, vd, vj, vk)); } /* Emits the `vsub.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsub_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsub_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSUB_W, vd, vj, vk)); } /* Emits the `vsub.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsub_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsub_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSUB_D, vd, vj, vk)); } @@ -2694,57 +2740,57 @@ tcg_out_opc_vssub_du(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) } /* Emits the `vmax.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmax_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmax_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMAX_B, vd, vj, vk)); } /* Emits the `vmax.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmax_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmax_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMAX_H, vd, vj, vk)); } /* Emits the `vmax.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmax_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmax_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMAX_W, vd, vj, vk)); } /* Emits the `vmax.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmax_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmax_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMAX_D, vd, vj, vk)); } /* Emits the `vmin.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmin_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmin_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMIN_B, vd, vj, vk)); } /* Emits the `vmin.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmin_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmin_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMIN_H, vd, vj, vk)); } /* Emits the `vmin.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmin_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmin_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMIN_W, vd, vj, vk)); } /* Emits the `vmin.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmin_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmin_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMIN_D, vd, vj, vk)); } @@ -2806,113 +2852,113 @@ tcg_out_opc_vmin_du(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) } /* Emits the `vmul.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmul_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmul_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMUL_B, vd, vj, vk)); } /* Emits the `vmul.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmul_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmul_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMUL_H, vd, vj, vk)); } /* Emits the `vmul.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmul_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmul_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMUL_W, vd, vj, vk)); } /* Emits the `vmul.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vmul_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vmul_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VMUL_D, vd, vj, vk)); } /* Emits the `vsll.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsll_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsll_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLL_B, vd, vj, vk)); } /* Emits the `vsll.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsll_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsll_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLL_H, vd, vj, vk)); } /* Emits the `vsll.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsll_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsll_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLL_W, vd, vj, vk)); } /* Emits the `vsll.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsll_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsll_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSLL_D, vd, vj, vk)); } /* Emits the `vsrl.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsrl_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsrl_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRL_B, vd, vj, vk)); } /* Emits the `vsrl.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsrl_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsrl_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRL_H, vd, vj, vk)); } /* Emits the `vsrl.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsrl_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsrl_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRL_W, vd, vj, vk)); } /* Emits the `vsrl.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsrl_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsrl_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRL_D, vd, vj, vk)); } /* Emits the `vsra.b vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsra_b(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsra_b(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRA_B, vd, vj, vk)); } /* Emits the `vsra.h vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsra_h(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsra_h(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRA_H, vd, vj, vk)); } /* Emits the `vsra.w vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsra_w(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsra_w(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRA_W, vd, vj, vk)); } /* Emits the `vsra.d vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vsra_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vsra_d(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VSRA_D, vd, vj, vk)); } @@ -2974,29 +3020,29 @@ tcg_out_opc_vreplve_d(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg k) } /* Emits the `vand.v vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vand_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vand_v(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VAND_V, vd, vj, vk)); } /* Emits the `vor.v vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vor_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vor_v(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VOR_V, vd, vj, vk)); } /* Emits the `vxor.v vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vxor_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vxor_v(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VXOR_V, vd, vj, vk)); } /* Emits the `vnor.v vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vnor_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vnor_v(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VNOR_V, vd, vj, vk)); } @@ -3009,8 +3055,8 @@ tcg_out_opc_vandn_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) } /* Emits the `vorn.v vd, vj, vk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vorn_v(TCGContext *s, TCGReg vd, TCGReg vj, TCGReg vk) +static void __attribute__((unused)) tcg_out_opc_vorn_v(TCGContext *s, TCGReg vd, + TCGReg vj, TCGReg vk) { tcg_out32(s, encode_vdvjvk_insn(OPC_VORN_V, vd, vj, vk)); } @@ -3324,29 +3370,29 @@ tcg_out_opc_vmini_du(TCGContext *s, TCGReg vd, TCGReg vj, uint32_t uk5) } /* Emits the `vneg.b vd, vj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vneg_b(TCGContext *s, TCGReg vd, TCGReg vj) +static void __attribute__((unused)) tcg_out_opc_vneg_b(TCGContext *s, TCGReg vd, + TCGReg vj) { tcg_out32(s, encode_vdvj_insn(OPC_VNEG_B, vd, vj)); } /* Emits the `vneg.h vd, vj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vneg_h(TCGContext *s, TCGReg vd, TCGReg vj) +static void __attribute__((unused)) tcg_out_opc_vneg_h(TCGContext *s, TCGReg vd, + TCGReg vj) { tcg_out32(s, encode_vdvj_insn(OPC_VNEG_H, vd, vj)); } /* Emits the `vneg.w vd, vj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vneg_w(TCGContext *s, TCGReg vd, TCGReg vj) +static void __attribute__((unused)) tcg_out_opc_vneg_w(TCGContext *s, TCGReg vd, + TCGReg vj) { tcg_out32(s, encode_vdvj_insn(OPC_VNEG_W, vd, vj)); } /* Emits the `vneg.d vd, vj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vneg_d(TCGContext *s, TCGReg vd, TCGReg vj) +static void __attribute__((unused)) tcg_out_opc_vneg_d(TCGContext *s, TCGReg vd, + TCGReg vj) { tcg_out32(s, encode_vdvj_insn(OPC_VNEG_D, vd, vj)); } @@ -3702,8 +3748,8 @@ tcg_out_opc_vandi_b(TCGContext *s, TCGReg vd, TCGReg vj, uint32_t uk8) } /* Emits the `vori.b vd, vj, uk8` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vori_b(TCGContext *s, TCGReg vd, TCGReg vj, uint32_t uk8) +static void __attribute__((unused)) tcg_out_opc_vori_b(TCGContext *s, TCGReg vd, + TCGReg vj, uint32_t uk8) { tcg_out32(s, encode_vdvjuk8_insn(OPC_VORI_B, vd, vj, uk8)); } @@ -3723,8 +3769,8 @@ tcg_out_opc_vnori_b(TCGContext *s, TCGReg vd, TCGReg vj, uint32_t uk8) } /* Emits the `vldi vd, sj13` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_vldi(TCGContext *s, TCGReg vd, int32_t sj13) +static void __attribute__((unused)) tcg_out_opc_vldi(TCGContext *s, TCGReg vd, + int32_t sj13) { tcg_out32(s, encode_vdsj13_insn(OPC_VLDI, vd, sj13)); } @@ -4325,8 +4371,8 @@ tcg_out_opc_xvand_v(TCGContext *s, TCGReg xd, TCGReg xj, TCGReg xk) } /* Emits the `xvor.v xd, xj, xk` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvor_v(TCGContext *s, TCGReg xd, TCGReg xj, TCGReg xk) +static void __attribute__((unused)) tcg_out_opc_xvor_v(TCGContext *s, TCGReg xd, + TCGReg xj, TCGReg xk) { tcg_out32(s, encode_xdxjxk_insn(OPC_XVOR_V, xd, xj, xk)); } @@ -4668,29 +4714,29 @@ tcg_out_opc_xvmini_du(TCGContext *s, TCGReg xd, TCGReg xj, uint32_t uk5) } /* Emits the `xvneg.b xd, xj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvneg_b(TCGContext *s, TCGReg xd, TCGReg xj) +static void __attribute__((unused)) tcg_out_opc_xvneg_b(TCGContext *s, + TCGReg xd, TCGReg xj) { tcg_out32(s, encode_xdxj_insn(OPC_XVNEG_B, xd, xj)); } /* Emits the `xvneg.h xd, xj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvneg_h(TCGContext *s, TCGReg xd, TCGReg xj) +static void __attribute__((unused)) tcg_out_opc_xvneg_h(TCGContext *s, + TCGReg xd, TCGReg xj) { tcg_out32(s, encode_xdxj_insn(OPC_XVNEG_H, xd, xj)); } /* Emits the `xvneg.w xd, xj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvneg_w(TCGContext *s, TCGReg xd, TCGReg xj) +static void __attribute__((unused)) tcg_out_opc_xvneg_w(TCGContext *s, + TCGReg xd, TCGReg xj) { tcg_out32(s, encode_xdxj_insn(OPC_XVNEG_W, xd, xj)); } /* Emits the `xvneg.d xd, xj` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvneg_d(TCGContext *s, TCGReg xd, TCGReg xj) +static void __attribute__((unused)) tcg_out_opc_xvneg_d(TCGContext *s, + TCGReg xd, TCGReg xj) { tcg_out32(s, encode_xdxj_insn(OPC_XVNEG_D, xd, xj)); } @@ -5060,8 +5106,8 @@ tcg_out_opc_xvnori_b(TCGContext *s, TCGReg xd, TCGReg xj, uint32_t uk8) } /* Emits the `xvldi xd, sj13` instruction. */ -static void __attribute__((unused)) -tcg_out_opc_xvldi(TCGContext *s, TCGReg xd, int32_t sj13) +static void __attribute__((unused)) tcg_out_opc_xvldi(TCGContext *s, TCGReg xd, + int32_t sj13) { tcg_out32(s, encode_xdsj13_insn(OPC_XVLDI, xd, sj13)); } From fa70120a71e51358523a1c1d6321a884def054af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 Jul 2026 23:52:07 +0000 Subject: [PATCH 368/627] tcg/loongarch64: Implement revbit{8,32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 34 +++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 97ed51d99c..7d89e80886 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1866,16 +1866,44 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static void tgen_revbit8(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_revbit_4b(s, a0, a1); + } else { + tcg_out_opc_revbit_8b(s, a0, a1); + } +} + static const TCGOutOpUnary outop_revbit8 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_revbit8; }; +static void tgen_revbit32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_opc_revbit_w(s, a0, a1); + + /* All 32-bit values are computed sign-extended in the register. */ + if (type == TCG_TYPE_I64 && (flags & TCG_BSWAP_OZ)) { + tcg_out_ext32u(s, a0, a0); + } +} + static const TCGOutOpBswap outop_revbit32 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_revbit32, }; +static void tgen_revbit64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_revbit_d(s, a0, a1); +} + static const TCGOutOpUnary outop_revbit64 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_revbit64, }; static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) From 48c18cdc9c9f9beadc204895a85870bddf237f2f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 11:45:59 -0700 Subject: [PATCH 369/627] util/cpuinfo-riscv: Detect Zbkb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RISCV_HWPROBE_EXT_ZBKB was introduced in linux 6.10 with the rest of the hwprobe api. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- host/include/riscv64/host/cpuinfo.h | 1 + util/cpuinfo-riscv.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/host/include/riscv64/host/cpuinfo.h b/host/include/riscv64/host/cpuinfo.h index b2b53dbf62..1f047051a3 100644 --- a/host/include/riscv64/host/cpuinfo.h +++ b/host/include/riscv64/host/cpuinfo.h @@ -12,6 +12,7 @@ #define CPUINFO_ZBS (1u << 3) #define CPUINFO_ZICOND (1u << 4) #define CPUINFO_ZVE64X (1u << 5) +#define CPUINFO_ZBKB (1u << 6) /* Initialized with a constructor. */ extern unsigned cpuinfo; diff --git a/util/cpuinfo-riscv.c b/util/cpuinfo-riscv.c index 0291b7218a..8c48b1ea91 100644 --- a/util/cpuinfo-riscv.c +++ b/util/cpuinfo-riscv.c @@ -36,7 +36,7 @@ static void sigill_handler(int signo, siginfo_t *si, void *data) /* Called both as constructor and (possibly) via other constructors. */ unsigned __attribute__((constructor)) cpuinfo_init(void) { - unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZBS + unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZBS | CPUINFO_ZBKB | CPUINFO_ZICOND | CPUINFO_ZVE64X; unsigned info = cpuinfo; @@ -60,6 +60,9 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) #if defined(__riscv_arch_test) && \ (defined(__riscv_vector) || defined(__riscv_zve64x)) info |= CPUINFO_ZVE64X; +#endif +#if defined(__riscv_arch_test) && defined(__riscv_zbkb) + info |= CPUINFO_ZBKB; #endif left &= ~info; @@ -76,7 +79,8 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0; info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0; info |= pair.value & RISCV_HWPROBE_EXT_ZBS ? CPUINFO_ZBS : 0; - left &= ~(CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZBS); + info |= pair.value & RISCV_HWPROBE_EXT_ZBKB ? CPUINFO_ZBKB : 0; + left &= ~(CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZBS | CPUINFO_ZBKB); #ifdef RISCV_HWPROBE_EXT_ZICOND info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0; left &= ~CPUINFO_ZICOND; @@ -131,6 +135,15 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) left &= ~CPUINFO_ZBS; } + if (left & CPUINFO_ZBKB) { + /* Probe for Zbkb: brev8 zero,zero. */ + got_sigill = 0; + asm volatile(".insn i 0x13, 5, zero, zero, 0x687" + : : : "memory"); + info |= got_sigill ? 0 : CPUINFO_ZBKB; + left &= ~CPUINFO_ZBKB; + } + if (left & CPUINFO_ZICOND) { /* Probe for Zicond: czero.eqz zero,zero,zero. */ got_sigill = 0; From 9d2e171fd606dc7c7b93bd8648a40e3cf745b22a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 11:55:09 -0700 Subject: [PATCH 370/627] tcg/riscv64: Implement revbit8 Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson --- tcg/riscv64/tcg-target.c.inc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc index 687146e0b0..8fd32644fe 100644 --- a/tcg/riscv64/tcg-target.c.inc +++ b/tcg/riscv64/tcg-target.c.inc @@ -246,6 +246,9 @@ typedef enum { OPC_XNOR = 0x40004033, OPC_ZEXT_H = 0x0800403b, + /* Zbkb: Bit Manipulation for Cryptography */ + OPC_BREV8 = 0x68705013, + /* Zicond: integer conditional operations */ OPC_CZERO_EQZ = 0x0e005033, OPC_CZERO_NEZ = 0x0e007033, @@ -2469,8 +2472,20 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static TCGConstraintSetIndex cset_revbit8(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBKB ? C_O1_I1(r, r) : C_NotImplemented; +} + +static void tgen_revbit8(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_imm(s, OPC_BREV8, a0, a1, 0); +} + static const TCGOutOpUnary outop_revbit8 = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_revbit8, + .out_rr = tgen_revbit8, }; static const TCGOutOpBswap outop_revbit32 = { From 2458f0cab5aaa21117f2a151e2f4f1e7d4f9d0ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 12:26:57 -0700 Subject: [PATCH 371/627] tests/tcg/loongarch64: Tidy test_bit.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use one macro for all test templates. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tests/tcg/loongarch64/test_bit.c | 69 +++++++------------------------- 1 file changed, 15 insertions(+), 54 deletions(-) diff --git a/tests/tcg/loongarch64/test_bit.c b/tests/tcg/loongarch64/test_bit.c index a6d9904909..69b2eaac78 100644 --- a/tests/tcg/loongarch64/test_bit.c +++ b/tests/tcg/loongarch64/test_bit.c @@ -2,62 +2,23 @@ #include #define ARRAY_SIZE(X) (sizeof(X) / sizeof(*(X))) -#define TEST_CLO(N) \ -static uint64_t test_clo_##N(uint64_t rj) \ -{ \ - uint64_t rd = 0; \ - \ - asm volatile("clo."#N" %0, %1\n\t" \ - : "=r"(rd) \ - : "r"(rj) \ - : ); \ - return rd; \ + +#define TEST(C, I) \ +static uint64_t test_##C(uint64_t rj) \ +{ \ + uint64_t rd; \ + asm volatile(I " %0, %1\n\t" : "=r"(rd) : "r"(rj)); \ + return rd; \ } -#define TEST_CLZ(N) \ -static uint64_t test_clz_##N(uint64_t rj) \ -{ \ - uint64_t rd = 0; \ - \ - asm volatile("clz."#N" %0, %1\n\t" \ - : "=r"(rd) \ - : "r"(rj) \ - : ); \ - return rd; \ -} - -#define TEST_CTO(N) \ -static uint64_t test_cto_##N(uint64_t rj) \ -{ \ - uint64_t rd = 0; \ - \ - asm volatile("cto."#N" %0, %1\n\t" \ - : "=r"(rd) \ - : "r"(rj) \ - : ); \ - return rd; \ -} - -#define TEST_CTZ(N) \ -static uint64_t test_ctz_##N(uint64_t rj) \ -{ \ - uint64_t rd = 0; \ - \ - asm volatile("ctz."#N" %0, %1\n\t" \ - : "=r"(rd) \ - : "r"(rj) \ - : ); \ - return rd; \ -} - -TEST_CLO(w) -TEST_CLO(d) -TEST_CLZ(w) -TEST_CLZ(d) -TEST_CTO(w) -TEST_CTO(d) -TEST_CTZ(w) -TEST_CTZ(d) +TEST(clo_w, "clo.w") +TEST(clo_d, "clo.d") +TEST(clz_w, "clz.w") +TEST(clz_d, "clz.d") +TEST(cto_w, "cto.w") +TEST(cto_d, "cto.d") +TEST(ctz_w, "ctz.w") +TEST(ctz_d, "ctz.d") struct vector { uint64_t (*func)(uint64_t); From ffc27ce9be6751a12c30f9a913d1f41003a74962 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Aug 2026 12:42:54 -0700 Subject: [PATCH 372/627] tests/tcg/loongarch64: Add bitrev smoke tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tests/tcg/loongarch64/test_bit.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/tcg/loongarch64/test_bit.c b/tests/tcg/loongarch64/test_bit.c index 69b2eaac78..65cd6598c9 100644 --- a/tests/tcg/loongarch64/test_bit.c +++ b/tests/tcg/loongarch64/test_bit.c @@ -19,6 +19,10 @@ TEST(cto_w, "cto.w") TEST(cto_d, "cto.d") TEST(ctz_w, "ctz.w") TEST(ctz_d, "ctz.d") +TEST(bitrev_4b, "bitrev.4b") +TEST(bitrev_8b, "bitrev.8b") +TEST(bitrev_w, "bitrev.w") +TEST(bitrev_d, "bitrev.d") struct vector { uint64_t (*func)(uint64_t); @@ -35,6 +39,10 @@ static struct vector vectors[] = { {test_cto_d, 0xabd28a64000000, 0}, {test_ctz_w, 0xfaffff42392476ab, 0}, {test_ctz_d, 0xabd28a64000000, 26}, + {test_bitrev_4b, 0xdeadbeef11223344, 0xffffffff8844cc22}, + {test_bitrev_8b, 0x1122334455667788, 0x8844cc22aa66ee11}, + {test_bitrev_w, 0xdeadbeef89abcdef, 0xfffffffff7b3d591}, + {test_bitrev_d, 0x0123456789abcdef, 0xf7b3d591e6a2c480}, }; int main() From 90aa356edcf1d7c1d4453269a0a8b0e667aa964f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 15:06:36 -0700 Subject: [PATCH 373/627] tcg: Add integer min/max opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have these for vectors; replicate for integers. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 12 ++++++++ include/tcg/tcg-opc.h | 4 +++ tcg/aarch64/tcg-target.c.inc | 16 +++++++++++ tcg/loongarch64/tcg-target.c.inc | 16 +++++++++++ tcg/ppc64/tcg-target.c.inc | 16 +++++++++++ tcg/riscv64/tcg-target.c.inc | 16 +++++++++++ tcg/s390x/tcg-target.c.inc | 16 +++++++++++ tcg/sparc64/tcg-target.c.inc | 16 +++++++++++ tcg/tcg-op.c | 48 ++++++++++++++++++++++++++------ tcg/tcg.c | 8 ++++++ tcg/tci/tcg-target.c.inc | 16 +++++++++++ tcg/x86_64/tcg-target.c.inc | 16 +++++++++++ 12 files changed, 192 insertions(+), 8 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index f2e9255dd9..88d48a1f99 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -317,6 +317,18 @@ Arithmetic pass 0 to *nh* to make a simple zero-extension of *nl*, so overflow should never occur. + * - smax *t0*, *t1*, *t2* + + umax *t0*, *t1*, *t2* + + - | *t0* = MAX(*t1*, *t2*), for signed and unsigned integers. + + * - smin *t0*, *t1*, *t2* + + umin *t0*, *t1*, *t2* + + - | *t0* = MIN(*t1*, *t2*), for signed and unsigned integers. + Logical ------- diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 13c7f17f76..f3a81d5d7f 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -89,11 +89,15 @@ DEF(setcond, 1, 2, 1, TCG_OPF_INT) DEF(sextract, 1, 1, 2, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) +DEF(smax, 1, 2, 0, TCG_OPF_INT) +DEF(smin, 1, 2, 0, TCG_OPF_INT) DEF(st8, 0, 2, 1, TCG_OPF_INT) DEF(st16, 0, 2, 1, TCG_OPF_INT) DEF(st32, 0, 2, 1, TCG_OPF_INT) DEF(st, 0, 2, 1, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) +DEF(umax, 1, 2, 0, TCG_OPF_INT) +DEF(umin, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) DEF(addco, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 80995403e4..f5c185bbf4 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2592,6 +2592,22 @@ static void tcg_out_set_borrow(TCGContext *s) TCG_REG_XZR, TCG_REG_XZR, TCG_REG_XZR); } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 7d89e80886..f65496a040 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1804,6 +1804,22 @@ static void tcg_out_set_borrow(TCGContext *s) g_assert_not_reached(); } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc64/tcg-target.c.inc b/tcg/ppc64/tcg-target.c.inc index 07dff67e84..cd1c234367 100644 --- a/tcg/ppc64/tcg-target.c.inc +++ b/tcg/ppc64/tcg-target.c.inc @@ -3281,6 +3281,22 @@ static void tcg_out_set_borrow(TCGContext *s) tcg_out32(s, ADDIC | TAI(TCG_REG_R0, TCG_REG_R0, 0)); } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc index 8fd32644fe..723c21b3da 100644 --- a/tcg/riscv64/tcg-target.c.inc +++ b/tcg/riscv64/tcg-target.c.inc @@ -2404,6 +2404,22 @@ static void tcg_out_set_borrow(TCGContext *s) g_assert_not_reached(); } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index c481745c3f..4d1a779c47 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2950,6 +2950,22 @@ static void tcg_out_set_borrow(TCGContext *s) tcg_out_insn(s, RR, CLR, TCG_REG_R0, TCG_REG_R0); /* cc = 0 */ } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d6ed9d3362..35cd14a5b6 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1917,6 +1917,22 @@ static void tcg_out_set_borrow(TCGContext *s) tcg_out_set_carry(s); /* borrow == carry */ } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c302a484cd..e28944cf72 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1294,22 +1294,38 @@ void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { - tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); + if (tcg_op_supported(INDEX_op_smin, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_smin, ret, a, b); + } else { + tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, a, b); + } } void tcg_gen_umin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { - tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, a, b); + if (tcg_op_supported(INDEX_op_umin, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_umin, ret, a, b); + } else { + tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, a, b); + } } void tcg_gen_smax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { - tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, b, a); + if (tcg_op_supported(INDEX_op_smax, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_smax, ret, a, b); + } else { + tcg_gen_movcond_i32(TCG_COND_LT, ret, a, b, b, a); + } } void tcg_gen_umax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { - tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, b, a); + if (tcg_op_supported(INDEX_op_umax, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_umax, ret, a, b); + } else { + tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, b, a); + } } void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) @@ -2473,22 +2489,38 @@ void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_smin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) { - tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, a, b); + if (tcg_op_supported(INDEX_op_smin, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_smin, ret, a, b); + } else { + tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, a, b); + } } void tcg_gen_umin_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) { - tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, a, b); + if (tcg_op_supported(INDEX_op_umin, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_umin, ret, a, b); + } else { + tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, a, b); + } } void tcg_gen_smax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) { - tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, b, a); + if (tcg_op_supported(INDEX_op_smax, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_smax, ret, a, b); + } else { + tcg_gen_movcond_i64(TCG_COND_LT, ret, a, b, b, a); + } } void tcg_gen_umax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) { - tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, b, a); + if (tcg_op_supported(INDEX_op_umax, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_umax, ret, a, b); + } else { + tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, b, a); + } } void tcg_gen_abs_i64(TCGv_i64 ret, TCGv_i64 a) diff --git a/tcg/tcg.c b/tcg/tcg.c index 8a324ce885..489df0e738 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1211,6 +1211,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_sextract, TCGOutOpExtract, outop_sextract), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), + OUTOP(INDEX_op_smax, TCGOutOpBinary, outop_smax), + OUTOP(INDEX_op_smin, TCGOutOpBinary, outop_smin), OUTOP(INDEX_op_st, TCGOutOpStore, outop_st), OUTOP(INDEX_op_st8, TCGOutOpStore, outop_st8), OUTOP(INDEX_op_st16, TCGOutOpStore, outop_st16), @@ -1220,6 +1222,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_subbo, TCGOutOpAddSubCarry, outop_subbo), /* subb1o is implemented with set_borrow + subbio */ OUTOP(INDEX_op_subb1o, TCGOutOpAddSubCarry, outop_subbio), + OUTOP(INDEX_op_umax, TCGOutOpBinary, outop_umax), + OUTOP(INDEX_op_umin, TCGOutOpBinary, outop_umin), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), [INDEX_op_goto_ptr] = &outop_goto_ptr, @@ -5518,6 +5522,10 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: + case INDEX_op_smax: + case INDEX_op_smin: + case INDEX_op_umax: + case INDEX_op_umin: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1b61668517..4cd1c1431c 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -894,6 +894,22 @@ static void tcg_out_set_borrow(TCGContext *s) tcg_out_op_v(s, INDEX_op_tci_setcarry); /* borrow == carry */ } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/x86_64/tcg-target.c.inc b/tcg/x86_64/tcg-target.c.inc index 37acba9045..2c8f1f3e58 100644 --- a/tcg/x86_64/tcg-target.c.inc +++ b/tcg/x86_64/tcg-target.c.inc @@ -2977,6 +2977,22 @@ static void tcg_out_set_borrow(TCGContext *s) tcg_out8(s, OPC_STC); } +static const TCGOutOpBinary outop_smax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_smin = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umax = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_umin = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From db9be9b136cb5a68e8d545d87e9ee3afbb6bbe0d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 15:42:35 -0700 Subject: [PATCH 374/627] tcg/optimize: Handle min/max opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index facf4c1e0f..d291c844ca 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -597,6 +597,30 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (uint64_t)x % ((uint64_t)y ? : 1); + case INDEX_op_smax: + if (type == TCG_TYPE_I32) { + return MAX((int32_t)x, (int32_t)y); + } + return MAX((int64_t)x, (int64_t)y); + + case INDEX_op_smin: + if (type == TCG_TYPE_I32) { + return MIN((int32_t)x, (int32_t)y); + } + return MIN((int64_t)x, (int64_t)y); + + case INDEX_op_umax: + if (type == TCG_TYPE_I32) { + return MAX((uint32_t)x, (uint32_t)y); + } + return MAX((uint64_t)x, (uint64_t)y); + + case INDEX_op_umin: + if (type == TCG_TYPE_I32) { + return MIN((uint32_t)x, (uint32_t)y); + } + return MIN((uint64_t)x, (uint64_t)y); + default: g_assert_not_reached(); } @@ -2101,6 +2125,16 @@ static bool fold_mb(OptContext *ctx, TCGOp *op) return true; } +static bool fold_minmax(OptContext *ctx, TCGOp *op, uint64_t bound) +{ + if (fold_const2_commutative(ctx, op) || + fold_xi_to_i(ctx, op, bound) || + fold_xx_to_x(ctx, op)) { + return true; + } + return finish_folding(ctx, op); +} + static bool fold_mov(OptContext *ctx, TCGOp *op) { return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]); @@ -3258,6 +3292,14 @@ void tcg_optimize(TCGContext *s) case INDEX_op_sextract: done = fold_sextract(&ctx, op); break; + case INDEX_op_smax: + done = fold_minmax(&ctx, op, (ctx.type == TCG_TYPE_I32 + ? INT32_MAX : INT64_MAX)); + break; + case INDEX_op_smin: + done = fold_minmax(&ctx, op, (ctx.type == TCG_TYPE_I32 + ? INT32_MIN : INT64_MIN)); + break; case INDEX_op_sub: done = fold_sub(&ctx, op); break; @@ -3273,6 +3315,16 @@ void tcg_optimize(TCGContext *s) case INDEX_op_sub_vec: done = fold_sub_vec(&ctx, op); break; + case INDEX_op_umax: + /* + * Note that 32-bit constants are stored sign extended, + * so (int32_t)UINT32_MAX == -1. + */ + done = fold_minmax(&ctx, op, -1); + break; + case INDEX_op_umin: + done = fold_minmax(&ctx, op, 0); + break; case INDEX_op_xor: case INDEX_op_xor_vec: done = fold_xor(&ctx, op); From 761bfe07b2c954251e25d636e2febb1c2a2e9eea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 16:01:41 -0700 Subject: [PATCH 375/627] util/cpuinfo-aarch64: Detect FEAT_CSSC Signed-off-by: Richard Henderson --- host/include/aarch64/host/cpuinfo.h | 1 + util/cpuinfo-aarch64.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/host/include/aarch64/host/cpuinfo.h b/host/include/aarch64/host/cpuinfo.h index fe671534e4..c32c04dade 100644 --- a/host/include/aarch64/host/cpuinfo.h +++ b/host/include/aarch64/host/cpuinfo.h @@ -12,6 +12,7 @@ #define CPUINFO_AES (1u << 3) #define CPUINFO_PMULL (1u << 4) #define CPUINFO_BTI (1u << 5) +#define CPUINFO_CSSC (1u << 6) /* Initialized with a constructor. */ extern unsigned cpuinfo; diff --git a/util/cpuinfo-aarch64.c b/util/cpuinfo-aarch64.c index 288074c08f..4ce6deb7c8 100644 --- a/util/cpuinfo-aarch64.c +++ b/util/cpuinfo-aarch64.c @@ -72,6 +72,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) unsigned long hwcap2 = qemu_getauxval(AT_HWCAP2); info |= (hwcap2 & HWCAP2_BTI ? CPUINFO_BTI : 0); + info |= (hwcap2 & HWCAP2_CSSC ? CPUINFO_CSSC : 0); #endif #ifdef CONFIG_DARWIN info |= sysctl_for_bool("hw.optional.arm.FEAT_LSE") * CPUINFO_LSE; @@ -79,6 +80,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void) info |= sysctl_for_bool("hw.optional.arm.FEAT_AES") * CPUINFO_AES; info |= sysctl_for_bool("hw.optional.arm.FEAT_PMULL") * CPUINFO_PMULL; info |= sysctl_for_bool("hw.optional.arm.FEAT_BTI") * CPUINFO_BTI; + info |= sysctl_for_bool("hw.optional.arm.FEAT_CSSC") * CPUINFO_CSSC; #endif #if defined(__OpenBSD__) && !defined(CONFIG_ELF_AUX_INFO) int mib[2]; From 100ec60528d389a20fa5c4323a2b35a6f5b9fd3c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 16:40:17 -0700 Subject: [PATCH 376/627] tcg/aarch64: Implement min/max with FEAT_CSSC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-con-set.h | 2 + tcg/aarch64/tcg-target-con-str.h | 2 + tcg/aarch64/tcg-target.c.inc | 103 +++++++++++++++++++++++++++++-- 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/tcg/aarch64/tcg-target-con-set.h b/tcg/aarch64/tcg-target-con-set.h index d0622e65fb..dd84a9af58 100644 --- a/tcg/aarch64/tcg-target-con-set.h +++ b/tcg/aarch64/tcg-target-con-set.h @@ -24,6 +24,8 @@ C_O1_I2(r, r, rAL) C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rL) +C_O1_I2(r, r, rS) +C_O1_I2(r, r, rU) C_O1_I2(r, rZ, rA) C_O1_I2(r, rz, rMZ) C_O1_I2(r, rz, rz) diff --git a/tcg/aarch64/tcg-target-con-str.h b/tcg/aarch64/tcg-target-con-str.h index 48e1722c68..fef75e8a76 100644 --- a/tcg/aarch64/tcg-target-con-str.h +++ b/tcg/aarch64/tcg-target-con-str.h @@ -21,4 +21,6 @@ CONST('L', TCG_CT_CONST_LIMM) CONST('M', TCG_CT_CONST_MONE) CONST('O', TCG_CT_CONST_ORRI) CONST('N', TCG_CT_CONST_ANDI) +CONST('S', TCG_CT_CONST_S8) +CONST('U', TCG_CT_CONST_U8) CONST('Z', TCG_CT_CONST_ZERO) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index f5c185bbf4..55b3be0b96 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -152,6 +152,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, #define TCG_CT_CONST_ORRI 0x1000 #define TCG_CT_CONST_ANDI 0x2000 #define TCG_CT_CONST_CMP 0x4000 +#define TCG_CT_CONST_S8 0x8000 +#define TCG_CT_CONST_U8 0x10000 #define ALL_GENERAL_REGS 0xffffffffu #define ALL_VECTOR_REGS 0xffffffff00000000ull @@ -320,6 +322,12 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_LIMM) && is_limm(val)) { return 1; } + if ((ct & TCG_CT_CONST_S8) && val == (int8_t)val) { + return 1; + } + if ((ct & TCG_CT_CONST_U8) && val == (uint8_t)val) { + return 1; + } if ((ct & TCG_CT_CONST_ZERO) && val == 0) { return 1; } @@ -472,6 +480,12 @@ typedef enum { Iaddsub_imm_SUBI = 0x51000000, Iaddsub_imm_SUBSI = 0x71000000, + /* Min/max immediate instructions. */ + Iminmax_imm_SMAXI = 0x11c00000, + Iminmax_imm_UMAXI = 0x11c40000, + Iminmax_imm_SMINI = 0x11c80000, + Iminmax_imm_UMINI = 0x11cc0000, + /* Bitfield instructions. */ Ibitfield_BFM = 0x33000000, Ibitfield_SBFM = 0x13000000, @@ -533,6 +547,10 @@ typedef enum { Irrr_UMULH = 0x9bc07c00, Irrr_UDIV = 0x1ac00800, Irrr_SDIV = 0x1ac00c00, + Irrr_SMAX = 0x1ac00600, + Irrr_UMAX = 0x1ac00640, + Irrr_SMIN = 0x1ac00680, + Irrr_UMIN = 0x1ac006c0, /* Data-processing (3 source) instructions. */ Irrrr_MADD = 0x1b000000, @@ -737,6 +755,13 @@ static void tcg_out_insn_addsub_imm(TCGContext *s, AArch64Insn insn, tcg_out32(s, insn | ext << 31 | aimm << 10 | rn << 5 | rd); } +static void tcg_out_insn_minmax_imm(TCGContext *s, AArch64Insn insn, + TCGType ext, TCGReg rd, TCGReg rn, + uint8_t imm) +{ + tcg_out32(s, insn | ext << 31 | imm << 10 | rn << 5 | rd); +} + /* This function can be used for both 3.4.2 (Bitfield) and 3.4.4 (Logical immediate). Both insn groups have N, IMMR and IMMS fields that feed the DecodeBitMasks pseudo function. */ @@ -2592,20 +2617,90 @@ static void tcg_out_set_borrow(TCGContext *s) TCG_REG_XZR, TCG_REG_XZR, TCG_REG_XZR); } +static TCGConstraintSetIndex cset_sminmax(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_CSSC ? C_O1_I2(r, r, rS) : C_NotImplemented; +} + +static void tgen_smax(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, rrr, SMAX, type, a0, a1, a2); +} + +static void tgen_smaxi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_insn(s, minmax_imm, SMAXI, type, a0, a1, a2); +} + static const TCGOutOpBinary outop_smax = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_sminmax, + .out_rrr = tgen_smax, + .out_rri = tgen_smaxi, }; +static void tgen_smin(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, rrr, SMIN, type, a0, a1, a2); +} + +static void tgen_smini(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_insn(s, minmax_imm, SMINI, type, a0, a1, a2); +} + static const TCGOutOpBinary outop_smin = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_sminmax, + .out_rrr = tgen_smin, + .out_rri = tgen_smini, }; +static TCGConstraintSetIndex cset_uminmax(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_CSSC ? C_O1_I2(r, r, rU) : C_NotImplemented; +} + +static void tgen_umax(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, rrr, UMAX, type, a0, a1, a2); +} + +static void tgen_umaxi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_insn(s, minmax_imm, UMAXI, type, a0, a1, a2); +} + static const TCGOutOpBinary outop_umax = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_uminmax, + .out_rrr = tgen_umax, + .out_rri = tgen_umaxi, }; +static void tgen_umin(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, rrr, UMIN, type, a0, a1, a2); +} + +static void tgen_umini(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_insn(s, minmax_imm, UMINI, type, a0, a1, a2); +} + static const TCGOutOpBinary outop_umin = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_uminmax, + .out_rrr = tgen_umin, + .out_rri = tgen_umini, }; static void tgen_xor(TCGContext *s, TCGType type, From 20eaf9a54abde6c55a7dacb5888b1deb8d68eb75 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 16:50:03 -0700 Subject: [PATCH 377/627] target/riscv64: Implement min/max with Zbb Signed-off-by: Richard Henderson --- tcg/riscv64/tcg-target.c.inc | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc index 723c21b3da..2ce9d47a63 100644 --- a/tcg/riscv64/tcg-target.c.inc +++ b/tcg/riscv64/tcg-target.c.inc @@ -233,6 +233,10 @@ typedef enum { OPC_CPOPW = 0x6020101b, OPC_CTZ = 0x60101013, OPC_CTZW = 0x6010101b, + OPC_MAX = 0x0a006033, + OPC_MAXU = 0x0a007033, + OPC_MIN = 0x0a004033, + OPC_MINU = 0x0a005033, OPC_ORN = 0x40006033, OPC_REV8 = 0x6b805013, OPC_ROL = 0x60001033, @@ -2404,20 +2408,52 @@ static void tcg_out_set_borrow(TCGContext *s) g_assert_not_reached(); } +static void tgen_smax(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MAX, a0, a1, a2); +} + static const TCGOutOpBinary outop_smax = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_smax, }; +static void tgen_smin(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MIN, a0, a1, a2); +} + static const TCGOutOpBinary outop_smin = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_smin, }; +static void tgen_umax(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MAXU, a0, a1, a2); +} + static const TCGOutOpBinary outop_umax = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_umax, }; +static void tgen_umin(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MINU, a0, a1, a2); +} + static const TCGOutOpBinary outop_umin = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_umin, }; static void tgen_xor(TCGContext *s, TCGType type, From 1643cf8962f6512dfa06db0299b9728fa51cd99d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 17:03:38 -0700 Subject: [PATCH 378/627] tcg/aarch64: Implement ctpop with FEAT_CSSC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 55b3be0b96..1f784e8d46 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -535,6 +535,7 @@ typedef enum { /* Data-processing (1 source) instructions. */ Irr_sf_CLZ = 0x5ac01000, + Irr_sf_CNT = 0x5ac01c00, Irr_sf_RBIT = 0x5ac00000, Irr_sf_REV = 0x5ac00000, /* + size << 10 */ @@ -2251,8 +2252,20 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_CSSC ? C_O1_I1(r, r) : C_NotImplemented; +} + +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_insn(s, rr_sf, CNT, type, a0, a1); +} + static const TCGOutOpUnary outop_ctpop = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, }; static void tgen_ctz(TCGContext *s, TCGType type, From 8ad4e32be0dd281bf4f1b849be588fee7058de67 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 17:19:20 -0700 Subject: [PATCH 379/627] tcg/aarch64: Use CTZ from FEAT_CSSC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have an expansion of CTZ using RBIT+CLZ, but use the new insn with FEAT_CSSC is present. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 43 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 1f784e8d46..1e64c5994e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -535,6 +535,7 @@ typedef enum { /* Data-processing (1 source) instructions. */ Irr_sf_CLZ = 0x5ac01000, + Irr_sf_CTZ = 0x5ac01800, Irr_sf_CNT = 0x5ac01c00, Irr_sf_RBIT = 0x5ac00000, Irr_sf_REV = 0x5ac00000, /* + size << 10 */ @@ -2213,24 +2214,30 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; -static void tgen_clz(TCGContext *s, TCGType type, - TCGReg a0, TCGReg a1, TCGReg a2) +static void tgen_clzctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, AArch64Insn insn) { tcg_out_cmp(s, type, TCG_COND_NE, a1, 0, true); - tcg_out_insn(s, rr_sf, CLZ, type, TCG_REG_TMP0, a1); + tcg_out_insn_rr_sf(s, insn, type, TCG_REG_TMP0, a1); tcg_out_insn(s, csel, CSEL, type, a0, TCG_REG_TMP0, a2, TCG_COND_NE); } -static void tgen_clzi(TCGContext *s, TCGType type, - TCGReg a0, TCGReg a1, tcg_target_long a2) +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_clzctz(s, type, a0, a1, a2, Irr_sf_CLZ); +} + +static void tgen_clzctzi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, AArch64Insn insn) { if (a2 == (type == TCG_TYPE_I32 ? 32 : 64)) { - tcg_out_insn(s, rr_sf, CLZ, type, a0, a1); + tcg_out_insn_rr_sf(s, insn, type, a0, a1); return; } tcg_out_cmp(s, type, TCG_COND_NE, a1, 0, true); - tcg_out_insn(s, rr_sf, CLZ, type, a0, a1); + tcg_out_insn_rr_sf(s, insn, type, a0, a1); switch (a2) { case -1: @@ -2246,6 +2253,12 @@ static void tgen_clzi(TCGContext *s, TCGType type, } } +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_clzctzi(s, type, a0, a1, a2, Irr_sf_CLZ); +} + static const TCGOutOpBinary outop_clz = { .base.static_constraint = C_O1_I2(r, r, rAL), .out_rrr = tgen_clz, @@ -2271,15 +2284,23 @@ static const TCGOutOpUnary outop_ctpop = { static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_insn(s, rr_sf, RBIT, type, TCG_REG_TMP0, a1); - tgen_clz(s, type, a0, TCG_REG_TMP0, a2); + if (cpuinfo & CPUINFO_CSSC) { + tgen_clzctz(s, type, a0, a1, a2, Irr_sf_CTZ); + } else { + tcg_out_insn(s, rr_sf, RBIT, type, TCG_REG_TMP0, a1); + tgen_clzctz(s, type, a0, TCG_REG_TMP0, a2, Irr_sf_CLZ); + } } static void tgen_ctzi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, tcg_target_long a2) { - tcg_out_insn(s, rr_sf, RBIT, type, TCG_REG_TMP0, a1); - tgen_clzi(s, type, a0, TCG_REG_TMP0, a2); + if (cpuinfo & CPUINFO_CSSC) { + tgen_clzctzi(s, type, a0, a1, a2, Irr_sf_CTZ); + } else { + tcg_out_insn(s, rr_sf, RBIT, type, TCG_REG_TMP0, a1); + tgen_clzctzi(s, type, a0, TCG_REG_TMP0, a2, Irr_sf_CLZ); + } } static const TCGOutOpBinary outop_ctz = { From a5572e5214771b288bd7234c48cfd513b1eac81f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 09:54:23 -0700 Subject: [PATCH 380/627] target/riscv: Improve riscv_has_ext MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constify the env pointer and return bool. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/riscv/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c9dfa7daff..376cff656f 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -615,7 +615,7 @@ struct RISCVCPUClass { RISCVCPUDef *def; }; -static inline int riscv_has_ext(CPURISCVState *env, uint32_t ext) +static inline bool riscv_has_ext(const CPURISCVState *env, uint32_t ext) { return (env->misa_ext & ext) != 0; } From a854350af144692f0efc6cd8f1a6254898e89866 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 10:49:24 -0700 Subject: [PATCH 381/627] disas/capstone: Allow for cap_insn_unit > length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cap_insn_unit is designed for targets like arm thumb2 and s390x where 4 and 6-byte insns are displayed in 2-byte chunks. For riscv, we prefer 4-byte insns to display as one 4-byte unit, rather than 2x 2-byte units. So we will want to set cap_insn_unit to 4, but allow for insns that are smaller than 4. Emit padding to match. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- disas/capstone.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/disas/capstone.c b/disas/capstone.c index fe3efb0d3c..8fb8d0724c 100644 --- a/disas/capstone.c +++ b/disas/capstone.c @@ -107,8 +107,9 @@ static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn, { fprintf_function print = info->fprintf_func; FILE *stream = info->stream; + int unit = MIN(info->cap_insn_unit, n - i); - switch (info->cap_insn_unit) { + switch (unit) { case 4: if (info->endian == BFD_ENDIAN_BIG) { for (; i < n; i += 4) { @@ -140,6 +141,11 @@ static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn, } break; } + + if (unit < info->cap_insn_unit) { + int width = (info->cap_insn_unit - unit) * 2; + print(stream, "%*s", width, ""); + } } static void cap_dump_insn(disassemble_info *info, cs_insn *insn) From 09d7b5d49ad6dff06c67ae61993fa5657f08dd7c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 11:23:07 -0700 Subject: [PATCH 382/627] target/riscv: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In capstone v5, riscv support is spare, but v6 is pretty good. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- disas/capstone.c | 19 ++++++++++ include/disas/capstone.h | 34 +++++++++++++++++ target/riscv/cpu.c | 81 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/disas/capstone.c b/disas/capstone.c index 8fb8d0724c..78062339d0 100644 --- a/disas/capstone.c +++ b/disas/capstone.c @@ -49,6 +49,20 @@ static const cs_opt_skipdata cap_skipdata_s390x = { .callback = cap_skipdata_s390x_cb }; +/* Similarly for RISCV */ +static size_t CAPSTONE_API +cap_skipdata_riscv_cb(const uint8_t *code, size_t code_size, + size_t offset, void *user_data) +{ + /* See insn_len() from target/riscv/internals.h */ + return (code[offset] & 3) == 3 ? 4 : 2; +} + +static const cs_opt_skipdata cap_skipdata_riscv = { + .mnemonic = ".byte", + .callback = cap_skipdata_riscv_cb +}; + /* * Initialize the Capstone library. * @@ -76,6 +90,11 @@ static cs_err cap_disas_start(disassemble_info *info, csh *handle) cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON); switch (info->cap_arch) { + case CS_ARCH_RISCV: + cs_option(*handle, CS_OPT_SKIPDATA_SETUP, + (uintptr_t)&cap_skipdata_riscv); + break; + case CS_ARCH_SYSZ: cs_option(*handle, CS_OPT_SKIPDATA_SETUP, (uintptr_t)&cap_skipdata_s390x); diff --git a/include/disas/capstone.h b/include/disas/capstone.h index c43033f7f6..5c78824da2 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -11,6 +11,8 @@ /* Just enough to allow backends to init without ifdefs. */ +#define CS_API_MAJOR 0 + #define CS_ARCH_ARM -1 #define CS_ARCH_ARM64 -1 #define CS_ARCH_MIPS -1 @@ -37,4 +39,36 @@ #define CS_MODE_MIPS64 0 #endif /* CONFIG_CAPSTONE */ + +#if CS_API_MAJOR < 5 +#define CS_ARCH_RISCV -1 +#define CS_MODE_RISCV32 0 +#define CS_MODE_RISCV64 0 +#define CS_MODE_RISCV_C 0 +#elif CS_API_MAJOR == 5 +/* The C symbol name changed between v5 and v6 */ +#define CS_MODE_RISCV_C CS_MODE_RISCVC +#endif +#if CS_API_MAJOR < 6 +#define CS_MODE_RISCV_FD 0 +#define CS_MODE_RISCV_V 0 +#define CS_MODE_RISCV_ZFINX 0 +#define CS_MODE_RISCV_ZCMP_ZCMT_ZCE 0 +#define CS_MODE_RISCV_ZICFISS 0 +#define CS_MODE_RISCV_E 0 +#define CS_MODE_RISCV_A 0 +#define CS_MODE_RISCV_COREV 0 +#define CS_MODE_RISCV_THEAD 0 +#define CS_MODE_RISCV_SIFIVE 0 +#define CS_MODE_RISCV_BITMANIP 0 +#define CS_MODE_RISCV_ZBA 0 +#define CS_MODE_RISCV_ZBB 0 +#define CS_MODE_RISCV_ZBC 0 +#define CS_MODE_RISCV_ZBKB 0 +#define CS_MODE_RISCV_ZBKC 0 +#define CS_MODE_RISCV_ZBKX 0 +#define CS_MODE_RISCV_ZBS 0 +#define CS_MODE_RISCV_VENTANA 0 +#endif + #endif /* QEMU_CAPSTONE_H */ diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 23b5023dd3..e73ff53159 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -39,6 +39,7 @@ #include "system/tcg.h" #include "kvm/kvm_riscv.h" #include "tcg/tcg-cpu.h" +#include "disas/capstone.h" #if !defined(CONFIG_USER_ONLY) #include "target/riscv/tcg/debug.h" #endif @@ -1099,6 +1100,7 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info) { const RISCVCPU *cpu = RISCV_CPU(s); const CPURISCVState *env = &cpu->env; + int cap_mode; info->target_info = &cpu->cfg; @@ -1111,16 +1113,93 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info) switch (env->xl) { case MXL_RV32: info->print_insn = print_insn_riscv32; + cap_mode = CS_MODE_RISCV32; break; case MXL_RV64: info->print_insn = print_insn_riscv64; + cap_mode = CS_MODE_RISCV64; break; case MXL_RV128: info->print_insn = print_insn_riscv128; - break; + /* capstone v6 doesn't support RV128 */ + return; default: g_assert_not_reached(); } + + info->cap_arch = CS_ARCH_RISCV; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; + + /* + * Capstone compresses some features together. See RISCV_getFeatureBits, + * which maps LLVM feature bits to capstone bits. + */ + if (riscv_has_ext(env, RVC) || cpu->cfg.ext_zca) { + cap_mode |= CS_MODE_RISCV_C; + } + if (riscv_has_ext(env, RVF)) { + cap_mode |= CS_MODE_RISCV_FD; + } + if (riscv_has_ext(env, RVV)) { + cap_mode |= CS_MODE_RISCV_V; + } + if (cpu->cfg.ext_zfinx || cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx) { + cap_mode |= CS_MODE_RISCV_ZFINX; + } + if (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt || cpu->cfg.ext_zce) { + cap_mode |= CS_MODE_RISCV_ZCMP_ZCMT_ZCE; + } + if (cpu->cfg.ext_zicfiss) { + cap_mode |= CS_MODE_RISCV_ZICFISS; + } + if (riscv_has_ext(env, RVE)) { + cap_mode |= CS_MODE_RISCV_E; + } + if (riscv_has_ext(env, RVA)) { + cap_mode |= CS_MODE_RISCV_A; + } + if (cpu->cfg.ext_xlrbr) { + cap_mode |= CS_MODE_RISCV_BITMANIP; + } + if (cpu->cfg.ext_zba) { + cap_mode |= CS_MODE_RISCV_ZBA; + } + if (cpu->cfg.ext_zbb) { + cap_mode |= CS_MODE_RISCV_ZBB; + } + if (cpu->cfg.ext_zbc) { + cap_mode |= CS_MODE_RISCV_ZBC; + } + if (cpu->cfg.ext_zbkb) { + cap_mode |= CS_MODE_RISCV_ZBKB; + } + if (cpu->cfg.ext_zbkc) { + cap_mode |= CS_MODE_RISCV_ZBKC; + } + if (cpu->cfg.ext_zbkx) { + cap_mode |= CS_MODE_RISCV_ZBKX; + } + if (cpu->cfg.ext_zbs) { + cap_mode |= CS_MODE_RISCV_ZBS; + } + if (cpu->cfg.ext_xtheadba || + cpu->cfg.ext_xtheadbb || + cpu->cfg.ext_xtheadbs || + cpu->cfg.ext_xtheadcmo || + cpu->cfg.ext_xtheadcondmov || + cpu->cfg.ext_xtheadfmemidx || + cpu->cfg.ext_xtheadfmv || + cpu->cfg.ext_xtheadmac || + cpu->cfg.ext_xtheadmemidx || + cpu->cfg.ext_xtheadmempair || + cpu->cfg.ext_xtheadsync) { + cap_mode |= CS_MODE_RISCV_THEAD; + } + if (cpu->cfg.ext_XVentanaCondOps) { + cap_mode |= CS_MODE_RISCV_VENTANA; + } + info->cap_mode = cap_mode; } #ifndef CONFIG_USER_ONLY From 2b386072864da25299991c4ca3d30efdd9466376 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 12:47:26 -0700 Subject: [PATCH 383/627] target/sh4: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/disas/capstone.h | 7 +++++++ target/sh4/cpu.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index 5c78824da2..788f90771a 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -71,4 +71,11 @@ #define CS_MODE_RISCV_VENTANA 0 #endif +#if CS_API_MAJOR < 5 +#define CS_ARCH_SH -1 +#define CS_MODE_SHFPU 0 +#define CS_MODE_SH4 0 +#define CS_MODE_SH4A 0 +#endif + #endif /* QEMU_CAPSTONE_H */ diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index ad2ec28c1b..3bbdee301d 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -28,6 +28,7 @@ #include "fpu/softfloat-helpers.h" #include "accel/tcg/cpu-ops.h" #include "tcg/tcg.h" +#include "disas/capstone.h" static void superh_cpu_set_pc(CPUState *cs, vaddr value) { @@ -167,10 +168,23 @@ static void superh_cpu_reset_hold(Object *obj, ResetType type) static void superh_cpu_disas_set_info(const CPUState *cpu, disassemble_info *info) { + const CPUSH4State *env = cpu_env((CPUState *)cpu); + info->endian = TARGET_BIG_ENDIAN ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; info->mach = bfd_mach_sh4; info->print_insn = print_insn_sh; + + info->cap_arch = CS_ARCH_SH; + info->cap_insn_unit = 2; + info->cap_insn_split = 2; + /* + * Possible capstone bug: the isa levels are not additive: + * least significant bit wins, so SH4 overrides SH4A. + * Work around by setting one or the other but not both. + */ + info->cap_mode = CS_MODE_SHFPU + | (env->features & SH_FEATURE_SH4A ? CS_MODE_SH4A : CS_MODE_SH4); } static ObjectClass *superh_cpu_class_by_name(const char *cpu_model) From 3a002bbcdd65030bc93f0435f91325f4ef5cb171 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 13:19:25 -0700 Subject: [PATCH 384/627] target/tricore: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/disas/capstone.h | 11 +++++++++++ target/tricore/cpu.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index 788f90771a..db1abe7f70 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -78,4 +78,15 @@ #define CS_MODE_SH4A 0 #endif +#if CS_API_MAJOR < 5 +#define CS_ARCH_TRICORE -1 +#define CS_MODE_TRICORE_110 0 +#define CS_MODE_TRICORE_120 0 +#define CS_MODE_TRICORE_130 0 +#define CS_MODE_TRICORE_131 0 +#define CS_MODE_TRICORE_160 0 +#define CS_MODE_TRICORE_161 0 +#define CS_MODE_TRICORE_162 0 +#endif + #endif /* QEMU_CAPSTONE_H */ diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 96e2817dee..dcd5c5065b 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -24,6 +24,7 @@ #include "qemu/error-report.h" #include "tcg/debug-assert.h" #include "accel/tcg/cpu-ops.h" +#include "disas/capstone.h" static inline void set_feature(CPUTriCoreState *env, int feature) { @@ -35,6 +36,35 @@ static const gchar *tricore_gdb_arch_name(CPUState *cs) return "tricore"; } +static void tricore_disas_set_info(const CPUState *cpu, disassemble_info *info) +{ + CPUTriCoreState *env = cpu_env((CPUState *)cpu); + + info->endian = BFD_ENDIAN_LITTLE; + info->cap_arch = CS_ARCH_TRICORE; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; + + /* + * Possible capstone bug: the isa levels are not additive. + * Work around by settiing only one. + * Note that TriCore 1.3.0 is the earliest we support. + */ + if (tricore_has_feature(env, TRICORE_FEATURE_162)) { + info->cap_mode = CS_MODE_TRICORE_162; + } else if (tricore_has_feature(env, TRICORE_FEATURE_161)) { + info->cap_mode = CS_MODE_TRICORE_161; + } else if (tricore_has_feature(env, TRICORE_FEATURE_16)) { + info->cap_mode = CS_MODE_TRICORE_160; + } else if (tricore_has_feature(env, TRICORE_FEATURE_131)) { + info->cap_mode = CS_MODE_TRICORE_131; + } else if (tricore_has_feature(env, TRICORE_FEATURE_13)) { + info->cap_mode = CS_MODE_TRICORE_130; + } else { + g_assert_not_reached(); + } +} + static void tricore_cpu_set_pc(CPUState *cs, vaddr value) { cpu_env(cs)->PC = value & ~1; @@ -214,6 +244,7 @@ static void tricore_cpu_class_init(ObjectClass *c, const void *data) cc->gdb_write_register = tricore_cpu_gdb_write_register; cc->gdb_num_core_regs = 44; cc->gdb_arch_name = tricore_gdb_arch_name; + cc->disas_set_info = tricore_disas_set_info; cc->dump_state = tricore_cpu_dump_state; cc->set_pc = tricore_cpu_set_pc; From 724452279fda64259b480db07818bb0f11b0b5a7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 14:20:46 -0700 Subject: [PATCH 385/627] target/loongarch: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Song Gao <17746591750@163.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/disas/capstone.h | 6 ++++++ target/loongarch/cpu.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index db1abe7f70..a922f7627f 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -40,6 +40,12 @@ #endif /* CONFIG_CAPSTONE */ +#if CS_API_MAJOR < 6 +#define CS_ARCH_LOONGARCH -1 +#define CS_MODE_LOONGARCH32 0 +#define CS_MODE_LOONGARCH64 0 +#endif + #if CS_API_MAJOR < 5 #define CS_ARCH_RISCV -1 #define CS_MODE_RISCV32 0 diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index cb07f15110..8cd5bc18a3 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -29,6 +29,7 @@ #include #endif #include "tcg/tcg_loongarch.h" +#include "disas/capstone.h" const char * const regnames[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", @@ -694,8 +695,15 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type) static void loongarch_cpu_disas_set_info(const CPUState *cs, disassemble_info *info) { + CPULoongArchState *env = cpu_env((CPUState *)cs); + info->endian = BFD_ENDIAN_LITTLE; info->print_insn = print_insn_loongarch; + + info->cap_arch = CS_ARCH_LOONGARCH; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; + info->cap_mode = is_la64(env) ? CS_MODE_LOONGARCH64 : CS_MODE_LOONGARCH32; } static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) From c8220a096f00b21cad99d39e9c4736c1d1e81694 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 14:50:28 -0700 Subject: [PATCH 386/627] target/s390x: Update capstone disassembly to v6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In particular, this enables many more vector insns. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- disas/capstone.c | 2 +- include/disas/capstone.h | 11 +++++++++-- target/s390x/cpu.c | 4 +++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/disas/capstone.c b/disas/capstone.c index 78062339d0..a5bd91890b 100644 --- a/disas/capstone.c +++ b/disas/capstone.c @@ -95,7 +95,7 @@ static cs_err cap_disas_start(disassemble_info *info, csh *handle) (uintptr_t)&cap_skipdata_riscv); break; - case CS_ARCH_SYSZ: + case CS_ARCH_SYSTEMZ: cs_option(*handle, CS_OPT_SKIPDATA_SETUP, (uintptr_t)&cap_skipdata_s390x); break; diff --git a/include/disas/capstone.h b/include/disas/capstone.h index a922f7627f..87f8f6181f 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -4,7 +4,6 @@ #ifdef CONFIG_CAPSTONE #define CAPSTONE_AARCH64_COMPAT_HEADER -#define CAPSTONE_SYSTEMZ_COMPAT_HEADER #include #else @@ -19,7 +18,6 @@ #define CS_ARCH_X86 -1 #define CS_ARCH_PPC -1 #define CS_ARCH_SPARC -1 -#define CS_ARCH_SYSZ -1 #define CS_MODE_LITTLE_ENDIAN 0 #define CS_MODE_BIG_ENDIAN 0 @@ -84,6 +82,15 @@ #define CS_MODE_SH4A 0 #endif +#if CS_API_MAJOR == 0 +#define CS_ARCH_SYSTEMZ -1 +#elif CS_API_MAJOR < 6 +#define CS_ARCH_SYSTEMZ CS_ARCH_SYSZ +#endif +#if CS_API_MAJOR < 6 +#define CS_MODE_SYSTEMZ_ARCH14 0 +#endif + #if CS_API_MAJOR < 5 #define CS_ARCH_TRICORE -1 #define CS_MODE_TRICORE_110 0 diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 641ea96c8e..7c725b8a4a 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -225,10 +225,12 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type) static void s390_cpu_disas_set_info(const CPUState *cpu, disassemble_info *info) { info->mach = bfd_mach_s390_64; - info->cap_arch = CS_ARCH_SYSZ; + info->cap_arch = CS_ARCH_SYSTEMZ; info->endian = BFD_ENDIAN_BIG; info->cap_insn_unit = 2; info->cap_insn_split = 6; + /* Disassemble everything, even if the cpu would trap on the insn. */ + info->cap_mode = CS_MODE_SYSTEMZ_ARCH14; } static void s390_cpu_realizefn(DeviceState *dev, Error **errp) From 89faaa51812765f1a8be59abe704bc88cfbdd17b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 16:12:43 -0700 Subject: [PATCH 387/627] target/m68k: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/disas/capstone.h | 20 +++++++++++++ target/m68k/cpu.c | 65 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index 87f8f6181f..3d6f90d816 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -14,6 +14,7 @@ #define CS_ARCH_ARM -1 #define CS_ARCH_ARM64 -1 +#define CS_ARCH_M68K -1 #define CS_ARCH_MIPS -1 #define CS_ARCH_X86 -1 #define CS_ARCH_PPC -1 @@ -28,6 +29,12 @@ #define CS_MODE_THUMB 0 #define CS_MODE_MCLASS 0 #define CS_MODE_V8 0 +#define CS_MODE_M68K_000 0 +#define CS_MODE_M68K_010 0 +#define CS_MODE_M68K_020 0 +#define CS_MODE_M68K_030 0 +#define CS_MODE_M68K_040 0 +#define CS_MODE_M68K_060 0 #define CS_MODE_MICRO 0 #define CS_MODE_MIPS3 0 #define CS_MODE_MIPS32R6 0 @@ -44,6 +51,19 @@ #define CS_MODE_LOONGARCH64 0 #endif +#if CS_API_MAJOR < 6 +#define CS_MODE_M68K_CF_ISA_A 0 +#define CS_MODE_M68K_CF_ISA_A_PLUS 0 +#define CS_MODE_M68K_CF_ISA_B 0 +#define CS_MODE_M68K_CF_ISA_C 0 +#define CS_MODE_M68K_CF_USP 0 +#define CS_MODE_M68K_CF_DIV 0 +#define CS_MODE_M68K_CF_MAC 0 +#define CS_MODE_M68K_CF_EMAC 0 +#define CS_MODE_M68K_CF_EMAC_B 0 +#define CS_MODE_M68K_CF_FPU 0 +#endif + #if CS_API_MAJOR < 5 #define CS_ARCH_RISCV -1 #define CS_MODE_RISCV32 0 diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index ce2707dee5..6012dc3186 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -22,7 +22,7 @@ #include "accel/tcg/cpu-ops.h" #include "fpu/softfloat.h" #include "qapi/error.h" - +#include "disas/capstone.h" #ifndef CONFIG_USER_ONLY #include "migration/vmstate.h" #include "monitor/hmp.h" @@ -182,9 +182,72 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type) static void m68k_cpu_disas_set_info(const CPUState *cs, disassemble_info *info) { + CPUM68KState *env = cpu_env((CPUState *)cs); + int cap_mode = 0; + info->print_insn = print_insn_m68k; info->endian = BFD_ENDIAN_BIG; info->mach = 0; + + /* m68k support in capstone prior to v6 is unusably bad */ + if (CS_API_MAJOR < 6) { + return; + } + + info->cap_arch = CS_ARCH_M68K; + info->cap_insn_unit = 2; + + if (m68k_feature(env, M68K_FEATURE_M68K)) { + /* + * m68k insns may have up to 11 words, and 5 words are common. + * Choosing 12 bytes splits after 6 words and disassembly + * uses no more than 2 lines. + */ + info->cap_insn_split = 12; + if (m68k_feature(env, M68K_FEATURE_M68060)) { + cap_mode = CS_MODE_M68K_060; + } else if (m68k_feature(env, M68K_FEATURE_M68040)) { + cap_mode = CS_MODE_M68K_040; + } else if (m68k_feature(env, M68K_FEATURE_M68030)) { + cap_mode = CS_MODE_M68K_030; + } else if (m68k_feature(env, M68K_FEATURE_M68020)) { + cap_mode = CS_MODE_M68K_020; + } else if (m68k_feature(env, M68K_FEATURE_M68010)) { + cap_mode = CS_MODE_M68K_010; + } else { + cap_mode = CS_MODE_M68K_000; + } + } else { + /* ColdFire insns may have up to 3 words. */ + info->cap_insn_split = 6; + if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { + cap_mode |= CS_MODE_M68K_CF_ISA_A; + cap_mode |= CS_MODE_M68K_CF_DIV; + } + if (m68k_feature(env, M68K_FEATURE_CF_ISA_B)) { + cap_mode |= CS_MODE_M68K_CF_ISA_B; + } + if (m68k_feature(env, M68K_FEATURE_CF_ISA_APLUSC)) { + cap_mode |= CS_MODE_M68K_CF_ISA_A_PLUS; + cap_mode |= CS_MODE_M68K_CF_ISA_C; + } + if (m68k_feature(env, M68K_FEATURE_USP)) { + cap_mode |= CS_MODE_M68K_CF_USP; + } + if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { + cap_mode |= CS_MODE_M68K_CF_FPU; + } + if (m68k_feature(env, M68K_FEATURE_CF_MAC)) { + cap_mode |= CS_MODE_M68K_CF_MAC; + } + if (m68k_feature(env, M68K_FEATURE_CF_EMAC)) { + cap_mode |= CS_MODE_M68K_CF_EMAC; + } + if (m68k_feature(env, M68K_FEATURE_CF_EMAC_B)) { + cap_mode |= CS_MODE_M68K_CF_EMAC_B; + } + } + info->cap_mode = cap_mode; } /* CPU models */ From 84dd090703e4164e209e0729333cfd30d8f9c9f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Aug 2026 17:28:46 -0700 Subject: [PATCH 388/627] target/mips: Enable disassembly via capstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/disas/capstone.h | 24 ++++++++++++++-- target/mips/cpu.c | 60 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index 3d6f90d816..e72faf8179 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -29,6 +29,7 @@ #define CS_MODE_THUMB 0 #define CS_MODE_MCLASS 0 #define CS_MODE_V8 0 +#define CS_MODE_V9 0 #define CS_MODE_M68K_000 0 #define CS_MODE_M68K_010 0 #define CS_MODE_M68K_020 0 @@ -36,11 +37,10 @@ #define CS_MODE_M68K_040 0 #define CS_MODE_M68K_060 0 #define CS_MODE_MICRO 0 +#define CS_MODE_MIPS2 0 #define CS_MODE_MIPS3 0 -#define CS_MODE_MIPS32R6 0 -#define CS_MODE_MIPSGP64 0 -#define CS_MODE_V9 0 #define CS_MODE_MIPS32 0 +#define CS_MODE_MIPS32R6 0 #define CS_MODE_MIPS64 0 #endif /* CONFIG_CAPSTONE */ @@ -64,6 +64,24 @@ #define CS_MODE_M68K_CF_FPU 0 #endif +#if CS_API_MAJOR < 6 +#define CS_MODE_MIPS16 0 +#define CS_MODE_MIPS1 0 +#define CS_MODE_MIPS32R2 0 +#define CS_MODE_MIPS32R3 0 +#define CS_MODE_MIPS32R5 0 +#define CS_MODE_MIPS4 0 +#define CS_MODE_MIPS5 0 +#define CS_MODE_MIPS64R2 0 +#define CS_MODE_MIPS64R3 0 +#define CS_MODE_MIPS64R5 0 +#define CS_MODE_MIPS64R6 0 +#define CS_MODE_OCTEON 0 +#define CS_MODE_OCTEONP 0 +#define CS_MODE_NANOMIPS 0 +#define CS_MODE_MIPS_PTR64 0 +#endif + #if CS_API_MAJOR < 5 #define CS_ARCH_RISCV -1 #define CS_MODE_RISCV32 0 diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 669c7d99bb..0fead20d65 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -30,6 +30,7 @@ #include "system/qtest.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev-clock.h" +#include "disas/capstone.h" #include "fpu_helper.h" #ifndef CONFIG_USER_ONLY #include "semihosting/semihost.h" @@ -488,15 +489,66 @@ static void mips_cpu_disas_set_info(const CPUState *cs, disassemble_info *info) { const MIPSCPU *cpu = MIPS_CPU(cs); const CPUMIPSState *env = &cpu->env; + bool is64 = env->hflags & MIPS_HFLAG_64; + int cap_mode = 0; - if (!(env->insn_flags & ISA_NANOMIPS32)) { + if (env->insn_flags & ISA_NANOMIPS32) { + info->print_insn = print_insn_nanomips; + info->endian = BFD_ENDIAN_LITTLE; + /* nanomips has 16, 32 and 48-bit insns */ + info->cap_insn_unit = 2; + info->cap_insn_split = 6; + cap_mode = CS_MODE_NANOMIPS; + } else { info->endian = TARGET_BIG_ENDIAN ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; info->print_insn = TARGET_BIG_ENDIAN ? print_insn_big_mips : print_insn_little_mips; - } else { - info->print_insn = print_insn_nanomips; - info->endian = BFD_ENDIAN_LITTLE; + + if (env->hflags & MIPS_HFLAG_M16) { + cap_mode = (env->insn_flags & ASE_MICROMIPS + ? CS_MODE_MICRO : CS_MODE_MIPS16); + /* Beware unsupported capstone mode */ + if (cap_mode == 0) { + return; + } + info->cap_insn_unit = 2; + } else { + info->cap_insn_unit = 4; + } + info->cap_insn_split = 4; + + cap_mode |= is64 ? CS_MODE_MIPS64 : CS_MODE_MIPS32; + if (env->insn_flags & ISA_MIPS_R6) { + cap_mode |= is64 ? CS_MODE_MIPS64R6 : CS_MODE_MIPS32R6; + } else if (env->insn_flags & ISA_MIPS_R5) { + cap_mode |= is64 ? CS_MODE_MIPS64R5 : CS_MODE_MIPS32R5; + } else if (env->insn_flags & ISA_MIPS_R3) { + cap_mode |= is64 ? CS_MODE_MIPS64R3 : CS_MODE_MIPS32R3; + } else if (env->insn_flags & ISA_MIPS_R2) { + cap_mode |= is64 ? CS_MODE_MIPS64R2 : CS_MODE_MIPS32R2; + } else if (env->insn_flags & ISA_MIPS5) { + cap_mode |= CS_MODE_MIPS5; + } else if (env->insn_flags & ISA_MIPS4) { + cap_mode |= CS_MODE_MIPS4; + } else if (env->insn_flags & ISA_MIPS3) { + cap_mode |= CS_MODE_MIPS3; + } else if (env->insn_flags & ISA_MIPS2) { + cap_mode |= CS_MODE_MIPS2; + } else if (env->insn_flags & ISA_MIPS1) { + cap_mode |= CS_MODE_MIPS1; + } + if (env->insn_flags & INSN_OCTEON) { + cap_mode |= CS_MODE_OCTEON | CS_MODE_OCTEONP; + } + if (is64 && !(env->hflags & MIPS_HFLAG_AWRAP)) { + cap_mode |= CS_MODE_MIPS_PTR64; + } + } + /* Beware unsupported capstone mode */ + if (cap_mode) { + info->cap_arch = CS_ARCH_MIPS; + info->cap_mode = cap_mode; } } From c54c041ae09004866ae049594ba9fb3a3c5ac271 Mon Sep 17 00:00:00 2001 From: Amit Machhiwal Date: Fri, 22 May 2026 13:55:55 +0530 Subject: [PATCH 389/627] tests/qtest/libqtest: Use GLib functions for proper const correctness While commit e68da5b7a2cd ("tests/qtest: fix discarded const qualifier warning") addressed the immediate strstr() warning by making 'found' const, there's still a room for improvement: getenv() returns char *, but environment strings are semantically read-only and should be treated as const throughout their lifetime. Replace getenv() with g_getenv() and strstr() with g_strstr_len() to maintain const correctness from source to use. This approach: - Uses g_getenv() which returns const gchar *, matching the read-only semantics of environment variables - Employs g_strstr_len() for consistent use of GLib string functions, aligning with QEMU conventions - Eliminates all const-correctness warnings with strict compilers Tested-by: Anushree Mathur Reviewed-by: Aditya Gupta Signed-off-by: Amit Machhiwal Signed-off-by: Fabiano Rosas --- tests/qtest/libqtest.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index c33c799c92..bec37c71b8 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -2151,8 +2151,7 @@ bool mkimg(const char *file, const char *fmt, unsigned size_mb) bool qtest_verbose(const char *domain) { - const char *log = getenv("QTEST_LOG"); - const char *found; + const gchar *found, *log = g_getenv("QTEST_LOG"); assert(domain); @@ -2178,11 +2177,11 @@ bool qtest_verbose(const char *domain) * QTEST_LOG=,- (only false for domain2) * allows other separators, except - and + */ - found = strstr(log, domain); + found = g_strstr_len(log, -1, domain); if (found) { /* reject options given twice */ - assert(!strstr(found + strlen(domain), domain)); + assert(!g_strstr_len(found + strlen(domain), -1, domain)); if (found > log) { ptrdiff_t i = found - log - 1; @@ -2196,7 +2195,7 @@ bool qtest_verbose(const char *domain) * If filtering out a specific domain, all others are * enabled. */ - return !!strstr(log, "-"); + return !!g_strstr_len(log, -1, "-"); } } From 6500a6abe656743bab51cbff79a6b2c229cd688f Mon Sep 17 00:00:00 2001 From: Rohitashv Kumar Date: Fri, 17 Jul 2026 08:18:34 +0000 Subject: [PATCH 390/627] tests/qtest/device-plug-test: skip pc tests when 'pc' machine is unavailable test_pci_unplug_request() and test_pci_unplug_json_request() use "-machine pc" on i386/x86_64. When QEMU is built without the i440fx/pc machine, these fail with "unsupported machine type 'pc'". Skip the x86 case when 'pc' is not available. Non-x86 architectures use the default machine and are unaffected, and x86 unplug coverage is still provided by the q35 variant (test_q35_pci_unplug_request), which already guards on qtest_has_machine("q35"). Signed-off-by: Rohitashv Kumar Signed-off-by: Fabiano Rosas --- tests/qtest/device-plug-test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/qtest/device-plug-test.c b/tests/qtest/device-plug-test.c index 2707ee59f6..650956fa11 100644 --- a/tests/qtest/device-plug-test.c +++ b/tests/qtest/device-plug-test.c @@ -65,6 +65,10 @@ static void test_pci_unplug_request(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } @@ -107,6 +111,10 @@ static void test_pci_unplug_json_request(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } From 4e37f749ddf4717b4f9df786232584f8a7953cb8 Mon Sep 17 00:00:00 2001 From: Rohitashv Kumar Date: Fri, 17 Jul 2026 08:18:35 +0000 Subject: [PATCH 391/627] tests/qtest/drive_del-test: skip pc tests when 'pc' machine is unavailable test_cli_device_del(), test_device_add_and_del(), test_drive_add_device_add_and_del() and test_blockdev_add_device_add_and_del() use "-machine pc" on i386/x86_64. When QEMU is built without the i440fx/pc machine, these fail with "unsupported machine type 'pc'". Skip the x86 case when 'pc' is not available. Non-x86 architectures use the default machine and are unaffected, and the corresponding _q35 variants already cover x86 under qtest_has_machine("q35"). Signed-off-by: Rohitashv Kumar Signed-off-by: Fabiano Rosas --- tests/qtest/drive_del-test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/qtest/drive_del-test.c b/tests/qtest/drive_del-test.c index 30d9451ddd..4c32da594a 100644 --- a/tests/qtest/drive_del-test.c +++ b/tests/qtest/drive_del-test.c @@ -258,6 +258,10 @@ static void test_cli_device_del(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } @@ -332,6 +336,10 @@ static void test_device_add_and_del(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } @@ -403,6 +411,10 @@ static void test_drive_add_device_add_and_del(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } @@ -456,6 +468,10 @@ static void test_blockdev_add_device_add_and_del(void) } if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + if (!qtest_has_machine("pc")) { + g_test_skip("Machine 'pc' is not available"); + return; + } machine_addition = "-machine pc"; } From bb98963d6df300fe6fc6d2074198e220571cd0cd Mon Sep 17 00:00:00 2001 From: Rohitashv Kumar Date: Fri, 17 Jul 2026 08:18:36 +0000 Subject: [PATCH 392/627] tests/qtest/pxe-test: skip per-row cases whose machine is unavailable The x86 test table mixes 'pc' and 'q35' rows. When QEMU is built without the i440fx/pc machine, the 'pc' rows fail with "unsupported machine type". Add a per-row qtest_has_machine() check in test_batch(), mirroring the existing per-row qtest_has_device() guard, so rows for an unavailable machine are skipped while the others (e.g. q35) still run. Signed-off-by: Rohitashv Kumar Signed-off-by: Fabiano Rosas --- tests/qtest/pxe-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/qtest/pxe-test.c b/tests/qtest/pxe-test.c index a3f900fbea..e85dec5a4e 100644 --- a/tests/qtest/pxe-test.c +++ b/tests/qtest/pxe-test.c @@ -108,6 +108,10 @@ static void test_batch(const testdef_t *tests, bool ipv6) const testdef_t *test = &tests[i]; char *testname; + if (!qtest_has_machine(test->machine)) { + continue; + } + if (!qtest_has_device(test->model)) { continue; } From 03ce28d45362dfaab99dd3a6ac842c617c548530 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Jul 2026 11:11:34 +0200 Subject: [PATCH 393/627] target/i386: emulate: stop torturing cc_src into carrying SF/PF x86_flags.c encodes the flags into cc_dst and cc_src with algorithms essentially derived from Bochs; the exact details have changed but cc_dst is Bochs result and cc_src is very close to Bochs auxbits. However, using only two words is unnecessarily limiting because it splits SF/PF between the two words even though *ZF* is the real nuisance (ZF=1 implies SF=PF=0) and the one that commands usage of PD/SD delta bits. Within TCG, the CCMP instruction would have a similar need of efficiently encoding an arithmetic result or an EFLAGS value; it is not implemented, but there are plans (see commit message for 5dcdbd07125, "target/i386: tcg: use cout to commonize add/adc/sub/sbb cases", 2025-04-17) to use an algorithm very similar to target/i386/emulate's, but with *three* words. Then SF and PF live together in harmony, because SF can be encoded with either parity and PF does not use the high bit where SF is stored; by placing them in a third word their computation is isolated from ZF's and everything becomes simpler. In fact I'm not even sure why Bochs did it like that, and did not just give SF/PF their own home in a third word as well; the developers believe that the extra store is too expensive. I am not really sure about that, but as far as QEMU is concerned, emulation proceeds one instruction at a time so using SRC2 should actually be faster, not just easier. To convert from the output of arithmetic operations, PD and SD disappear and DST simply has to be stored in two places; to convert to RFLAGS, SF/PF are easily computed from SRC2 as if PD=SD=0; conversion to LFLAGS encodes parity in bit 0 and mixes in SF as an even-parity value with the right sign bit. Unlike TCG, there is a single meaning for all operand lengths, which corresponds to either CCMPL or CCMPQ depending on sizeof(target_ulong). So the carry-out value still needs to be split---with AF in bit 3 and CF/PO in the higher bits of the target_ulong-sized env->cc_src. This is an acceptable tradeoff for the interpreter, in order to optimize lflags_to_rflags. Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_flags.c | 65 +++++++++++++-------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/target/i386/emulate/x86_flags.c b/target/i386/emulate/x86_flags.c index 3c4270a14c..c49d8bb836 100644 --- a/target/i386/emulate/x86_flags.c +++ b/target/i386/emulate/x86_flags.c @@ -30,28 +30,24 @@ /* - * The algorithms here are similar to those in Bochs. After an ALU - * operation, CC_DST can be used to compute ZF, SF and PF, whereas - * CC_SRC is used to compute AF, CF and OF. In reality, SF and PF are the - * XOR of the value computed from CC_DST and the value found in bits 7 and 2 - * of CC_SRC; this way the same logic can be used to compute the flags - * both before and after an ALU operation. + * The emulator always encodes flags in the same way as CC_OP_CCMPB + MO_TL. + * While for arithmetic operations ZF/SF/PF are computed from the same value, + * ZF=1 may be inconsistent with PF/SF for arbitrary RFLAGS values so CC_SRC2 + * is used for SF and PF. CC_SRC holds a carry-out vector that is used to + * compute AF, CF and OF. * * Compared to the TCG CC_OP codes, this avoids conditionals when converting * to and from the RFLAGS representation. + * + * The underlying ideas ultimately descend from Bochs, but with significant + * simplifications obtained by storing flags in three words rather than two. */ #define LF_SIGN_BIT (TARGET_LONG_BITS - 1) -#define LF_BIT_PD (2) /* lazy Parity Delta, same bit as PF */ -#define LF_BIT_AF (3) /* lazy Adjust flag */ -#define LF_BIT_SD (7) /* lazy Sign Flag Delta, same bit as SF */ #define LF_BIT_CF (TARGET_LONG_BITS - 1) /* lazy Carry Flag */ #define LF_BIT_PO (TARGET_LONG_BITS - 2) /* lazy Partial Overflow = CF ^ OF */ -#define LF_MASK_PD ((target_ulong)0x01 << LF_BIT_PD) -#define LF_MASK_AF ((target_ulong)0x01 << LF_BIT_AF) -#define LF_MASK_SD ((target_ulong)0x01 << LF_BIT_SD) #define LF_MASK_CF ((target_ulong)0x01 << LF_BIT_CF) #define LF_MASK_PO ((target_ulong)0x01 << LF_BIT_PO) @@ -59,19 +55,15 @@ /* OSZAPC */ /* ******************* */ -/* use carries to fill in AF, PO and CF, while ensuring PD and SD are clear. - * for full-word operations just clear PD and SD; for smaller operand - * sizes only keep AF in the low byte and shift the carries left to - * place PO and CF in the top two bits. +/* + * For arithmetic operations ZF/SF/PF are consistent so DST == SRC2. + * For operations that are not full-word, keep AF in the low byte and shift + * the carries left to place PO and CF in the top two bits. */ #define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ - env->cc_dst = (target_ulong)(int##size##_t)(lf_result); \ - target_ulong temp = (lf_carries); \ - if ((size) == TARGET_LONG_BITS) { \ - temp = temp & ~(LF_MASK_PD | LF_MASK_SD); \ - } else { \ - temp = (temp & LF_MASK_AF) | (temp << (TARGET_LONG_BITS - (size))); \ - } \ + env->cc_dst = env->cc_src2 = (target_ulong)(int##size##_t)(lf_result); \ + target_ulong temp = (lf_carries) & MAKE_64BIT_MASK(0, size); \ + temp |= temp << (TARGET_LONG_BITS - (size)); \ env->cc_src = temp; \ } @@ -93,13 +85,9 @@ /* same as setting OSZAPC, but preserve CF and flip PO if the old value of CF * did not match the high bit of lf_carries. */ #define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \ - env->cc_dst = (target_ulong)(int##size##_t)(lf_result); \ - target_ulong temp = (lf_carries); \ - if ((size) == TARGET_LONG_BITS) { \ - temp = (temp & ~(LF_MASK_PD | LF_MASK_SD)); \ - } else { \ - temp = (temp & LF_MASK_AF) | (temp << (TARGET_LONG_BITS - (size))); \ - } \ + env->cc_dst = env->cc_src2 = (target_ulong)(int##size##_t)(lf_result); \ + target_ulong temp = (lf_carries) & MAKE_64BIT_MASK(0, size); \ + temp |= temp << (TARGET_LONG_BITS - (size)); \ target_ulong cf_changed = ((target_long)(env->cc_src ^ temp)) < 0; \ env->cc_src = temp ^ (cf_changed * (LF_MASK_PO | LF_MASK_CF)); \ } @@ -255,7 +243,7 @@ void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, static inline uint32_t get_PF(CPUX86State *env) { - return ((parity8(env->cc_dst) - 1) ^ env->cc_src) & CC_P; + return (parity8(env->cc_src2) - 1) & CC_P; } static inline uint32_t get_OF(CPUX86State *env) @@ -283,8 +271,7 @@ static inline uint32_t get_ZF(CPUX86State *env) static inline uint32_t get_SF(CPUX86State *env) { - return ((env->cc_dst >> (LF_SIGN_BIT - LF_BIT_SD)) ^ - env->cc_src) & CC_S; + return (target_long)env->cc_src2 < 0 ? CC_S : 0; } void lflags_to_rflags(CPUX86State *env) @@ -304,16 +291,14 @@ void rflags_to_lflags(CPUX86State *env) { target_ulong cf_af, cf_xor_of; - /* Leave the low byte zero so that parity is always even... */ - env->cc_dst = !(env->eflags & CC_Z) << 8; - - /* ... and therefore cc_src always uses opposite polarity. */ - env->cc_src = CC_P; - env->cc_src ^= env->eflags & (CC_S | CC_P); + /* compute DST and SRC2 that reconstruct ZF/SF/PF. */ + env->cc_dst = ~env->eflags & CC_Z; /* DST = 0 if ZF=1 */ + env->cc_src2 = ~env->eflags & CC_P; /* odd parity if PF=0 */ + env->cc_src2 ^= -!!(env->eflags & CC_S); /* rotate right by one to move CF and AF into the carry-out positions */ cf_af = env->eflags & (CC_C | CC_A); - env->cc_src |= ((cf_af >> 1) | (cf_af << (TARGET_LONG_BITS - 1))); + env->cc_src = ((cf_af >> 1) | (cf_af << (TARGET_LONG_BITS - 1))); cf_xor_of = ((env->eflags & (CC_C | CC_O)) + (CC_O - CC_C)) & CC_O; env->cc_src |= -cf_xor_of & LF_MASK_PO; From 7c84752396d16c3379091fa8341c902aa67ec3d3 Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:09 +0200 Subject: [PATCH 394/627] whpx: i386: fix xsaves enablement in legacy probing path Without this, Linux will crash in a configuration where xsaves is expected. Signed-off-by: Mohamed Mediouni Link: https://lore.kernel.org/r/20260812082814.27217-2-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-cpu-legacy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/whpx/whpx-cpu-legacy.c b/target/i386/whpx/whpx-cpu-legacy.c index d341e6f4fd..3fb5ed79e3 100644 --- a/target/i386/whpx/whpx-cpu-legacy.c +++ b/target/i386/whpx/whpx-cpu-legacy.c @@ -113,7 +113,7 @@ uint32_t whpx_get_supported_cpuid_legacy(uint32_t func, uint32_t idx, if (idx == 0) { eax = supported_xcr0; } else if (idx == 1) { - eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1; + eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES; if (!whpx_has_xsaves()) { eax &= ~CPUID_XSAVE_XSAVES; } From 32452bac6d991e9778dd7a9fb2b3eed3a2b23d71 Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:10 +0200 Subject: [PATCH 395/627] hw/i386: fw_cfg: do not set VMX feature control on WHPX Hyper-V doesn't allow setting this bit on build 26100. Signed-off-by: Mohamed Mediouni Link: https://lore.kernel.org/r/20260812082814.27217-3-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- hw/i386/fw_cfg.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index d422302c1c..5903994a7c 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -13,6 +13,8 @@ */ #include "qemu/osdep.h" +#include "system/mshv.h" +#include "system/whpx.h" #include "system/numa.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" @@ -182,8 +184,15 @@ void fw_cfg_build_feature_control(MachineState *ms, FWCfgState *fw_cfg) uint64_t *val; cpu_x86_cpuid(env, 1, 0, &unused, &unused, &ecx, &edx); - if (ecx & CPUID_EXT_VMX) { - feature_control_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; + + /* + * Hyper-V in 26100 disallows this bit to be set. + * Otherwise a #GP gets raised. + */ + if (!(whpx_enabled())) { + if (ecx & CPUID_EXT_VMX) { + feature_control_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; + } } if ((edx & (CPUID_EXT2_MCE | CPUID_EXT2_MCA)) == From 3bfcd8ef6bd26cb80175f40f60e67bc6f42fa0a4 Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:11 +0200 Subject: [PATCH 396/627] whpx: i386: enable fast hypercall output Already enabled on Arm so extending it to x86. Signed-off-by: Mohamed Mediouni Link: https://lore.kernel.org/r/20260812082814.27217-4-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 634d542821..1800ba8eb1 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -3247,6 +3247,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms) synthetic_features.Bank0.HypervisorPresent = 1; synthetic_features.Bank0.Hv1 = 1; + synthetic_features.Bank0.FastHypercallOutput = 1; synthetic_features.Bank0.AccessVpRunTimeReg = 1; synthetic_features.Bank0.AccessPartitionReferenceCounter = 1; synthetic_features.Bank0.AccessPartitionReferenceTsc = 1; From 7b0516912e44e73ba0859e91aed848d5be26f05e Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:12 +0200 Subject: [PATCH 397/627] whpx: i386: synchronise PAT too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/cmspam/winq-emu hints that this might be wanted for some use-cases and it's a step towards full state sync: > Linux uses PAT to mark virtio-gpu / Venus shared memory as > Write-Combining. Previously the partition's PAT was not > synchronised with the guest, so the guest's MTRR/PAT cache-type > computation could fall back to UC for memory that should be WC. Signed-off-by: Mohamed Mediouni Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20260812082814.27217-5-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 1800ba8eb1..2739a80da3 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -115,7 +115,7 @@ static const WHV_REGISTER_NAME whpx_register_names[] = { #ifdef TARGET_X86_64 WHvX64RegisterKernelGsBase, #endif - /* WHvX64RegisterPat, */ + WHvX64RegisterPat, WHvX64RegisterSysenterCs, WHvX64RegisterSysenterEip, WHvX64RegisterSysenterEsp, @@ -624,9 +624,8 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level) assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); vcxt.values[idx++].Reg64 = env->kernelgsbase; #endif - - /* WHvX64RegisterPat - Skipped */ - + assert(whpx_register_names[idx] == WHvX64RegisterPat); + vcxt.values[idx++].Reg64 = env->pat; assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); vcxt.values[idx++].Reg64 = env->sysenter_cs; assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); @@ -962,9 +961,8 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level) assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); env->kernelgsbase = vcxt.values[idx++].Reg64; #endif - - /* WHvX64RegisterPat - Skipped */ - + assert(whpx_register_names[idx] == WHvX64RegisterPat); + env->pat = vcxt.values[idx++].Reg64; assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); env->sysenter_cs = vcxt.values[idx++].Reg64; assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); From 37ce6d8da75754f725db8cc27ae6c82a2e5b930e Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:13 +0200 Subject: [PATCH 398/627] whpx: i386: work around Hyper-V FP state oddities On Hyper-V looks like we need to fetch both the legacy and new state instead of being able to rely on xsave. Signed-off-by: Mohamed Mediouni Link: https://lore.kernel.org/r/20260812082814.27217-6-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 2739a80da3..56a8b16749 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -614,9 +614,9 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level) if (whpx_is_xsave_enabled(cpu)) { whpx_set_xsave_state(cpu); - } else { - whpx_set_legacy_fp_registers(cpu, level); } + whpx_set_legacy_fp_registers(cpu, level); + /* MSRs */ assert(whpx_register_names[idx] == WHvX64RegisterEfer); vcxt.values[idx++].Reg64 = env->efer; @@ -950,9 +950,8 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level) if (whpx_is_xsave_enabled(cpu)) { whpx_get_xsave_state(cpu); - } else { - whpx_get_legacy_fp_registers(cpu, level); } + whpx_get_legacy_fp_registers(cpu, level); /* MSRs */ assert(whpx_register_names[idx] == WHvX64RegisterEfer); From 93f38b6e8817280e1a51102d2dfd21115b8d4e88 Mon Sep 17 00:00:00 2001 From: Mohamed Mediouni Date: Wed, 12 Aug 2026 10:28:14 +0200 Subject: [PATCH 399/627] whpx: i386: inject back db When we get a debug exception other than int1, inject it back to the guest. Signed-off-by: Mohamed Mediouni Link: https://lore.kernel.org/r/20260812082814.27217-7-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini --- target/i386/whpx/whpx-all.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 56a8b16749..113f79afb9 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -1079,6 +1079,31 @@ static void whpx_inject_back_gpf(CPUState *cpu) whpx_set_reg(cpu, WHvRegisterPendingEvent, reg); } +static void whpx_inject_back_db(CPUState *cpu) +{ + WHV_VP_EXCEPTION_CONTEXT *ctx = &cpu->accel->exit_ctx.VpException; + WHV_REGISTER_VALUE reg = {}; + + if (ctx->ExceptionInfo.SoftwareException) { + /* TODO */ + warn_report("Was asked to inject software exception."); + return; + } + + if (ctx->ExceptionType != EXCP01_DB) { + warn_report("Was asked to inject exception other than debug."); + return; + } + + reg.ExceptionEvent.EventPending = 1; + reg.ExceptionEvent.EventType = WHvX64PendingEventException; + reg.ExceptionEvent.DeliverErrorCode = ctx->ExceptionInfo.ErrorCodeValid; + reg.ExceptionEvent.Vector = ctx->ExceptionType; + reg.ExceptionEvent.ErrorCode = ctx->ErrorCode; + reg.ExceptionEvent.ExceptionParameter = ctx->ExceptionParameter; + whpx_set_reg(cpu, WHvRegisterPendingEvent, reg); +} + static void handle_io(CPUState *env, uint16_t port, void *buffer, int direction, int size, int count) { @@ -2646,11 +2671,7 @@ int whpx_vcpu_run(CPUState *cpu) } else if ((vcpu->exit_ctx.VpException.ExceptionType == WHvX64ExceptionTypeDebugTrapOrFault) && !cpu_single_stepping(cpu)) { - /* - * Just finished stepping over a breakpoint, but the - * gdb does not expect us to do single-stepping. - * Don't do anything special. - */ + whpx_inject_back_db(cpu); cpu->exception_index = EXCP_INTERRUPT; } else { /* Another exception or debug event. Report it to GDB. */ From eb3f7fe382babbab44419603e81da56abb91d11a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2026 16:23:54 +0200 Subject: [PATCH 400/627] serial: clear transmit retry callback on unrealize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GSource is removed when resetting but remains active (and can cause use-after-free) on hot-unplug. Remove it before the character device is disconnected. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4125 Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- hw/char/serial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/char/serial.c b/hw/char/serial.c index 0729cd2ce9..4339562ab0 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -936,6 +936,7 @@ static void serial_unrealize(DeviceState *dev) { SerialState *s = SERIAL(dev); + g_clear_handle_id(&s->watch_tag, g_source_remove); qemu_chr_fe_deinit(&s->chr, false); timer_free(s->modem_status_poll); From 501187d0bc62a46628acc25e0ea0187094f04246 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Aug 2026 15:14:07 +0200 Subject: [PATCH 401/627] meson: make linker warnings non-fatal on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These cause a werror=true build to fail with Meson 1.12.0, as it now makes linker warnings fatal as well. Cc: qemu-stable@nongnu.org Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 49a5baf5b5..40e3f4ec44 100644 --- a/meson.build +++ b/meson.build @@ -602,6 +602,11 @@ if host_os == 'windows' qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-seh', '-Wl,--nxcompat') qemu_ldflags += cc.get_supported_link_arguments('-Wl,--dynamicbase', '-Wl,--high-entropy-va') endif +if host_os == 'linux' and get_option('werror') and get_option('prefer_static') + # On glibc systems, glib causes warnings about getpwuid, getpwuid_r + # and getpwnam_r not being supported with static linking + qemu_ldflags += cc.get_supported_link_arguments('-Wl,--no-fatal-warnings') +endif if get_option('fuzzing') # Specify a filter to only instrument code that is directly related to From 2a428c8541ec5e9be54aad5f0a446ec8172226c9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Aug 2026 15:12:55 +0200 Subject: [PATCH 402/627] dockerfiles: remove packages required by Avocado MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make our CI containers smaller, by removing a handful of packages that were only included as dependencies of Avocado. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/macos-14.vars | 2 +- scripts/ci/setup/debian/debian-13-ppc64le.yaml | 4 ---- scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml | 4 ---- scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml | 4 ---- tests/docker/dockerfiles/alpine.docker | 3 --- tests/docker/dockerfiles/centos9.docker | 3 --- tests/docker/dockerfiles/debian-amd64-cross.docker | 4 ---- tests/docker/dockerfiles/debian-arm64-cross.docker | 4 ---- tests/docker/dockerfiles/debian-armhf-cross.docker | 4 ---- tests/docker/dockerfiles/debian-i686-cross.docker | 4 ---- tests/docker/dockerfiles/debian-ppc64el-cross.docker | 4 ---- tests/docker/dockerfiles/debian-riscv64-cross.docker | 4 ---- tests/docker/dockerfiles/debian-s390x-cross.docker | 4 ---- tests/docker/dockerfiles/debian.docker | 4 ---- tests/docker/dockerfiles/fedora-rust-nightly.docker | 4 ---- tests/docker/dockerfiles/fedora-win64-cross.docker | 4 ---- tests/docker/dockerfiles/fedora.docker | 4 ---- tests/docker/dockerfiles/opensuse-leap.docker | 4 ---- tests/docker/dockerfiles/ubuntu2404.docker | 4 ---- tests/lcitool/projects/qemu.yml | 4 ---- tests/vm/generated/freebsd.json | 4 ---- 21 files changed, 1 insertion(+), 79 deletions(-) diff --git a/.gitlab-ci.d/macos-14.vars b/.gitlab-ci.d/macos-14.vars index def77cfdea..0c187624dd 100644 --- a/.gitlab-ci.d/macos-14.vars +++ b/.gitlab-ci.d/macos-14.vars @@ -12,5 +12,5 @@ NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' PKGS='bash bc bindgen bison bzip2 capstone ccache cmocka coreutils ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libcbor libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python-setuptools python3 rpm2cpio rust sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 vulkan-tools xorriso zlib zstd' -PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli' +PYPI_PKGS='sphinx sphinx-rtd-theme tomli' PYTHON='/opt/homebrew/bin/python3' diff --git a/scripts/ci/setup/debian/debian-13-ppc64le.yaml b/scripts/ci/setup/debian/debian-13-ppc64le.yaml index e64321357d..9acd99a743 100644 --- a/scripts/ci/setup/debian/debian-13-ppc64le.yaml +++ b/scripts/ci/setup/debian/debian-13-ppc64le.yaml @@ -105,9 +105,6 @@ packages: - openssh-client - pkgconf - python3 - - python3-numpy - - python3-opencv - - python3-pillow - python3-pip - python3-setuptools - python3-sphinx @@ -115,7 +112,6 @@ packages: - python3-tomli - python3-venv - python3-wheel - - python3-yaml - rpm2cpio - rustc - sed diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml index 12b0e38a22..5c948109df 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml @@ -106,9 +106,6 @@ packages: - openssh-client - pkgconf - python3 - - python3-numpy - - python3-opencv - - python3-pillow - python3-pip - python3-setuptools - python3-sphinx @@ -116,7 +113,6 @@ packages: - python3-tomli - python3-venv - python3-wheel - - python3-yaml - rpm2cpio - rustc-1.83 - sed diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml index 56299f4cc2..010b7f86aa 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml @@ -104,9 +104,6 @@ packages: - openssh-client - pkgconf - python3 - - python3-numpy - - python3-opencv - - python3-pillow - python3-pip - python3-setuptools - python3-sphinx @@ -114,7 +111,6 @@ packages: - python3-tomli - python3-venv - python3-wheel - - python3-yaml - rpm2cpio - rustc-1.83 - sed diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 118c6e8eea..8a5a355e89 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -83,14 +83,11 @@ RUN apk update && \ pixman-dev \ pkgconf \ pulseaudio-dev \ - py3-numpy \ - py3-pillow \ py3-pip \ py3-setuptools \ py3-sphinx \ py3-sphinx_rtd_theme \ py3-wheel \ - py3-yaml \ python3 \ rpm2cpio \ rust \ diff --git a/tests/docker/dockerfiles/centos9.docker b/tests/docker/dockerfiles/centos9.docker index 0d5b5fa7f5..e38cd692db 100644 --- a/tests/docker/dockerfiles/centos9.docker +++ b/tests/docker/dockerfiles/centos9.docker @@ -96,9 +96,6 @@ RUN dnf --quiet distro-sync -y && \ pkgconfig \ pulseaudio-libs-devel \ python3 \ - python3-PyYAML \ - python3-numpy \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 061cd8e9b8..823606dc52 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 3dfa60fdfd..ed58e089ec 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 401c64269c..0843f7428a 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-i686-cross.docker b/tests/docker/dockerfiles/debian-i686-cross.docker index 8b60c7b085..caba08f842 100644 --- a/tests/docker/dockerfiles/debian-i686-cross.docker +++ b/tests/docker/dockerfiles/debian-i686-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 2a7e8cba05..17018c0dab 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 349de3a0bb..2408d453c2 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 8bc42b1e00..2b0a344c2c 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -41,9 +41,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -51,7 +48,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker index 413986d3f0..064b2ad1f1 100644 --- a/tests/docker/dockerfiles/debian.docker +++ b/tests/docker/dockerfiles/debian.docker @@ -113,9 +113,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -123,7 +120,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc \ sed \ diff --git a/tests/docker/dockerfiles/fedora-rust-nightly.docker b/tests/docker/dockerfiles/fedora-rust-nightly.docker index 4f84b80379..dcad3af2a7 100644 --- a/tests/docker/dockerfiles/fedora-rust-nightly.docker +++ b/tests/docker/dockerfiles/fedora-rust-nightly.docker @@ -104,10 +104,6 @@ exec "$@"\n' > /usr/bin/nosync && \ pkgconfig \ pulseaudio-libs-devel \ python3 \ - python3-PyYAML \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index c1e63feb46..bce350dfd8 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -44,10 +44,6 @@ exec "$@"\n' > /usr/bin/nosync && \ ninja-build \ openssh-clients \ python3 \ - python3-PyYAML \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index a6996917c4..c541f5d5b1 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -104,10 +104,6 @@ exec "$@"\n' > /usr/bin/nosync && \ pkgconfig \ pulseaudio-libs-devel \ python3 \ - python3-PyYAML \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index fc363c647c..8d8631bbcf 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -93,12 +93,8 @@ RUN zypper update -y && \ pcre2-devel-static \ pipewire-devel \ pkgconfig \ - python3-Pillow \ - python3-PyYAML \ python3-Sphinx \ python3-base \ - python3-numpy \ - python3-opencv \ python3-pip \ python3-setuptools \ python3-sphinx_rtd_theme \ diff --git a/tests/docker/dockerfiles/ubuntu2404.docker b/tests/docker/dockerfiles/ubuntu2404.docker index 27992e34fd..f027eef022 100644 --- a/tests/docker/dockerfiles/ubuntu2404.docker +++ b/tests/docker/dockerfiles/ubuntu2404.docker @@ -113,9 +113,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ openssh-client \ pkgconf \ python3 \ - python3-numpy \ - python3-opencv \ - python3-pillow \ python3-pip \ python3-setuptools \ python3-sphinx \ @@ -123,7 +120,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-tomli \ python3-venv \ python3-wheel \ - python3-yaml \ rpm2cpio \ rustc-1.83 \ sed \ diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 7d185cda3c..b3c9993672 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -91,11 +91,7 @@ packages: - pkg-config - pulseaudio - python3 - - python3-numpy - - python3-opencv - - python3-pillow - python3-pip - - python3-PyYAML - python3-setuptools - python3-sphinx - python3-sphinx-rtd-theme diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json index 08b6eb6155..dfa8b41a52 100644 --- a/tests/vm/generated/freebsd.json +++ b/tests/vm/generated/freebsd.json @@ -49,14 +49,10 @@ "ncurses", "nettle", "ninja", - "opencv", "pixman", "pkgconf", "png", - "py311-numpy", - "py311-pillow", "py311-pip", - "py311-pyyaml", "py311-setuptools", "py311-sphinx", "py311-sphinx_rtd_theme", From 51ea699eb84677490312bb09b3c1e9cfb645152c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Aug 2026 15:09:16 +0200 Subject: [PATCH 403/627] dockerfiles: update CentOS Stream 9 to Python 3.11, Meson to 1.12 Python 3.10, which is a requirement for Meson 1.12.0, was never packaged for CentOS Stream 9 so update directly to 3.11. CentOS 9 does not install meson from PyPI because configure will install it from the bundled wheel; this way CI covers that path as well. This is guaranteed because, when using a non-default Python, basically nothing is installed. The opensuse-leap-15.yml file was not in use anymore, so delete it while touching tests/lcitool/targets/. Signed-off-by: Paolo Bonzini --- tests/docker/dockerfiles/centos9.docker | 16 +++++++----- .../dockerfiles/debian-all-test-cross.docker | 2 +- .../dockerfiles/debian-amd64-cross.docker | 2 +- .../dockerfiles/debian-arm64-cross.docker | 2 +- .../dockerfiles/debian-armhf-cross.docker | 2 +- .../dockerfiles/debian-i686-cross.docker | 2 +- .../dockerfiles/debian-ppc64el-cross.docker | 2 +- .../dockerfiles/debian-riscv64-cross.docker | 2 +- .../dockerfiles/debian-s390x-cross.docker | 2 +- tests/docker/dockerfiles/debian.docker | 2 +- .../dockerfiles/fedora-rust-nightly.docker | 2 +- .../dockerfiles/fedora-win64-cross.docker | 2 +- tests/docker/dockerfiles/fedora.docker | 2 +- tests/docker/dockerfiles/ubuntu2404.docker | 2 +- tests/lcitool/mappings.yml | 26 ++++++++++++++++++- ...ensuse-leap-15.yml => centos-stream-9.yml} | 0 16 files changed, 47 insertions(+), 21 deletions(-) rename tests/lcitool/targets/{opensuse-leap-15.yml => centos-stream-9.yml} (100%) diff --git a/tests/docker/dockerfiles/centos9.docker b/tests/docker/dockerfiles/centos9.docker index e38cd692db..8101370a2d 100644 --- a/tests/docker/dockerfiles/centos9.docker +++ b/tests/docker/dockerfiles/centos9.docker @@ -95,13 +95,11 @@ RUN dnf --quiet distro-sync -y && \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ - python3 \ - python3-pip \ - python3-setuptools \ - python3-sphinx \ - python3-sphinx_rtd_theme \ python3-tomli \ - python3-wheel \ + python3.11 \ + python3.11-pip \ + python3.11-setuptools \ + python3.11-wheel \ rdma-core-devel \ rust \ rust-std-static \ @@ -131,11 +129,15 @@ RUN dnf --quiet distro-sync -y && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc +RUN /usr/bin/pip3.11 install \ + sphinx \ + sphinx-rtd-theme + ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" ENV MAKE="/usr/bin/make" ENV NINJA="/usr/bin/ninja" -ENV PYTHON="/usr/bin/python3" +ENV PYTHON="/usr/bin/python3.11" # As a final step configure the user (if env is defined) ARG USER ARG UID diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker index 2dc580552e..833185f607 100644 --- a/tests/docker/dockerfiles/debian-all-test-cross.docker +++ b/tests/docker/dockerfiles/debian-all-test-cross.docker @@ -47,7 +47,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 823606dc52..9e30457ca7 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index ed58e089ec..b9b94e5e6f 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 0843f7428a..aa412ff66f 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-i686-cross.docker b/tests/docker/dockerfiles/debian-i686-cross.docker index caba08f842..d07eac84fe 100644 --- a/tests/docker/dockerfiles/debian-i686-cross.docker +++ b/tests/docker/dockerfiles/debian-i686-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 17018c0dab..7302c8236e 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 2408d453c2..aa5a881cab 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 2b0a344c2c..82eae4fc2c 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -66,7 +66,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ dpkg-reconfigure locales && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker index 064b2ad1f1..3a4f208ccf 100644 --- a/tests/docker/dockerfiles/debian.docker +++ b/tests/docker/dockerfiles/debian.docker @@ -145,7 +145,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/fedora-rust-nightly.docker b/tests/docker/dockerfiles/fedora-rust-nightly.docker index dcad3af2a7..0f3dc370a4 100644 --- a/tests/docker/dockerfiles/fedora-rust-nightly.docker +++ b/tests/docker/dockerfiles/fedora-rust-nightly.docker @@ -145,7 +145,7 @@ exec "$@"\n' > /usr/bin/nosync && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index bce350dfd8..6f972f6173 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -66,7 +66,7 @@ exec "$@"\n' > /usr/bin/nosync && \ nosync dnf --quiet clean all -y && \ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index c541f5d5b1..99bb38a366 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -145,7 +145,7 @@ exec "$@"\n' > /usr/bin/nosync && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/docker/dockerfiles/ubuntu2404.docker b/tests/docker/dockerfiles/ubuntu2404.docker index f027eef022..a5c22231f9 100644 --- a/tests/docker/dockerfiles/ubuntu2404.docker +++ b/tests/docker/dockerfiles/ubuntu2404.docker @@ -145,7 +145,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==1.8.1 +RUN /usr/bin/pip3 install meson==1.12.0 ENV CCACHE_WRAPPERSDIR="/usr/libexec/ccache-wrappers" ENV LANG="en_US.UTF-8" diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 62fe60d047..1816556dde 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -3,6 +3,30 @@ mappings: bindgen: Ubuntu2204: + python3: + CentOSStream9: python3.11 + + python3-devel: + CentOSStream9: python3.11-devel + + python3-pip: + CentOSStream9: python3.11-pip + + python3-setuptools: + CentOSStream9: python3.11-setuptools + + python3-sphinx: + CentOSStream9: + + python3-sphinx-rtd-theme: + CentOSStream9: + + python3-venv: + CentOSStream9: python3.11 + + python3-wheel: + CentOSStream9: python3.11-wheel + meson: # Use Meson from PyPI wherever Rust is enabled Debian: @@ -23,7 +47,7 @@ mappings: pypi_mappings: # Request more recent version meson: - default: meson==1.8.1 + default: meson==1.12.0 # Drop packages that need devel headers python3-tomli: diff --git a/tests/lcitool/targets/opensuse-leap-15.yml b/tests/lcitool/targets/centos-stream-9.yml similarity index 100% rename from tests/lcitool/targets/opensuse-leap-15.yml rename to tests/lcitool/targets/centos-stream-9.yml From 4c8c1320367a5b84864700d4634a8f07aed4753a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Aug 2026 10:27:10 +0200 Subject: [PATCH 404/627] python, meson: update meson required for Rust to 1.12.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meson 1.11.0 brings support for parsing Cargo.toml inside QEMU's source tree, and Meson 1.12.0 brings support for cross-compilation of Cargo subprojects. Together, these two features allow QEMU to remove hundreds of lines of manual compilation scripts. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 4 ++-- python/scripts/vendor.py | 4 ++-- python/wheels/meson-1.11.1-py3-none-any.whl | Bin 1078534 -> 0 bytes python/wheels/meson-1.12.0-py3-none-any.whl | Bin 0 -> 1106208 bytes pythondeps.toml | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 python/wheels/meson-1.11.1-py3-none-any.whl create mode 100644 python/wheels/meson-1.12.0-py3-none-any.whl diff --git a/configure b/configure index 6ddfe4b534..7f637c018c 100755 --- a/configure +++ b/configure @@ -1166,12 +1166,12 @@ fi # detect rust triple meson_version=$($meson --version) -if test "$rust" != disabled && ! version_ge "$meson_version" 1.10.0; then +if test "$rust" != disabled && ! version_ge "$meson_version" 1.12.0; then if test "$rust" = enabled; then $mkvenv ensuregroup --dir "${source_path}/python/wheels" \ ${source_path}/pythondeps.toml meson-rust || exit 1 else - echo "Rust needs Meson 1.10.0, disabling" 2>&1 + echo "Rust needs Meson 1.12.0, disabling" 2>&1 rust=disabled fi fi diff --git a/python/scripts/vendor.py b/python/scripts/vendor.py index 1bb59d863a..9b4c763f9e 100755 --- a/python/scripts/vendor.py +++ b/python/scripts/vendor.py @@ -41,8 +41,8 @@ def main() -> int: parser.parse_args() packages = { - "meson==1.11.1": - "9b3a023657e393dbc5335b95c561337d49b7a458f5541e47ec44f2cc566e0d80", + "meson==1.12.0": + "71f133147fa0fcfe8f4df49fa1045771064947834538409e5d97b3613aac8b4e", "qemu.qmp==0.0.6": "5d7c5af0e9de427696e3bf72e333965c3a697929f77f6b7ddc30c989fc7b539b", "pycotap==1.3.1": diff --git a/python/wheels/meson-1.11.1-py3-none-any.whl b/python/wheels/meson-1.11.1-py3-none-any.whl deleted file mode 100644 index 8dc3c9f2f6db1215bd9d64eaec84dce03fd79f1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1078534 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 z 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 z zeaZO}e4zt;96Q7)VHH#@lcs5`B%b=^md|CO!<*Eqx7=gtP4h0R}lM_1!$4xtii)?G5zQ48YnO&P% znzzpixG$*vyN4gxiFMpu?iw(sJ0o^v8l(AKmPrV4xmS4i2XF5X7X8OO`Pub`=v_WZ z9b-QgWPo@Oo^UydMNv|qspyRBSuaG$V^-eAW6@56LuFdK%9c1w;)r#!>K~hwtnXS8 zmS5#Z$Z zr$YI{#cKSLAAW&S!GQj@5+SqHmUH6X?3q!KCDt)j1r`v^sWsB;?DhV5{*yRw!!)pO z3geWR?BYiDs%iI04*Qmgq8N7x2oCxesJhL+2IdSUjZQj*Z z+Tsa}MDhU;4HWNN5=l(<9_MJP#lAz~@i|sGWWmE)MC-=@B_Q4fT_eLnJ)5Pj+e8f? z^~Z7^3qH&gwFDG%T^WH}(vpoh_P&OIiL_M*vtQ>HfR9d@+c zOjCZBDeBPc<2)AlJ|Petn{C#I?On&3Ks}7+)(&5{9aq7iQ?A&b= z)07)551uT4hC86S2kVquWJqrw# zW2BH!!YTE(C($&IKGq^lieui&c?ma38UwbTLrB#&uqtu zmQ)hyFmX_8c?*y-ePJeQtw^5EvpkSP*-!Oi8Zvk*(q;w8^SL#lcG)D&=RoHm!Ik2) zhij?AUqpdA_z7}Ve39|(;`?*+ZH{IXobp23XAP~To0K|~NSqgd!j|A#J{1P$M`-H> z$b;h5KhM_o-$vg3WBAA5vYC49VVDLs!*%P3U91V3AROQ!R)qIMrN3{5iD>$f6497H z^UsOoaLS#1h;vNF5^oa<=w6B079#FTu|Mab58afI%H8w*BD8u3RP()RcvbaEUCfV^ z!G|JqWJzYxvN=>z5FX^;7h@BuhVW!h{mYvA!43*kZW=Hvka-RiomC9$IJ3+6B3IhJ ziHQ0r?wJacnE|m{EYX7VfXlsD!3-&f6DG2hi5px#yM09GM^mpf{IEk+n|CYh?UXWM zn1ro0a+f)%Xy4F;4z3$cAwf*HUR$swY16u}kU{kpe}7|4_duE${|^MlY(YQ4RwwX$b8B;(R^(q=c|-zU*qe`=9Yl-A5@v^=1<n9n*G&Wv|9biU9X8QkXIuYT`+b~(7*uHnng>}kA(WU z^iYIH`axW_#IBoQEa`z~+apv4hfH16i{YXrXI~{P7+z}zPYy+VNN}WjIrxG2TEWiw zC)k7NqN$PT+*%OL(Sl&~KK%O+j4xJB^_0&0hwGy&jS483q*p6dM1A2QBCS6f0|sja ztm1G3Ev;bs?0i=MXmGNMJr_HDItx_T={fpAvopH9W<5p>@nWTz0y^++kHd^ddvHz~u^`;sp72F9FAh*~x?_7a z;ZMUgkjMxAQbi0vricJDY&&IOh?@}9G8s1WNrrxw*P+!f)AnNOQ5!&)M+S%k9v|cW z1pJDE>3uapQ2tlI8a-=LI@gC|Qv)cEl6zyrS67L+kend3hM*(67Jcq*y5W>Y+ejL|01 zqC;;yS6GZtb52#4pJD68Owhl9_9g`?<#zEymt0NKNFXNlu>O++1RA6p8M`2sjP|Y; zXTwRd;XXb>W~5%Th0oBn+CdUt8)wy>@0j5i^sbnia!}=4Vdb$->PB@ama5rnF1)NX z-0YnJlxr%rdCRiO~$3o{=9Kv)Lkx)QO4@tm%a0sK?i zVw8!4`ilST%_+uc43xMONVBk6%2VYa%Ex3nc(@hN(E9-%(6vO?=TW67(ls>J>Gutl z7BlrZMnkR|MnPGwrWwwzC&LhuN?%3O7#zQ?X$?A>gO}~HF@Kg1 z%Ubp57uP-0M4x@J8*J>Ep8}BjnZ*uyXC{f2d}t(Si;kfRZ1=T}M9hiu=+r10YR#oq z#SyOmW)#;+Z)2j)SZTDfuuq1oRV8xMvjM02E>*L1#BvHs=TQL^w-1=oj@|&hL7c9- z7VOT_VYwd9+A5EkFGOd0kkmAD4-D?V6j!wNuo=l#9*cf1aApK2-TapBkJ9BGQE+p| zi3Ylt)TbTkyK8^%D2XgGm4DwT}a~Kc3db67Gd12 zZ7$3O!S%FXb%QCsbP;JSg=+NoMXB`QPr$fhgV{DEAo}8#mj-(dm(Pz6Y&JQeAG>wU z-u@Nogn<1$!40P*2XVA+lvdWmy;S@LpOI%2GrK<$K20sO!zHZKhDd<~H>9oWAqxPP zb!BTC*;hh3yum@h%lK=8|B%26l;jYoXrNy4894z7Q$#{g;BZodvH-^3n)~2*O=_u3I}^ zJ}~-#?KuWC-vbS%X*_T~VzARM^3fI!!My(}y|EFPOFN zOy#p&+Td{{w<7*e<%5gRKT&l}gqwLz^TZ~fhuRcsvIb)3@RIE2gtMErZ3~R^z zvkuQ<*Y4O53iiPH5wgGVC0sLdnr=@u)=%MgjMp9k^fD^Nzl~T&aYP7BD1Wr?ReX?u zp(uDbH|=b$g59y3cA`yRTVEPzhNB4fO3c_~zxvoq(*at8S^DE9}hD@{M&c_hT9`6#O%fm3WsA}z5Tp?|3GEf07rf^ zmR^P7rr*-rq`2o?T~7ZWvd*bHuyEV9v29gs+qP}nwr$&XDo!f4ZQHh;oZNQL!`W>= zt$#4T)#jL^_q?-yd-n&!urknB)$muRpAYmvHr^a@lL3)dE88QW5++=y$euP;LBk83 zj8dQH*o7~|(--rva)#arDlkw|0i=gJr~r7BqF%@W6>iu3Aw*u$=^1e&J>XURXv~79 zipmqK7n-e1b$Fb!RZxkC;2{WJ$V{BxubxYSP7?#sAcKXk5ojn<4~q`Pp=bQD=8W)T z@oUn`=2l|Xwvl)B7^g&?`ME9^c{I1zS$00D2+ts<_{$@g4Wspe#)MpmJ4EsiYu^*6 z-J(FPV^v)3kGPa44_o63-xf06e@A{aQ-r?Q3RQa8U0E>|c1KyV&FG}TS9?36PZ@&* z=zpw>m#|;EsI?D!t@`=iPgy3%-HHeKJ?~y=n``0DE^*qovy6tvO;U1n`Uxp}X=|1E zJo{afAbB#{D;QRV-_{q|Z=vV+!G_np0le|pKBS~2eow!qhp8JtMURyY7{#olQ0y~K zQoLLR0_y8!qngR=nd3Ne4eyNKW4JTP9BU>eqQBR~6$=LG59ThkCT!K%T6>2*3d0y_rjvdggO~`LH$m^Z>+#N8S99AhBCwBO2V`R-vAs4St8yicUnnqxK zeA>radgbW++B!KoVd0}uP6wtf9rF$v2+n6`?v|W=j2Pt8 zm0#7jJREqq+qz8Eg@NmGG6d{1BL1ksy}zr7&TqCE-eHk2npC529gQL64dtHm!?FvO3I$j=J361qPyU`3?dy#{zHN^IebU+?mS~!r zUU5)sJ1SsI={H$J-E8Q#M^eawXI0t3xvxXAzhX;Fze-5 zq9UKc`)M8<7V=T2*u{BAgRQF2+F|yYCqq%Pva}KSZE$x<4GiC*Ni}}B%Js!1MXD;s z^_qWG5kP*tr32jH0MrAQk+XU|`~&o#0X1I{@QBfGKpp1@0D$>l0kwsrovn?Dt@Ce0 zeZ+I+cp&Qd^MvBGsSL=ewE9F^q3m2j+)%7@QI(>cxcrP-)E_t~9|#J>4Un9=eF=QT za<g{e}xu9=EFIf~vYE1;oU|!?VTn#ZshpdH;EPl9OaOT$y@Cu;^)7&#@ z+Twj;b8mWq%2l3rQQF#ewYtH!)4k>KaeRgC>N2qgzP*e(@y0`UaRl_sj532R8~FKT zd-V8-TRq8Jb6C1V(q)}!A8RkHX>LB2>C(60)N`o}Eu)}9yR9+OP+9uJV$srk*jRWV zqqbsFiMx1}&Z7NwzC2ObZlEzyvsk2|lj==cFe@H`rQbX{QMmuT(7xxfY_fd-I^9TJ z`fY@d*qe@C0$--f8T9x2+@*79S7?#zo%>+XeUcZ#9=wI6Y9u{pMM}5ChIQnoGr?|T zap{xy@WEQeb?qO@RE;h6w9w7EiH5Vq^5#DyrgyhW?3mu==0R1$+IXI#Jigl|zK@3P zgt$~0p9N#+t)o*WYL%3fll?YA;M!|57Zy5OZBB1BWsSyeBy-8dxJnP$2Md2N88v(L z(;)b@KR*msP}XE8@egpRY$+Gdm4wh}E;sD#>k@1qqvs7FMXvhT$qn5=; z#MXeYBFgwok0M)Ccfv@u=6{rLpwneMX0ocQs}~v<9*ut1(Wc!A>7xf0N_v+6cIZqF}r`u>;nUPmt?9l8LSgoqG zi|}<;oMgG7{D45;fesW5{H~cyjCD%5jVF_T<_j81EmyQzfrePX;iMu}ZWj2$r<90M zsVT_r&NT7ZF`|z*pskCk|ukUIDvNi`avTw=gKVc)kG1-6+i6QwNq!Lvm- zytsKdrGC-W;x0oQ!auQOk-L}JXeBq(w2J4*ItST{`}Dfa*=MCIiIAYZU-txBEthF3 z8#bAV88HDuam{3Ce&J%H+O44?Ce=$dVEj^0Qfe*b2vK0CpqF5mYt|R6{$1v(088hw zIsKimAfM9Mxm$C{**PBIL39l@z>fm<{tHQZ=Y^4E52w&Dw_(RtD55v((J`JpV{gtb z$TLJZ=}S(}A_HHN(Ljno4^xN`47KSHe=8UWxH~{m!>pZ@mKUmwiFYN8MH3jqZd*Ky ze68y%2i3_rtU#XSom&EVJ60jShazme8ans!ry7w^0J#`*Kui38ZVc8fbeT2#E=R)x zw*daU&~Td%QLU?IyS;)iC#@#(`}A%Dd)Z*MbY=%lSEx-z4-+=gqXFUjdYv0YyGl^L z1nQU+6Q{NCKYZ>E6qs)&nmTv@g-K3|`)9ow)PESrOe_TC2MkX6M{rWa!(auXfi?lW z@9m|kfywlRpvvK(0>cAVEWxzuE1V4etwej8%2YQr3wyutss1hIq%j9h9dF|ksFqb^ zxO$b!^=NPb4>-C~VF!lqr4k$SzhG^A#;aG=ZH1Yw?o!klUjX1lndJhBv$zom$Zgu} zd0>Au{uuyM{HLS2bEU&V^(`(Iar(eXQOx=bH0`J+m&Cue+_63`+l#y#b_-fwn3v*` z8g*xny!;qpuwkpl#)bn1#!K=6!X4V>hFRWobsO%)-vzAES!;GE*-O8;X)!hSZF1AQ z&0gK%_Vjl=F0<4&)Kq{lN%fOJg?uD+(l$*0qAg+St7uh$7v%~F{Z}1(+IIV0uDB?_ zu5Tm^@BeIVUo2T~5RgOEO|6jBxM2%Gin~C>t2wwF5Zd14kr;UkB2dzriPa%Xly7Ewx7q3O4l8e4?&KdH2%w?q3{T| z(Ldl$MEaDfBQU0}zM_?I!ASUnQ-7g4wJwPVMT)nfI_=xPb~SGX^32czzjJ(995*v6=$H2qZf|Zh@}uD zQvp~c3UivgFmz0MTg%Pe5)KHaHL_E$P z;2%DVOg9to2Ioq;f`0FF2y+*bx*SZatj$_)%q1Ys7u=M`ZFLHC?0DOZCYD%K+WuAV z`9-K{+ZKm7pNP99`K+7wRBB!5A!FcdFK^{RBt~144>UBKy0Nyn?A9T_wWC15sAQAB z85SZf1Q09r<2%FYKm*6WMgWm=2=t-a;uXR|L*Z@H;PQY$K{jGlr9*anJq&O09?P^z zkmFJFrMsg;7{o)4ZU+ko6ipf-%t&4T^^m@fGI{VIuIk0|E6a62rQ;!QI3u;z*W2H5 zANd*1OGHUNwAFe_(_Tc~(ge?`V~ju7si3mPB#R*qWkz8gQeiCER8eehq@O-ngbFsD zA0byor`NLSD#>hq$-|YID}E+Yl+BvEdWVmMnX8QKxMMIn;$ebgpa$%pBLoN|MQUhY z9blM=to=k^#{skeTf}y`JTBkL<&cP2jRVnt;M7899#^MO1BwI1Bl4F(d^W8%H>E}6 z+=jf=1R_@T;8&^L@<)D=9VFy9t1#{qL89LHl9^Q*_obBKy2)9v19AuvSjwtZDj0Q3 zcPCFrHzY$^m{5pY)L_`GF}?4gW$$l{B2zDX@Ei1+z(Xm>J<>8WHAz5caFPE%L|3)L z2=k_Lvz?OJjy9ax23+L%P!dv#MnyOt2LinpF|^@}hv8JP8)VU!e6NEZLq7X%6w;GK zRyB)`iK#4Y@p=)=q5wzeK^k0Y@5)AK?_nq1DRu{r(4Uf=3RcuII;^ic$T*eJ4xpaS zD?>B%zzCY&VF>pjp1Iy?@D~{SHl_4bQ!hZu&;&5=U#dGKvs8oXVBWqBGo^@l+loOD zBh)GGVc1=fq!GwA(N9X8{)xN2w5%9U^jI`zlRjj$e9^9=LMIpIs(Fm6IdW4PT_hT; z`ottMZUqWgbTg%dPjS?d(B+zvZ*dly;lHwf{4ZQ<)9Cg+MJ!`J#o4*;zav6FaUbne zsEvvqS;g6_+UbE7jpte*Xe4!em4Jk%IA{^|odL;aY>d(&fLl@(ZMV8Pa3xi~Nm|{S zlk^Bv89Rn9FIU#6$yLtE=C^}r_aUgEv}gP;N|wQ|*#1Rc%apui(Gq1cHjt87gv)$% zy*omgslQXLgMcHqm^#`kuw8azpx)#*YwS>|C8q9b>cjJ_+ieq&?1uHq8##TDIu!Bq zgoTp%r=m>z)Bg`G6S#YzbtisPt5f+&Fuxm|&EqQDt^aXS9eH`{DN&NCQvRQ$iVVsb zeTLn;XzLG`@bN5zz_XqS+YZ~c>uz5gOJe%PyLYZvu*!}iQM*q4M4DANq`Nl_lT&=Mu?s@AR^UX_b952x+@`eX9f%=uE`|>ad5@5EjKXw*OqQY{8ADdtL+Jj?#`2bJ@OtkyLj8tR6<;yk9g48b*%? z$y8BzGnfl8Q5ylNF*+O()RH-NI2w9Pg>WK>2;aIAyOt+V`$y83@*V_8H&vn3hZBu#B>g-` zs^nLw95PtHKo=zX;y?_6%fr%FLP{jRFlleP`E(hqFyoQo+AT@iB5rE@`S7t-5ju^H)2oJ7CxE>QcgAdaI5ZSFk&l;LYij+edPDG9Lwp=*_ zxor4Y@C=Q~9aUxK`BdPUO<_)7b!<*CMu?>;Ei;XP3Z{n2*RUvViz9VFCc^DSe(>c(H;e5oz;$Xs^A&nADxr01svpjjnEL+OF?U zEtT7J2;aeB)}$kmQ}b-cATyp6-k;SnmSr$7b(@S`dliLDhu3(Yz>h6~K}pH=LhT77 zERUj-QoGtG@t11ig0jC(eF?O84mauO8tx#ytq1fVY;Ick%?skLr{a~{fd)@Wx3RsC zzLu%Rm$hoJnT*TMt=4Nc@LC7q>$KtKq^aczN?1e@qZQ{%fF7;?uK6_S>O%simM;dg z=Y;dvvKHq~f)xaI;T&Hc>`*@24p-;aBx8#Gqqs{k%3IGZrt)0^g@(U_H=`g&%*-6m zM(cWh7=!iK1;c}=0-`o1G3T08d1wjhDbgxqE=myBI>8WeGeTcP=cZQzdk{PZ1m2Vg z%o&pGyUNGM$Lmu|e46QV&d!dqN3Ls+c#Q!FgBWIB-bq=WzjLpS_Y0R)%&Qf3Uu8}J;+N-e-AU2Kf}jBT2ur;)$|Ee%7Dx& z)0zf&MjC8OK%GBwL*JpMn8XJ5E6Cb_=kI+CCGuhRkANf(ii$2D%(+3p8{i*%)G)^S zTSQds&xfQ_tD(}EgUwxA`TJ>F>wCTmP5E~xD@8xmn9@Xo&5Pa=bD!Syqv=Bvd(tUFOH4prRwWya!vz4?j z_t}CM<%3*_an}r}IcS3_HHfh&k9Dt_c;f01S4OcwOJ7tsg}rRar&U!^OJ;PY9`KNj zm(A|HhQchciXn0ibD_x>A%D9PHD@8ehn+JLbVxJ6b|%ZpLOo+nby25sFawW@3JF({ z!rvF5_K}5wpJUjO#`}4Bx1FG%VACy-1BFX>_%4pU^J@qSQ!>!IFw*?2tpt*?+t7T} zG*uojbb0&d#7>mE`B5CJ$R(C|J5lC`&|JZ@cwD$M_^6QE^oMcE32|m{F5Z5#nnNK{ zm&Sj~CG>E(H{?>R8Dh226W5WS-XhwQB#Xr-wGXSIkqx`9r$V^P(5w{}N*6vA%b3LT z+=}mv_qkWzWJpNBOs{a0g4&G=21tWBxOz}y$j;o_ZZhB@A{YLOJXF7Y&SsA^eW^n@ zn5qyijGBKxRJIOI3Do`T9FP_fZxqNtGx(%Eanh@JRcKB_g2 z+_`X}Tg30zmzVdHJiI*YZ|?5S?%s%iAPVZNaIWC(tQw839eFr@ZuNe5X=KiJ=k1N0 zy4g88dp6jQQNH|sk=h?yeq+~-kIlOF=U*pZcrOb#GrTwk@=p*@Cte_M+~QB|u18i&ah70Z+{;`cUq zx~giK#Fy%?PiW<#H>)h?D8$b}dyH?o%Ds6Lp+@C|W$Xclm4j6Ef)pqUm)ulPPF0Rdmk$O*_`p`cod;!G7k%W9kFD*dCbE#{!pDPMg<0 z#9oDM8Pq_Ve*fHej;#ASHaOkD5Ynk){{1bby8m=?ILmHd6y0VmgC%Doy@Z~TcU{NDPTgILu6<0ArQl+F>Jv^v2e-Cnp@!+2PxA@%aJM}wBcwu0M3 zv|8AY{k?D3ce$?dWQP_+YMLX6dK$RHwspuev_JCbuhE z*#s_%x8)6m;v}Q)e~}9|pgnrzkIM4i?~p;LOZ}l>!xr4u4*9>@}KH*1XVyHY&UareT2IZj4pq1BoYa1 zrfWep^VP5=>kT@u3)lNwxr^&!NYbq^ z#-nj_cR<)T*vSHLZ61LqcbtBY@f4|KjOV}ihwqT^<~6v#I99yxg<(QE(g!|1F}mxc zT4ahdbed%6YkFm6GHS-fY|sVmur9qI{Pf0jd$`zIWxK`^pRRUdDCwWHMo_DL3~y$< zA3P%|w;x7QvY$G`sC6GknXf}POf{%@XE8BePd6+z{#$rT5-T^1m&{~I{%l-gvqs#u zul(Jx@K~O-b&Dsv{6M4^ObKVW1tR4xdLuQ4v#MOLM2dzh&kv~SpBi6-vI{W`1kb=o zoQqGTlP%%*Vh2@8f6Y_*$5XHbw1AkTDWzx>(+O@(x85v?;iHgAF4g`w3)D9vtq@0+ zp7yz8o0>{7=+kFxBC2HnCh?_HQ!JB4pwVnrYxfrC@o8h3=|{X#0RA(C-gBTJFCb`RaN9S?I5zF({h7`bJ6;u!SDh*wk>#nrc5iN;rlEo&i0y?>O=Tp5y?NPp! z1OOJJJR{X3Ds12lgzVdg)9TT8?!~W~kom1(ssoHszI<~l`Kt3{!!=7BN=+f%(QS}Kg z#l*xhpxIL!Gb9-m^evv%%zq12{nTuL?*D3*g!2skE-I#R=?8A~{N!k6WT~*a=Zw;& z7vpCUps}|bIAJT(`|<`Ok!*Ov@>DsKpsmXqzA|9=FGokP(xppbrbh!)v1iPh!^N5) zjCJ>!%DGM&QUVt=EYbjf2Q6GcMr3;bzyJbJ%B5PiCik$!_zUB8+A%2Pkj z+~ZZXQ46nYDJ3!p{w9w`$%I>*<(D4^lXFgkxUEcCKI7JL&?^ zt3}QuMso_ug(At?y`cwie_%oc#fNHlJ%`}#rhxI!9E%J5{45E%AzkrUn^?BP_`RIf z>QTodcs!KgT-|0($VfM5YpwySf3wD<{*u#0jlIU2EoymGQ<4boDvh>-CI6+yj@OH8 z#sdm7Sx~tPQL)wSo=+5|=dSMZX*)A8dd3AHPk`?_Z1NBEeF^wws8TC@(hA@Pz?nY@XR_GpijrxCUyAPd~3PDOd=S zXn6s8_HoJbY|Iswj53yr-ExYu*gQILv&omZWvXTu_p`}?${-HQMFuHOqzGu4_a~J* zcVJq#m22HpOr%YI-_~|@`&y3g=JM+LE6`}3+(9ct(83hT^tiY5^#;b7K%*k^1tDvD z-S5Z1^(cZley^1hdMJkc&^-Asp_xMRuZIIcMEa233?r?9UR5~moS>0Bq|->d(SivD zoe|ZIL=8)sN%a(q*}CptGaonhffyMnbFGM*V`$|UztAE(9dUFhLu!l7aj|u%1XIGK zU2Kgd`{T(K5vwZ~yPcigvyR8$y?Nd*d1iV?9E3wOxwPLe`#IeRH9I?Z5!E<$H%7w6 z-!YJw(A&g++=E&o|2p6yNf~^ZwL^ALK^7}tHEhX0VNTOds!4y zCYY7MdTu)DtWbf06reF2;D7ZwJPi#A7lx~e+iqVVK~-=U)J;6BhfN!^vNMf);nA|^?u+TWM(BQ4t)#w`ywFDm+q}sVPn1SelRQH6~=R5|PHT+owV5iCYXYhE5ujx(Vc z+*+sJiUI*CHh`B*vY-M2vNApr8di$rtZW-|X0{6lDYe709K6Vypaf?J*-|sh zSg6uBbBVVxmaG*~5Xs=h}smdKCl0$;a27 zwO~mGe%G^M6_gVqcUq>**2bNv3Su%^&kDOE8h*HQf?&@r>P?cpCBue*)ynG_3^aum zgVAsnG^)+GrMK<@nQ{sU9Mx*Pdq`mYjFanx^RJ0_ZOC(A_uH2#Y$f9!7`0k(0w~rX z#Jfz<*x#D#VOBp0?2J)3ICXFK0xI>U#(*4+VGKsal~j#mt;~kcGQ2k%;868K zzCT7uY?*jLp+!-+KN=y}$U8!GspQ3IM$ZAqX#Mp>5+DR!rFb6SeVV4e5f~|WEk(Pk2IwzkxbomPUx;8k zy~4iY@?N_HdYojm740q!x;Qk1K`LU1HV_&gT=_d>clSGmdtJisW(8IW{vbTkC&7nK zIq42PuL|nGcvzrq|Ahl>r?JczSq&FgeU%6~XlXa=U<okRSzZ}n zg1Q5wz{-Z{fi)b8i>~W5R`j834{*e)&;R0Kzi1<%X{s*NKR}pGeS@4$T4A|ewG(Ta-JU5$Sj8LH{3Y>0V8-|5S zUJdz?NBYyN?c`n1)xk#aluK3VRA_yai3{!C?Xgk_DvUFB7)0W>z?QBnx%u}CTf7x$ ze=S~R2GN(hUOB)#4cI%2TS;Yw=bi@)4s6&Xh%-YR7>MxXqus);s%l^rXDtn$jxk-z z&*&Q0!xWEwThv#8hikokMK@BaWI(mrTLwp=E0+MYmY80{iwn1yrdAL;v3?~$SrLGI zexH0_)^JBR&;*cW3kCyTdrgZf5-YmI?u@Cn*ZgJ%`$}%wm1{hNt}EYa+G;(|_b1#| zcK<5VPE}vVw@O_7&g!_F@p>3T0-MqtB0S#ZJ0#&afjw9+UL&W6|IWTkP?#Al4jZ3c zo;w#52^m~t8Df{d)LiX_eRBa!MAK68*i4}NF}lWN#u62myu2qT{s8>vL?1q@Qcgwy z0Ptk{FBZOyk)4hG|L4R^X?ZyvG$a1(Ykb-H;`Yc1=1%jzr`-2Q z8HA)WyDWz2XUXG!$;IU{C@Wk|9kbM_KatDhGdZ!E-nOT3M7x8P6G`afR=vaL;*69^ zVAzSf_)FV%(@0DutWl3YBZ8_NF?uvNcXxLe)k)bBBCekcGf`ZwPA%CC(=W#zr(QQ6 zQk57VLP(XE>_vZYDxQQi&+P+(Ht94rm9)tUeAr%-xY(((K{%#H9e=4^j~U5)M8IJ3 z8tsm=Xn{&%P%?}n&?K8wa^?qL>zR~mF`-z0&Q{>8pJ|IGVwT|c_)fHQZp*a(m}ITD z8Js;Fvj&b^+=(v!fwQ;upLV3Jdu zpaz*B+8JomqBYFMCwCtw;Ma;NM3*0sp5t}$4jVeI# zHisCVK#`h1Mbd04t$GwL(+z}F8*l;b-le!8wc9co_FPyRiz47ITbRGk>wrvBVufp3 zj86EidZ^8W%2da(3}dKtJUdM)l40#18$?q;&Vc~S{hG&gk90PoZ+|U5hkqR?e4i`3 zxyn&Jfi#6n9`q{QW)e{h3QWRB(%9@ZjMfsG(h=g8!8HXH^ppKU0k3bMaf?t4WNh(6 zqX7m^stx`Y*$4%9*hJ1(;L-A_97wVR2;KEJ{s})N5LIy8ID>E~pRl1zr_PF&Pa(@SBOF$GcFba zOYyV$0S8B`xxA{5nR`fOV-`;M`l5W;D+20e${q??myCaqBq?pr4n?c~xOkB;nIeJf zXc>G)LKd^)aSyFo(FL|2ss}m5lGUg~C4H|R4>=z%0ZJC4HZLUaWDR^RfBy<=PYqu; zGi2jN*x=p5FJlHt&Y|}e;IqQEC4cD90JIysnyRM9WhqsBNXwvbyLse6PKeL!c21e= zeHM+Nd63Eg2}caAf741rhbnM5oUcIgXVzTUGy7@UUyOPKjK$-{2|xxos&)Am_yMQd>MmjjFV zJAjCD&-N&GcFzkq>2RF$kq`=z*$P1WjE0 zRt92{+$rAvx@PRN8z$?~maWgYGfg&G9~ySixAMo}WAk-(#G)Ps!<9|pnnBl^p^90M z;Hd}+|E#zT$S_0w6Cg-%uay!^1aKwjfbANOISv#Q3-XBA0^(<-Vds^#oti>Hrfs>R zxjsX~Tu}YpoQAh>hZ^A#)iIMda<*A^y&w7QNDDpF?A0eEjlWb8gz-OOOmbebc)?1R zoL7Ll`>8oo@e8J#QwD+?_bQ3@jrhy>wLD~iNqyY08*BLfH0JhP9Xv{OcVXGLuWkNx06N^fLAZ|xSj}*xf17l4t{znIfeO_;Ga3!9T zNcQC;8aRQ|8jdV&d{47#(G7$EPWOR0DFCX1@w#iiG2@nM`{Ic&7IRzkFDzJwWiVQ6 zO9l0P723yDD&DLeP)gG;kt65U@gs~OhM;X zAkQw&0>)U)Sdz|oPkK@Euo!#X_7-;Ed=vBpF|Pf4vd|o1+LkFn7#*3#*bSUCVZk%o zu6?z7$Q{pjBN!Xpv>Y~`EB>%s2F~+EhXzOV_)Io_x8297e&=U4?N4*zqk94vf!iOj z4;ODU=D=dJF!U8(UmnH5m99oCtt&@=jeJFxL}y2VWE`9}Di{#ytZj%B`2*fU{6a)) zI?$2EJp{FmoB=i<%5?2mFhR2LxxSyJ&V@N1X^g{lXg!x{8+0sRJ!uuN;;Dv4`x$PN zE=>msmBb7keEHi&TV#3w`0revS=uZkuOE%C9^U+(W94lx6lhbJhr4Bnw!ehi1?3@a zH-oMrJCS=(rCjT`6FShlcFeF*eI?UR4trSxi+*xq5U*hW+1KO;30 z8*g#R%?9DPA_%#V1+3EpLkNK;X&*MW(XOSV3l3UhVU+-?1=&hGlf?r+vcY|#hc z(ssLepMUPn*6UcCWw7#M2>z15T1a120B>?Y`6S6Z099A!r|5TgNVvd$WKlb6zOF-Q zcR3MwCU1Qo_47h2S;LoI0IQlT|C}mb!}PoBTs_KzHULz*y+_U>@zq8p>!~M>oJyev z1pPx!HYlr54e;+pDF>TJGv7);tiKK=E~oLh<^gwyfk_0Mb*4SWpdppm3J(Q|KeuqanlPiMa>5R1x)u6oH0$w?-bs!a%Oq z4-yV=F{!oR`oLt5B6q}SuM!$hSOV)#1!ojjn_~`{DLIp3s`2bkP0=L$VdlkEQR+a9 zN2v!M4S!M8k?~S>T4;l)>EXGYDt=`2EyM7v4KuU3i$U}M-hf3`(ZVWN!$z#=)^bm; zg*tiX+m_71{ZM{Mv^3Hl@$k@T?Vjc^Uq+k~9|o&CqdOphed4}!r?C82CM+;LoE6tX z^q)LhQJgAcnq$E1j#j#cI?aTUB{&{_h)~!a?x7FlK_#bwR-EprD6%oj} zbxaCr1hZOdDgHgr=#=@+Ea*K>$AN~@m@(!jvJ zb{@@l z>`H8CmbXe#zVMVVU(#0tR)maAS?KY;8+s^$!_2vTD&fn1hYhp6anwhb(Y>JtR-l`5 z+Y7#Ea2J#K%S@dT8~j~t`EPb&49-oE>v(MgwQw8P>*_ck-%T$C15Z=|n&j%uotPz~ z!pZBzrXSnetrLSs;pke({y|PmC0T4&7&`st#FP!^=0+0_xURs16g+7~$!6O)?J{W_f#!;c4dFBjl1zsAdoUNj{k$Ma{y!V+H z7JF?BgZCCDkWH1}JMg)De4l$~cRxKqqTt%kxGU%MOa#f-kWKHqiG&|w(fzO#Q~7O% z_~*fi#3>&hM*fZ@7+%`J37~j)nQ8F33vDiKv5o;<-M-_q0hCI1~8!NNL;ho81m($y1 zm!=k1bChsi?SpEHL4Q)mGi5+plq>`ZX@1u_gpqXJz65S!Q%?3bB6>!1pvVf`;DV3T zD+HCbEduguY5k~7j8M6+47pXVXtNpxrD|4n6;gZLy5n9Y|N7@lly~N6u6=xoBe+M- zq&#B3iQ1l_0yC{}j)u31q!lwdFpv-ZGobeuWjZ)IJ!gZ7_1&U)D*zHV{)-42-gYZ6 z57U1pJ&TZ|a`1Rbm!z{`2*%xoXe7FbA^7WsA$b>85iOU$CsR=E{*wj>-{uY>{yyvq zn0&bTP=-AH_4tvendKBo(SWn3rC3|>(1ekmOpAP!xOU}%sJ)#0B044|UeI}69uCjf zS8HJl6zvxk+7HY*|ALN`w-TZux)ud#_f#y5RwAy8TJxPf*>K|G;_5-F>Bcg{>8&+h z);G-AcN){I8j;F4fT}HSDOW*`HaYm-Zoi_OD#^qcrgLVhNw3;YM%6cu(4?vF#t@@9NJ-|m-Y(3!p> z)f8)`^}T*{$&g*fwM2p2Rk+-U@kv08O>FcIN7yYjFW-*dQf2z>qyR*?=zV-Rd`hQeRsTIJ#chu{qmV$5DHG(##yaa8pbnSTz~ z2y!DXm?*mwVgRcKh#ec+E1B;RmEmXiJE)$0F-grMWYvxX5JrP^ZbLazzvYis zZWuK4+3zIwX6q+nrVG2vzmEeUpntBU^%6bTD}2oIzp-!p&ULHQf|Ap- zSJ>k6%8@F*0!wPuSer_M0_K)Zw<9-)rIVpvOia*zmTw(|J5VQrDj8%+b&5S3PUro1 z@(3B$`xiqsu^}NCt)bWv2Pxe17sJ-4E+KBE8-R_&yxrYxJjEn2pbu3z3k#E{;Wu3| zNf6+cm#pzMTWhiU-du5ec4u93y}JAiXxInnDr_B1P^t`L{C514!ql^6|Ks^hSH+g( zkE*bCh*st{=4;nbAx@s@)Ka+jww3< z?XXg=qGzShCoZ@a9sR|q-Ce#kTvd`2{BSipz3wayBL3+78sShiY=X%xBvtFv<=>Ww zUv_4Bf$?%~)uY1<4Gac%2OC#l0c9y++xgDJBz$T>?p!4(St3#%_hAh#e`N&&ID~)- zHvOo%uR-u$W4#B_O{h-iZP2gOaQ~)$+TiAkp4+rqV_^zi$rbo}0xIZ)#j^c{#0BrH zng16h!ysk$N^i<#;h0wLeM;p>CK-`q#{wRuH5K*l0Z0m`RYi!QHj=8Syev@o(zMAyZqWVr07s?3wQAfeAC6&ljSJDzuq6o@UaQbk+Gxi zadX!K+YMuQorqzA8ZeL@6!)@N)KYbjp427QNi74<&B}xS&XKz)`&M|n2u!(q%J-jp zjP7#DzE@-bfHiRdfZxym)mQ)SF>Fo$AJCKA%IUBhvzFsB?PZnJEWN@r)w_}Ng6Ng0n<-8z zH0spLab^<28IQs;qGZ9KF`JyDiiOmwd2XuK4NA$}VU4IXgFas6Mtj65ba7(Lill)u|1tQX5`F0yMTwf z_JtCFwppJ?Lg}=Z#|N?QdfXQKj;>3{mj;dwsM_zBeHZ8Vk(DyO+@24E_K{r?eH0@? zef01mo-GjyNJ7ouXmlxDw+syP3u8`4ws?x-AQ9B~sMPx|AwA-TAE7w!R^f;Nk-Gf0W*t`loZd4+6-_2G6-xV<;TH6&&s zON5#))jgzk3RKexx9TUM;VmS5Tc+bgqV_^x5K0FxPj zPL1H}&$7z?djpB+)S)W*)@e~#BG9QFp&|f44z!@WCQFIHC7{0j(Nylzk*zbvil!G( z=DKx1?jP^>UmX*9vhWJI@JER!Zvq<{xYs4#v9pDygn8+J!gnx6{c7)Ppgeb^m%Cj2 zO}mi?p#mg&#z@9Qg1G)DPyDjaC}VeC<}+trp*Fg`Q06I2H$A&lyJ#yOEDwTq6RSZ% zsa^Esq(|uB0z4c$6v`)q5jtCrY!C zYD1wQP`KnCKof~$RRI0ykR!T)XD7z%(r~2Zw9q&KabyOxxbA0_OAp@q-f)2yF=_d+ zb+mM!GR7f0hRHJiL;8>MP6%~edz&5K_aga=T{lN4L_6l-7PI;u({;N zwRp&~gZD86@MCmrSDuho7_*q=nF;L*$*3BrBHf2?-15uxjK{O30Nij{W&Cgi11{P$ z1Fx$4Wp=)4+|v~WXWSNJKp?jeDxl*+?K)WrE&5fF?n7VK+DW|`pQh`Ge-$QoR}fkQ zNc!-N#b3rKeWQ^agB8czrlUlfg1dKcUAziii(V4PrwXGf(~wWhJMF;wh%6Cb2`|6E zimx=WeJ_1{7OtS9Yu&D`?YHZ>$Q=}~*Eyyi%9oTQglIiX&?r1WIZc>0>Ijqg-$aFz zkz87l%-h)2)7E%a}jxUZe}C<`$209oAdYphCtj8 z=ra-O*i^L!!duCSW*1=n2}T-L&bs1=g-)ud@w3c0M#RwtA#ZPQ5CX24fL_-yMYCTE-2%s+1&pY(HcQ*nGf0M51qqdq}|CrI+_pQvm$#!OT-OBiWa} zX?RTYW&n}rCHnZ0d$fJD{Aq8D&P<>Ogml3&q5|#Vk#8Iu{c}0ey+pp!HK5L7BE{)- zmUKECd7H zp?nczXawz{edbnJycGLSdoEq(W;vqt@6Y8dK*RVMYh4D>0bb-4vHq6#Hptm#`TFJ< zs&Px~STmw~Op-H9#3y>hEP16p!5?O`dou*JuUKhoCrNOIH?(8qpVogE4I8(JHnwG0 z4lts%v`;!`wujwtN~zlJDdVg9?IDslI6whqs|T5Z9iZWBnL~BU5^B$bAqlKDMV0pcFMEXf=~54y0{KdXrsD;{+mY26$M4 zKE!fUOonzN~X3X2ukk14&l`h5v^U*!Hi zrStnFXj0|&ic+7MYgJ7~s|+qP}nwte?`JmewHyho>BaD#j3rIzJ)XcL;IfXfY z1t5#u4H`Sx0$7`9uJ3^$gZ@D*P3UUn&#f#jLpRT6gpyTrX&7pU03nF9uk(x_G1&n4 z%#Hy(0LiU{X~LT8&qJf9*w{zN1aA5#-}RStB7IZL)1VGZrrLt!*E`Pl2VK(^;gexW z`!j5N)^cVB%W>}$_V_(5|(t&DtlwfTSuZVmKcE>XtV=aNVxoB;~o}vmFb`DyAoJWdbTw0DzUVD>t9x88^`8tO_{Y$cqTAkS}l#g{x0 zKFgTr?D#Ms(UEIL3Oq4yhgX(yZ)5DUpKli%0))`xUjnC>#Bp-UM%o_%diRLsKX)s= zx-I2<+TrK50Zeew^LEW3-4W1#c@@=3M8dm-96Q8Di{9M@L)B%k#h`Yf8=6$7SbnR3q@BaDAjF-T+Bq2twXYP|)iw$}sp8 z4g%xAw>WHT3_uZofbHppAolv^2(G(BzGramFAC*^4J`vdMT{q+g)~%`HD%%9(f#FopmQu;+IIZwDdE&IpHJu$k+OF7?{9m* zO#u!NH2R|)k_Ur=w}bMH5mROh#8KhOd^=j)Tyf6VLkode)CkCW z|K8&Ph$-Z12bvv<@JlP;f%rQ(!>Xs8R|ZgV8Ck$rZs{f5`Hp)VIRk<;y;8ayYT{d~ z*%lAr5Qc66q!bJDzh{AbsfftQI|i4(6@IbT*_)4^28J0#!HfmcYPK&*21w*VzcJ7+ zj6u=^0%2SYD51rK^Q-Di{c(%*OfHKK?xR{Ipd2U&;CAUduV!iftad?O8@6S8oBxxS zzX$+mVUx=09dO<18H(Tr?->-EEigJmaP0qaD4XR#KEv*;^sPXb{h#NENP!@O=My0f z0r8R_)qWeWkOwUU-G-PHP_&JseFpQbB>;(V1&+aQqP7v+k^ZfGicF#;2ASL9s9}hG z{nvA$_LGJ8R0_!U6#kOiit*fhTB`D_noW}aJBL-PsYLLxrDhJ~XN-+or8&8gro4vL zO7cquf7v&p{nP$W!z+<5@ziOQLmrt+&`{U2JhO|}7iMUF{T5w`*>k$uC z>k)<)B5)+(D|Wbp8h=m*S$e@A@@mkP41bHz2W_dY(k$v#v89vTs}CFjkA5qzn@J;9 zUre~-_i@V+U_BC$W@c2YH*)wb z+V~l(Jw!hT(MC7E4*~>%A_8_=8mazJy=JeAVdDLksiJ_9Vpe~u!RjR-1>BYb+FCcz)12<>G}c& zd2ks=b=BQNvC71Su0o=e12PD?CG0b=2@RBNQCb%W8+syrzFr%=&la{R(l(xogve$s zP3zHv3dnh(jW!A1-9BwIK(b}bsZ4Z16|Dxn_Z!U{^jLt2_bY?<{in|6)+vM)(mOh=v6S@u&F!jD*42~ z3_9BFds$9k4Dydt1KUq&?rT9dN`+mHRxyA5msYjDVS~u}b_+Y7zPhVp5kf%SJSB>; zA?af{Za(+Qm)qOU>4%=3{fpAw+s5hld($9N9k{iO`;`wV>=Tz-OaX{pr*|lZcWwgv zS4A?tgzcR@nDi~Q)JKp_rg82oc;38+*XK#H$i+6s&$q_{cbM%@{rD$W1iXKLp%W6k&7@_Ub)VBWR6Lx$c@;A( zr{w70G_tmA@JQg=+5vX27FTrS*l})Q2SJYy4+w3%iW*xg6$q~dN%X^an`Cw`4<*8GnaJF%7G-I>MQJvGPqER??%{^>?UJ2s!97v~9sz3XC zZ77zZfamh}C=sDvat|XXwPqPqL}WfxN=tr*FU*Aeoj+8SQ{ZLF=ePMo$9Cj(FBQ<-*xrZb zXZ7pD!C;2CXdN5Y7d4U9$t=dL>>fIn*04r59JNoRbeeo-LueZ65z9vU%Fz-JM&mhg zS(te~elPas=*`5#J3vSNGjg7M;EelHqgkuMS)=z$^q0N#B358 zt2fzDZvPrWLbP=mlF926W_su?GMZYauK|I6d=f~v!tH!-oHGh-LFK4)smM2vG}&)S z+g%w4EAu_m9afdEbRxhCwd4gpx6Us34Ly8;l#91Qu<fB(}F5PN`}W1=IxZkY|A zkKz0)31|Q#wUFwSxxDY=pTA6HOZvjHRM8}j%iDkW)019Yct5TWXFB83(g>?VgwdXI z<#h`}<(cwwaqMiwOTUUih&O$b8QQP|7ap(|x1SWeA{rDR;RSlbfP65WU@|%{IZg9& zO-ng__nQd_blnX=-`=)~%)&-9A5iOGrBlPwc1ivA(IQ8DlGF zO5vHt#U{$=(mwzy$cCG>4cwt@V1EO`=4+@EE*`4*Zb9CYAme&t* zrTI@<2U6pe3>qi9VOw9XdQl>*1p_K@AOdut9soNiNLEPnyM#EfW1{I*|;yQ**Y zEScHXU3M!4DDf)Na#9QVhf7m1!PKvuDLU{3V}ozcz*oV6TTs*X>_$rKthg7BzmeIo z7IvYm-8woBQR)L3DZwhRv%tE@ITcz%)D%04xt_t<#>5Jr-0Ob_p3>DUk)9C&0Lq#E zPcD{?v5D)y1fYMd!eT8Or%m?1KR0>-DvHn-q6G(2%S$OO%xZX2<7X@NJ}It@PLWYU z3GqWLA`cJ?4F!uoFW0vIB;pgUC8{cvQXq5N=FWWIK&HtfS|{w4+>=WC>@;g+4jBw= zkq1-Lf$V?H%sw<|yrfSiNn&^iP41UuRwFVc6~1PMST#Tm-nDEWXdou_J{=9>BbcKO z>%0kqT#izh8hwz2txhCa`M9+5lOi&02J|(;-J$uG{dKrCPXx|h*I2`iPeSwYwxKY^ zMg*;pc)%=hY($d24@v?$VL+{~k!3TvJ&5{kUf1{z2psj@=uyPY(1m@wgkZyI3YdXSSP}wX)@syEW#L ztEtT#t&T^>tObyBwbu_P?(vKyx|1umBN~Xy#hRJft+`}H5N_HC4{7g~DoL(#R3JYk z1`i|$w&zDXB$;5>n`lJ)rK8&!V6=iL7o~zpfGLVxU6+nuop`#saoh=%0oGrtB_8ih zp;H%~Bt_FOb~vkV#A827bJ=0=^SDhavvby*N z61dvp{Vm~n77){7I~-AnB6t3aKC?*-pHc{#ip||_2zVH`5arWSK(nUsLynk+$R$3 zK(z4TkQ@p^PNldy87S62W};yFpd8}|kp>r|eiZBUDVn<`XnNlLAT4Ni%tAci3|)Yj zReI=bvxZt%WC8U@Ka#<(uMG?_c2|H@Hj6W&3E5)?6=9?t3HEi-zr&zBo@N`~YGa-g z*cMtd<_B{a;Z2_YLA6hiZnT@k0mI$PyJd^KCW*PCw4dw`ss3w^C?6^kGsID)y`>lS zJ`cM?4ylK!1z<;v3PK@q_u306R_1bZfKrco#|7t z)-H$b{*->`UEvJM7V9fW2+I>Qw6!4wIVW5fj9j9t*Dn9IA>$QF$)-LU+Anu^&X(?! z-^vRtAq-=TqbX?&QXUC#Sky;>@xYD^ke!i(_s^i;18t#_ZEO=JKuqG3K#K_JD$kt- zxV=?A<<_gDflYcap!IoeSEajwddq(9Fl9Ob`~*PS_#`nzguVjym>EHkJ}BFXr*4)Z z4D4&ktH1b)qEYjAqNEi9an>>`HY=_K*D80Id%HQF1iYweAl{Z$Dzco$1rhYxdAYVY zwi3s5in~2ZVfOt|>i9FA{uZ?F%&lIUyO-PJZsKISlh3_H;9@GP`XL`buI!O5XqB>U zcd7+WAvKK+u!%h_fE*e`dl{+h%Pd>tJCEjHU@2T}tK`$F2v}IPGRPOcL^(gVnh}DH zqroRN6vLG6FP!4I+sq#5&8d;zpmi_N#eVr+xx&!6x8fydy^3;QG_h zcp5-)xX>qIA8@^JC;!pnJOm@`Xg+8($N&kiGJo07jBL=gc(@&-`A zKxd2+B0%p&fE;#fvFsypL^8m7dlLM(@`e5!?e+#U6?wIP2dZV>Ng|99mb&h?I`l^Y z`P~I{2DIl=&~{A^0j#-HeL+EjnlKp0mYuhOdneY8Q4-UpKsO~x!;=L#FGtJ1C5=A( zrS2*c_F=C`Fv@57Y4)cF8D}DU$Ic&4J_er-C%dLNA~VOj`V)IkCW@M=#{L>SUGHxv ztWIGA9p>kZ<0OwGKN0`q7UoPy4{9m4V2Q2#qb3>Qh%n9;G&e5JJg?+CcIV@D-_`Ze zDa4duDXA-|-hccUa(y*7G~_^v9D@zf6==gL%yl{(50yheNwFG0n>xIm>o71GZI`69 zg|1Q4vJwW%JSWLp5fZ>pY{}uR>S|Q#XeXD$o=JHy&=+4c)w7{#Zk_{3(;%A7v~Y^q zCWzP@u*`XL_seGk(BIkc8{p;h0v4ShvBDYM`OCSF>h@s7y&wR756`-Ne&8N7Mu^cD zx!pHJ4~-&12s*kWoq|Izx&Z&E_A5c}5nezp(W!PJ5eUu!BBOBVYpH6yYicV{7}EF> zNFc5W#5*g-Gih1EiFDD1N3FDPlYdV1#-sPm_Y#MZ-8T?;E?oX)zd_=G0)j3^TC<^W z%P&>-j@DGS0aB?3QDNAmx{hJ=HDXkk;5hMz@7w=Je=_kX<=Ea1cP~Ts)(w9MiFQ`Klb13YwS2r!$6Su**Xu8Z~+^C|&<~!KSH3Rp}8*0Wm)r zf`3vv&r?MVn2WhEIUKQVe%C2CXP+eCqdy7=G_XV9PU?@6JhF$qVx94h2*- zU1GaPF6Mla1b8fxQsTE^CO1rnasFg4k85=Ii8(Kq5#)Knmzt(djC#zM{b9Q)RE$z& zH^drFVU)VlySIeFx%jG+h=?c|{^Xwn6V6|_d7>ykeK$C_$>dnXW*zOCcV--Kp)IPU zD3Q|etb^hfEl-~v&`<9;$J6Suy#O4k!a8ydbcLrxutm&nKC51DPUnZ1Zji4+YO_j= zE9nTm3W~^bL%+R<0Yag%I;V3|>ia>?GsV+0MTT(JO61=yq9mTo&TZNj0&q+ zcAacF5ng?T0!8M%Ah@lloT)#~n3~HQvQZ-WeJCbGT!4>ah)?fFj8f%Pb**4v0QT+^ z^B94f>yrtS7hrkkF|wAWJ%KL0yO*L zO_i0f^Z|GoQYxb0zs~hXXC&XwfSa1+oOe*a;R5JoKp+zN~W~h z>wP?*SkUu&$n9!cE6$`&1n>Eg{9+3fqu7p5$=qIy%)K9+Wf3WLt(SNZq9;XH9we73lroN7Sy$hmG+`fs@^I0@3fyj8~@Sg=SxE3^wktvX);xXkJsTzHxK zpCr6=eCYDb^b06=N`gs6iuE?K=6{NH2Kq$rB&#OY${OIN!Z>vXU2Z^Vb6N#l!e9{> zv$%xO7i~yN^bXU;um`aZK;bxadz&tFeU+;Y_49W3-y~GFhK~CXsDN5&2~aR<2ClUT zdSy_p`P@oZ3oN3njQ6(rdTLI4(bJkP<+2+@NeX((<%b7H{~PQ}G`|J1r{)S>bqxS> zf}Lcy`6UZl+I8z4o^hmce&1MjWixAkndZThn!CjsGD@vNkZEIJ_l`^M#A*u+%aACw zV2ZoS&ERD>vyg>LQ!zB+oZv>OdeVf9oz~%zYmuR)Y~lj?#YX76)6i)0t_y#Lmuh_XP{x8CLb=pIH2kvXxX%88qkfZH8Mb z+W;_(5iP9#aL7LHPn(w<&ZD(IlKfs!O>;(kl_zoSF_HLW!XnV2o)QaG;MiPq9Xd&e zuc56y3uXgaU-RW^&>88)mc@N@Oz($qTd1ri_wcks9G-`Oi7(Dk&8a(-i?2V_bx7WR zkvmoEA5U<~QTvy67+G6fFV@bDKQFZ!kazDDqo3lo5i|+|8v7w1A#^8FocRwcgvJoemsqHbHCo7pP z9v+Vtu3YUP0J2=EgLJv2tB0AhjdT}a_n)tNO)Fg6ErwJPVDM>H_lAWrJU!h$p9z^M zD@nH;>q)y$l9!>L+A3k$fGBjp?dQ(0^?O;IXS}!%RZo60fI^|rFFZW0UUf6t4 zAISn$g>Gci<9GDW{1pcwk`svE?R}RdY}-cNwl+q3(Qh>df14EDz}^C%L4zb=NP#_H zuV(#BU7z=)mRe5Ls-{WwOuPKG3R4`qLrSyJ!Wx!;r);!wbL5m?1h4qkAV}w$)jX4aZnDQpWc6 z>);yZbT%qc{=yOBH?Y?qI`gOtX`|MSqx3#g2H=4xo(RIt{3?PQc`B`{`q6w#UDu2X zx^+J3oIIr+mRSw+S?ZVEU?;QLxwSGgBxhH#)9uSO_~PG^ijT*RgtEh~0ES;;z-y66 z0r*%TX#})JXy8{IiVQy8Vz$cGTSmcWf~4y$2{aF?UEf|(K7JbI6-rhjxk&a=R(6|q zR!de)cS?&ybb%FQexvq>9=hzynyftOLoASfB3$ZFfRUcG6ml=bxbMG4Wpx$fX>JF% z)xrjUdLr%JJ=zd18!G~CZ%>zQzLzcX-nUwo#RzvS_x-wgGvUkKp7Fp6@t6YaAMVzS z%q%~Zc1CsX;&|d$yQ3;J3 zf|h)0fQy(@lA$~V(wQE;Tn{ALVJa`JSb2N#T45vkHXlQVUjSprCHb^Q76X?1U6%hHeBJH+?U^UC>#dH|p?UTr=7%gSKzMQeDWfTo zMv9*{u!z_A*w7h|RqSuE4?Ro=Q@fXC_5|o&15&9v zaXDhy_^{CgVZEO=_Tx+X9Sv@o>=OTX zpv>69=|B4IVeU=GP4<-AA1K!bm7)bCWHVRK7VY93iOriPvjqt%S69!;%L92562cO3 zRsqcvo%g)&nC}K2bbkQ4hHjqj=JKRJ34Q(Ty8v(PZa@G2<<_~# zYk%p3@co`<9yE>b8mOYEYD^OFacC+H4@Kr1$}=T}6Uf=_YF-Yw=`67d;Nak<21OQp ztN!8slmyo+RMcoEsJ6L?trV&6sqXYyyqpvucC)l4G@FZ?!bub%<*yP$m_)B+`?u5z zV$4jEk<(-|i{-CY#QXb_D~rIl^?q9ErNgQs1R;i)Dw!Qfh8L6yY$ncy{(F>!IyT0% z1vUygQBY`>51s>WVW9iV48)sNEOJdQ}-N{wH>!~h?C>hP#K&UGxpxRr*lOgWK>feB%<{U4(H2Q?S zkESj!`_HSz-SeFk#@Q1kH?6fvtvrYejCK4M<#)C^pU~a(`G1xk)lLSh-|fkzekW#- zT3Oh!06-pZp1X)=;rHFz+PtoB74Tr!qP4fLaosmD-8=mVh(ZVNUe%C**yHX*mBV#N z9!>Ur_+A6~q`L?Gvg`PpQX%LLF2ufIhm;xq0m8EZhx|!`qsi97-LwmR((0@lEm0R0 z3eDorYvX`z6R#qFV!N(2kIFKSl%qXmyBU!Qxc|*=1lV74|_e$jnymo^(bE|;0 z+2@Zy(%Ax1rn>cL_*813lax z73p;D%tTbSlN6H1JdhbD9$mjWg1#Lx#iI*QuIQqt{ZPvrye4MEeK&Ac`SR@P^B~;hp zhV9w$#qI~h=;fizWYOt1rj(yOkRm!j-o7qbc{NW&BKnJ<`)}k^_%*^YprCm7@Ql~z z57S*aQW_2wIF*1D{pY?zl;}0u@SjIS0v{9=Fb)$KoICnmsLggMaZD0~t6jfm-7UZG z*)4dFb$#TTVH+xeDDjgJD2DgKw`de5H!@_D8PRH@(P`n0X@JykxfSC62cwyAiJb`= zqwG-cplNtqDudhtY(Ty`0Ne)+RDH{gh;VH)kZ~0Nig;Fkj(oWzHnAO`@M}s45Lq|z zNl5940UPc7O;LLq%LK}KY~qTFGJB8;G%Ab0a^QLPvFXW%dF)*Ggy8AhoRU*At|!dScHA1leZI8X;&cmH39fL%g5`z zh1n$-1*I$h@cc$H@M@`*w=u&0-au}xMZR`#7ZVdeN+YG?9niN);Kon|#XX|8l|Jup z#j&nqqCR*)Xg@}WBd7ro6CSf0eb-wP5x}phBbGDbqsjYN4TEqHife0i3>I{#gu+-M z5>&vtsL*uat`P@>B&(;;b2eWycK>_8kxn)~;ZZYQD!#qisPe*qQkK5_CeXIKT>Hrb zP>f%yrua@M?oc!)B-9115yqei)~AlNWc{Brc^yQ;l{L*yS2vgXjC z!dlMRzy1GgzY@BvgEN8Q9$Z^$uY!ZK~u#{9I{wt zQ#iFUDElY^UsO7VCORv6NrGpXA;2D71IPUc*T^~4wc3IwP!$}gC|J{p_^!a;N@E5X z-&u!^*hZi-);>AKnjnmlcq=86DUdl5K%_8$aH_lu^=5fyX+xM8{<}sLA0yByFV+?~ zSsMw|t3$$QI(^hTr#n<)Qren4ii&tPgn>q9Xm|dNEXcZjQiMiJ|DW6g>^yhl1QY?v zIp>0kkuOK+{n*q*)OURoVL%iE9)Ta&f3cq6LyT!5Mf3j*5q%i+Yv@u+QuspW?x>HGpw^V2cxMMJQ^_C64J0EV7->vIPqO zwL|C`Kvf9oqzX(&6!wfq85_pXs3>V1_@e?clQIk~0o$pSKx9>isVkP|J+}DAVQBL} zRN@kwDL0!AoE8|3^BhQ5zylryu*s{&R5u&sBQ`$4dBKC!Cs2c>tf_}F*Nx1H7aGxL zf975IgwRiFu1C0>7t2Uk8CuW55z5~aHmpvKnm zeOBbr3^$(8HysOecOZqU0VExK+2hb9-cG^}bN2&cRnj0uY)+)&IL+r1MN(dJ=9qPy z@jcK9TMTJmnWbwmD*m|G4@5{`NNt9u6B*-`VQa}U{NT+IyX==m!$cE}L0yQSG{hDF zG#8{M&i}n*H1<9oSyelT0GKOHnxjvBt1G4u+@ekm2K`W$5QTT>t#1VvLk!T}c z_?u@1pM_MXd0DW+h~gpW%(45&gEX=oG_0Fhjp{Qk5LeR@1A7?g2`E)oil@E^DQO1y zS$2|T=!P6K{M;7|SzMFOhi9X=VO`KyD2Dc8LYUm_6n(xF9-sEB5Y7plP$G`+_wIf1 z-oi|@^3|*4>+bz(Tf$6~`uH9*SN8Yk{OSNj%Rpa}M(Zjotd|vZiJ=vlip*{vvK=QK zrq8FDO5 zpf}SdV2hSTjL-MuZguexTFhO|D+bV{eANdfhkDB)d}Wjev55HV-{N4D;DWJtIfz-B zb!kt2+rfnNkyHI6w~hRiG+uBI4jFy1u!_RcK!YlBObaUm#NCciNa9 z!WneLhv`)p7BId}rusCO-CW*y#C&_n2XJvG^mYFWB@D&@3(GGUCMO72{|yC+YfOK? z+-P1)Ly3I=pX|f`Fc3i!X zheB(w>+&sHLP57d%VwX@GI;YMkEUcRz$tWZ<}M$m?}FgzM^|~3fn<8=+27eX0P>6_ zQaiO`ZD>)_GBLdYNy=lB+K$SBsnC6dl!|Z`xc*3>p)~$bXqsmf$l1}u9hFKN0eDhJ z2koJ%X2`k6{|gFXr6^2#NIFBPJszAnGFMKJY)Ih_kb>!`0od{cS9kp`=sm$UXN()Q zmGx^a3+z|mT{Z^vidKnCGjWT46Zi7S{=m%AHwE3+#fCr37>MO|W-u3zZQZnqnaxc= zfx14Dy5bH-CjPHsz`+X<{l6S}kCseMDFOg*QB3MI+4cA$rFQKHtPV~GDuB*HEFw_? zdtn@r7;Io3yOYkhg*-hCYXAN`FRR}QVz{ThU+OzF1u!YkaC|>bAEyQ2Snqt6lb!rz zGsPq>Ths&x9B6bN4fwG>s}OF*KH1MT>})E-g1_RO{ha37h8Nz-r9r4`x-1Tr1Wqrp1>D za~AimBwLpVSRWl$u{N*ZLBZIY{=#(<>(PS+HM|w4#;}Y>e8@k zq}lz;Rnx6G#`Ny$9IX;$pwVanbx3W`Km}z{dBaVm8kvj@%gOIge=w-KFq;^?qFu@4 zLf0oL2Dd4_-W%QIQ^o#BD5b&}^*G7T^P8pVPz)6(V2;smfMV)=o*yBkj1&Ppm566b zmocQn(aho6ZvQA*$CZjSam~qf&hN?xX%D`DL(0fCz}1bbr!>xPww^7b-;gDq%H3h8 zSrS<!6%k=Tk9hECQ2T4I0*o#8imu z)|iO~(-rm!(Z#`a&L~$O{sZ2?lz6W0&LYv_@@&&R!x9CU0d@=n0FehPm>wRIW%qFc zFoX%LXTK82(l-w^KTiJ`yn2#SKuEU{qdDFSP$tjRIBXKjw3pC#IuNrAnM+VJMiJFL z?EIn)f2{v<4mt0gz8ZXfS`+i4(Bj<@3u(=#$!HcfmQQ4<@R#D4<|Q_NH}Vw6zMg>_ zx8mU2VC0u1HpDd12u^gX@L>#wkNNu)f%Y}Mkn^o%6aT=L!W~8cTa)BOQx!I0SHNKs zH@-G5r?a`7pD$k&ep~V`NK^>l??LuKBnVW_^_aPd{gLKebzM%di4L@3smL5f!=95Y zCh%F1Ns_&N(z3Jvx@NrbVk-bUv@ZgGEy9qqnB*vU+qmvIzzp1RvK{Q8ZW{`5&@f!s z9^9Pn5F@&2+sM@I2JW%({A$9w^!VCUnY>KaqH%g$w*B~9!+uZ#x6yfcHr?sAME4lC zEy%TB5?*^(X9XL0n60#tAmFyMw{pVb(ECsL5DB_)&!oI3~R{A4W+Pa1W2c^rb z`uM(Rh^=!o6G6P?>iv@s8fR3iTkKNRuBQNCqQrF*2E1gxB@>ty-?X3`O;)`@iRs)49S;4HZH zW18Rt>(aT2p_p*|q-=~)mG>=qHX|5f$1kNL-YZvGy6Yv&=BK;wr?bB2K?2QQ>ym&w zmf1a?l1rmZY~G4)erKzr$BmsbTa_Aw$U~)DEQXy!MlsO5!|u?ri96=OPwnE~Ds=c$ zuFk+zWq)e5}in4Wy80EO9zm`=gpnU)j6WeP+N2H zG~N@=)gKKVpE_e5UO*a^IaPhVtQ;Hd8XZ!1*}OpiV1ZjRpSGE$w(rW(@i}6ADWp!W z*JcWpxpw6x35vRV`Gs*w$w!;sY}bQpH6NTg-aIe4rWg)s`M&n%QuWVF7+hs@KR;G2 z0w51g^0XfW(kR%z+Z)w~Si??>iPlr79i^(H0z&XA_>9GVfrJlWFuWU~6{PWOte_D* zn%Hyuwup*eHmD&QZoAm?6XZGuZVN|^MGlu^)OWjK>qak%+tSw5pYike;qi5H$ZzJAy5<7D1GIaQhTww#?DlMGLV*(6cASc}O58z>$FeTu~! zNDAw|G3?Q<44EZeA$Gwipd38c>dC7Ty*u1shlyKUtf?B#%~kO*p+o*opNgD&cAjyF zqXZ6byo^$HTzBKY2|RLzDe#k*O zJ0914D?KQAZli|1Db{U=X{S6gx9VQ2Ax5oPwB8>^{(H?eHqW54h8Frse(*y*=QtQ# z%VC-?!!2QkVU--VUl|zSA$z^}oN1)^zJ#rLbWH0`d0JztH`7ofJss7}3d5HceLD`- zaenS;M#zP0d{<}`oJ}|LH@j}M%rTL(H`_27NZy&yN6n`|MG7T1ItD&AikEEIyP!kR z_9Hzb1l)R~$>MQ-y!)`;Tk-R1qi5(w?jFT4LsJKC?k|yJb1^Y}mj0OGrEFL18$iwE zU03#BC@=jAmF3-RxNn?|_vA11S*CRO;78fWjf}ZuYe9uQHb%Fd=}*iRQDfQ_(0J_U zoU|p9Wn`5$A)zyBie8dRMYkFm*Lmf;&m9X*jh<|2UJ{KQoy||bxLz+ijb881n08CY z&Nhg%hfb#nnIAho@O!Iu$UTTwi5QbB!Skq+55BROn@ZNVQ9FO+s^;(EnVQfEwT{K! zY-qnJv^LYEUn*K@EVNeY95Q9QQcuL`L;2!U;^f}&OtDt4af@CSNO0rgBVFbUyilb` zJ^f_-VYc0iy*jCEMTbh;&6gBiAalXN-9N+St}A9zMC0N{Zr>V_hp0DD%F|9kgO72lhs(tN zCdAYBEovJg*lO%{GMuZkN&~_?m#bz=js0xL)&TE#1#6{>6|&7VKgpc3Z9Z$>FLhdQ z<#fk9$zB`RpV*WqfQS)^~MD&&SiuzS`yO+jY70f(G`^S^0!1(hQERC89s}u87$l$ZgBdJ7YEi_71KNaF;;) zfYqw;`*2b^YB=D*1rJ?YXHb7h?8+F@NC+x5v4QfF$OIIrFFkhp*L)<~BVY9Unh?u6@>B>n+CG_j3N^R1e>Wl@`bOsAm!PQ>b zy3*RyGOnCtpNIc!5dufZ|czyQ6vuP@-;7a;HJ~N}hm<=JeHOA+g5LFyS8$@Ry5*>gsE49OP^IOO(Rh3v}nc0LRSs9|q0Y`$EIr^gO? zrvaT8u{x5M<$^++!2NL9yj@Fg*@H0|V2W}vr#w$1jk9Re5wv9uq{0spHsnRx%4e_dUW^sG+%4JAFAuJu0+z8<>0>!ffvb9ybXUucr4UgVp4wf=%!Ym|5HyIDc-nND&fW>9A$MgX! ziOh`8M0!u#m$09H4SF?Qh9!-KYrU`?)L==FY2R!TXSBef>rvXX=gVr5BY@LFR-wbe zXu{4pOC8=|#(=v`aeEcT_kLo(Tl~HI0sQZaD9#>hxbc65&IR~?4UPXPcxwy8fAwxN zC15#7j}WroEz7{(=^tHq)j)k+5P$|XU7$ty&uY6MZf-0TyJU4_oScsUqvLn$$MyE* z{=Q&$6c76BAzX6=ISHB5;DT(q2yY2KOSuc>BZoR=Prm_k0+0&1k4wrB-KH z(FS?LS2weI0%2Bzft8XKS)HWbY|{gJ;0e^OxRL`zwd}G@9U2Y#HD!wnrH?n@j+KnK6EHr1q$i2WnyRJUA;g#YnB!r?c0tgx+r zvf%)Z|Nm~cF|e@x_w~(OR(6}>e|NvBvF-tj9Fe}oP3h@nz3g$!M%?a!TY|0ztn4Wo zNT1VcO%hX@1%5tNRQT3NOhg*jm`sThwsmxLZYyZ78#^=O{Ib2#7-mUxwMn>Zhqdo6 zg0oW;x{eYL_w4O*vr&&bkfKbcW8vds$w$LR#jbqE*GW@FW{`fS77M2I87e)JuCJ#n ziHr=`?Ji0V490|2(Nv}jxals+&_rlo0WMYxJPj38m^}uJ6C6}UpBYh^Sgp_)A%I}X z=_iGFdP;MTHE;TV1yo67CXRzjN4v#XZO8{jU!@4wwTrU)&61e-n=~665d81D%G8re zXlNT~CXhKyiQ*Q?5Z?pG+mKBD0J{p*vR9_!^o@5QIZQJqL{*Kex7VcdgT{aY(s+R4 z1JIpR9Uvk|fPq~Kf`w;z&@7gXw4Z4Bu$M+xh+wMx%{=wgA+k*{ehuZ9`J;$ABr*(J z9?oz|$3T~`Vf6f!ud$}avtVjbzqTp$mUUl2RY59GbeudZmj*1Hcm@JVZ{2K_Kx6PeXo_s9Ef*YEN5D`^^ApN+d7L)c&>z<|PE;oG!|Y$lTVo@Hvj448uU z0V`Mx%i9of#=tdPY5Ffirk5FdN^Kr4OPo~>z_%hIUp;9pJLEXqAIN^1zua+*&<0Q2 zwkYm8AbU-wWnRKx)YSUnb|YLQfz|FmG!;bfXk9PelaHO3m3NEJ*Xtf{`%hPXw{~)~ zGu;a4rl^qPn60-|a2HvP#Gd_1=kl0I=|SQXU`-gt#xaUe9r9CJ=>P((V8An!h6@i2 zU(gF`V;g{=2f9&h5`|PcK^=jf`F%l8`{3h$&IqCKYbE<4)MzZIa6WZ_LXU3)fG^>$ zp#bCiA~?#drx7iOooZe0bL+5mO#~(5`<#{l8&J=wGzY=sThfZTgJdjjMF&bU^2}d2 z?JLMu$p|Uif^F_%INQNVG>+|)K!!l7$ONe~hW|p!d!O?g&>$iO154Wvm|CeaqYB>t zeoHrhL5h0|$_uRxZ;Mv)WXh(S&7M5xQO&cr(0Opm|6XzxT$%^jwshD{2mPK%)lA77 z(o}&VPwo)*&zRE)0MgvY6U|P3(Vl3#0>YgPXEtRSS0;TanyVAzB(h1hJ6z>=_e2KqJp>dg=%|UenM#4i+y1|V8z}Z5^2=SB- z2>SpymQ?ysRqLybzQXrj!8uj&RtadYw9iZLC-d_s2Ks9POAF$KW;o_gf^i6^A#pWJ z{|}_thYq24fhUy`4Z)n^o=MtL#%bxx_M%o*QO-Dj>!yutYNq2%(lUfu%)l+O1Sm7x zmn6x{RpJ4L)d{~9!7I*3`91o92x%I3T-T|J7dxdlu}GRmVmydKmU`Y}%Sp+dqQM8> zpPH9~Sdb4jAq1TmK+&h-w=QjY{Fc$f=$#4G~X-+THO?CuN{W#(%F&3U>sIffmRUaTmN#CQGIb}1xAP?(?o z$H5hv|8~H2u2v-bp}e$NY=9L~e0XWm>~3T;`ti~aAlMkb{Xl1`A4PK&Bvc`Vdt`}J zKo1HFi-l605(8)fl4&uf^b91t1MiV1;{ubXfMImutaT5l6~{jq{0aw;FEBVN7mzBD!e&G!e?8(s#q;HqzYNm={0+6jG-ydvbG1Rnl^+*vd*b7vnbo5v2EKl$J@Oh&R^0{YAIXtyRo~Yn$CdjIv(qtJe!V;eVk9S4>c3=SgB8zQmBr=* zS0NB^ty4UEX;}!V-gi`gtHvL!+nbnIEnNtZ){cxChL>4sZL`|ZinF7D6kWdXYhCr_ z*^|!VkrcI+)6ms%odVpVG~imm7bYT)72%&#&i@F+bKsYH$W5(CG~utI&wHguk4Ght zO_UUYB(v80^V-mANhk8*x*>2@=#laxUBli|JHm|1t9ixo5SJP9iRU9G#orEt8vbC8 zB#Gy=v^2v_hkvOekqtIMS>y&1s(3&^{p|c3TeA^LJq}&{=N#oEK7MTa{@t4I$tAd0$?e4LRo_|3JA;pD-ts45J9QBe+ zNFLGyYV^G{#hK|wJFq^iW(?w$-WO&GR5T6ZyUy3s#ZK+?b+cuR@_ag8FOJ`!c?u)> zwZ#D>G>Qi7i1tqVCOT>NM|=J-|D+WH3$*YQz)xOZ(_VVpz$t@x)UqLdNL)A*+bsAe z_1|O!SGji@)R*M?LMo|vud#C*>w`3s7LG;i%q06NyFMXsxz3icn_6t2?K}-484r`L zO>jg`(6VwzxSE-nj8`&rG|)6O#J+KYtfZVG9aw?9P{~CNmH4<-AuDL8TU`Uq@C&D8 z84&3=vW9ctRBGdZDxvnl4$HP_wl}Bb17}Ym$UNUjf2l%3{~Z6uVU#-1ZlA(lSy>ys zD95the}#mC>TgzSPTZR%1F&$4P9N5?3s-N)XT!^*589&?HcbPWC)`g?;kNMNF9c!f zoe)CR7_*2Hlw%s*?Dk0KOMs`kd^dH4SJ=2u0c}=>20muG(iX`aAi$6Cru4bS&WWCwkgIrHro zZqLZ1@Q^+Y6UH6SI~MOSgVN}WUq;3`q)V4 zscuXinCgN*DLJ<@kV)7ZV*%zciqGi4jo09nDYXq~mv=!NnuZ~MEcxO0^T&w9kgS4s zF?on#agPX>9&Ski12)Cud~3@yAR9(7Wo4e&?a-{SwUAjf!a$DUkqmv#DJZ|Wc%_+a zZR*}-!L*Bp>7=nwL%i6X2skH48q9Ap)pj*9Omt?grHgbD*a|w%%D^Bl_u2h+11fTL zg3nQ#uxultIJ-Cy!VV)YClfy5Eu;vz9y z%2?d>wk)YeylzRBde{P@Q%9FZ7HGzIIT8_0Z>QB#atb1-o7O%5x@{2fWsh*9y>;n- z4}Z8BxjLWPSJ$lI*6PB?$talp$uhDz%dPG%8p1&7K~`&p9Afw7bRf~~E#ecs9dOH{ z#@<0$c*?_oBK*zN&J2=Mz(?}l8F?6E zULK?iFTk1kDlF!`NFX^vU9J-1v;C#DfOuU!^hR6yG(4;YbwC;Oh&G|5@63-Cq@@*?5MK#CqSn3n>hzO6n-5j* z6ly{o>wJDZDhJ3hDrv_oO|ks1(nu(UXtP?mL=%L6!_h=wIz|+n7dcem4rLS*=)V&o zsPi1A6o}B*I_mxwPjj=4sBqavRHpA~Zw6g^eqJKf$EcVG%qL}~Ax=#nk<}RE9acBZ zCC{4o78~1POx`f;JJgxd(s%-cfDUn$WKwp3RYOsJC~}xYDj!XCaWnq!LQN){e~Tbb z^eUu11-R&+Q}_=4nyoIJihcvnw95{QY?1=j2%H=Kr36Zy5NNn9j;msT z#h4ZcJ5d-F)mG2|dbjY$9O@bKfgDci0funpN*#uJJ|&PWTtTK0a29LFfKMS`Mn0gd zpb{Zj1plj$^I)LL5aylGdLUlnwHxFvNF!oJNuQg^&(erZl%pz8P*VmXA8zg<9DjXP zx;`RDYzcDX>Tb1o$VcuC-jNylsbylJkM8`ZpSW zL1nhWIc{d5W(z^0Fioay>qhd(hWy2ga0?y?t}4mBIs?TBa2Kp52j$ZF`2?3M*)7Gc zp#0xu>{09Uvn+xJ1POel8XUB#foY9Fc7C19N;HwPmATD{LUg; z5IlZt4Be+m7L28k*th?BU};#n&S3NMDlWsAhv^w(!)z zq=M`bWBs8u9-*Yy2u=qO?RGr$wDN1h9RZ#FVlRu9EaI49(tgD0Q1D!7hdxUhNfwGbwyDYGWrp}zEA2Q z;k3?3t|o0W7%j$g#|e6piN0b<8i9hopeWp!p;tj%{<5#gaV}6&Y-DCf2ZA)Bq8hifRUy?OX*^G6oRH+2w?h+ zu0h!sMaeMA#4AHpo@a2&cmk;r)bF*$@~ZAEhJT5ISaM3Gd5d98!0Lr?FpP>S-tD0? z)uelMF=M1bU(e?!w+~~93$CVNJLv1_Cy6(rw?(wArct8k{7(qY zGS+;_16a2_!+`n}uuT7?THeCz{_-Gy^C!s24<-Qr=+3hqrM-21W9#$k`s)J)mK15~ zbm17ZyTmOH7t}d!3_x~?FPg{u3nsDu8dB?VPaxQ7swWc9QT=l=sCi~U5p}J2%w>Ju~!BR7H4JobRTYGM-z;>AA48juTc zb{Tat=4Y0^I;P`xn1FdrJk&!OHVka;jP&j98JmELj0&#gOeG$`YVAueL1O2F=e|#C zS*%}BL%PUni^HNHkaG_2=t>P?tUN&{&$R-*Q_HFPl=HmZrfQgOd%kM{HHRzH=4Ob- z=0X~u*`$y*&r!G}o(|!N1|smk&xxt>cQ!b2jB=X4o7V7*i%htkC~t(w=<39zMQVTG zz{5X{mJvBkyJD-YGxWIpD}d(xC%=!}=PO|3=jP2a1lOzEd*SSCE=aT_B ze?i#$S-U>zJvsyCB|#}}Tf`lGw-?XoOn%=3QhJe@|5 z>M@g56}NJoj2_xSF3YscBKnw0*wnF}1)s-qcZTRa8q=&1&{gWtWgRSm)lg zj{Fe*s>=9S*}1;IXPL-6g%4}3n2_~tpF9s;MmhN9`Ao`}CBFMt7Su(z5&hs5b#kT3 zS9cY?Yk=f7(pSp9QybcJdJVzvf#afTT1{+)wMr5EsL%o|n|kE{@nb5}rN`1^SZ767 zNZYuWaKF@A)@c)}W$O5X-Y(L;Lrl#wC8BwDw|Wg>lZAZEq{YMn)NZj=W{!I{)3v8E z(^Xxac7-Z1kDdP3G{@*TZB4-Qj+=2aHcY^TL*SlLE90VTd{a8bqn;54=*{d)CE4iM zMOU5tsgugBem2UbV;nZLNtn{Efa8JV`}6SOaXl|r;NR?x?&s*4A{Zex65EZur?{X; zZRw>B>_B)RNmS2NKwlLnH+O+=c#lbzwO&&P5ZQa&_!+X0P9waeq3(%ICIvh#yRy5= zkv7rwMT8MDikNKyPoYS-&!I4U;$n% z`rAJ6z#L&rK@TF&w_E}k{$lvB+x?HK=t2p6(lRC3#6->}bGlw*dLWD`41gTzxhMnfsPtL62Pi}Y1pb!+hO|0Y&iF=Lg|;kzvv!$GJZ?Q2g^K9mdG!6 z(KsN2&m7V`S1E5i`JvUr*R~*qUvur`j4(mqnsw6~%c_wuWM@S&8}PG&T3iBUF_@~V z_FE2ktJcks)gIFYlLZ}n`hvRW;nj+;_C9nT8-n2cO_OY1kVE|WddI$5E1DkT=2hKb z^Ewm6kfb4@lUxm!9y>1B`t%E#SCQ7kiC5ID7GHb^6fgk`v0UV3Q{cxMSSBd?d% z2;YY8=r(DTe<>um65=rCBktPDY)j_RryK;4)iOCcN$gOetqjqwGudZddDLo>z_gNp zqM@5+M(R3YqG<)_-`H@o&qRW@br^we?IZr;)M+r$Ucx z&*R=eefO7_m-}x=mj?Gwm}ZESP&Arf_pjMKT0n#(f_JW9I*79bC~fVS7?A9Q;1+M- zXdj+$lk31VBHNvT3jJfhZJp&n--UAq}SJ z4k6&ILqWDoF`21_8)#9PUlKlng0h>j3$(l94A=uI?#gGs`pZuShx)R=w?(7RpAQp& z&;lUG{9}e8JlZPWzHcuGG}}7{C~bh4vDA*C3yxF6K3F=- zTJA^3dv)rrz51_{IMcsdEnr9V0@NO+(dWcSOcbJ$-uVEcOmws2?}l0rf{T1qdbUrx}w9W&+ZL{K>qcXxO%(eIe5-Q?32a37EZ%wk@(!1Abn zy4iby4soB{nzq%C^{t|ri&&F{x;;JD0GZtH$W?s6STtW>5w-s1>I}9%C)YlUkq~kM z)y$vQ`DqX$naeJ&o21z<5)JVyzzr5kXZi0}@SG#EFsL+0y&>FheW&*vK*vae#hV9y zwbV>pb;drg|{FcO3Iz`GL7L9;Zfr7IN60E%>5h9(fX>XA0 zpuH^T5^ME&P6%H)X)2x+N5v$%n3t<$#3GhY4K>d^>CueJ9EQ&qCEmL~tKM#<8fib$ zro}~p#9|ot+KT4L`f;Mi3UjKeleKy^S{(D;f798c2pmr9k;NoO*&pBV@88}Q!GeBu zhv2tN9(sr!yXmo{BfSZR4fN4oqCNQoz)Y878t>ULW6av~mC#4Cp zLK(o{%ofzCREzFSi+x;tcZ{p)Z>=(+)i*b+v3;q+3p*jV$-t6Qn~;ADzGJcDP9umk z2R0QQvw!2HuWZhSxw|NzLQnTgV!K4=g|0@eUGIVgVOLbEDSQR44p_fA$#oGY^x@s2 z{~b>N#GWFXl|q|Jv{YVj&Bn!;%`Ym;>Ea#+5V2Lj5T^Nep&Cx>89*?zm4fn-jFk{j z3MeU?A4#P5lcGNv?r?O9Bw|exxsy6WT$~cyswQ3v5(r&#f%WsF(qzHzTV&3rozVw% z!jS$`AIcUM%OS6h65M0(WSB1F8bWuGm zSDZv%74shu<@Z(Y2LHrzbNLy{9%*`yqF=vnXN_UHEsK>ntMtZ$IhZJFHHnXRJiQS` zoWm{zV5V9+OyAv;B6M7uWj~2Z6}7>2J?bJFuGdE6gG3KJ{!#sD#AKHN>T6(UeBrgC z3m&FfZ6EJhP!f11en!l(?v@*7nSp?q&si#`ec`{tK596`FOUsUkl0Y|_Kyio9S&EM zBh6fvr`G;mF(v=QQz0vDLA7Nj4e>9WXK+*nd>NzFNPuKu6bKJ9a1xV*vdB-5fg~ZP zB2?N!Q44I43`$mL=g!O-KCJSzZo?$}p@c5hugc87Hq57?vRk(Si3dsCR@%Y)Cj941 zlk2aJ|4FJuUG?`P4mEV)1i5dYZF9R1ZFV8x{(-wwO7^PXWMD?=!cu1ffB|hIlVY@R z#1A<$ZZ8K2#6TiySG3MGDhHFMH@=JDyAasD-q-{z0(J;^|3cbeHlzd@+LpBnX{73n zX&cLy_Lyq22W+ylPNc|Eu}CvdCgg&OV3)A4!&*m~oKWQexXuVBK4q0usbtF0^s$6P;qDxr3B{->YL2n>h=zJXR7H8yzfLpgRtl3Hz zl=-1f2IQN|DK%S+MuLP`i9whqo>}qm*LP#*liI&CJ)tW5VM}!)lc0puhA{S?gY;)8 z*UF(M3l*S4wQwK+`oZlSQWXbMZ;DLvcl5u+=WcNCI0em9ggM!V%EtbO5^!!={CCJR z`M`|$tqH&O+)d5zV0BnSwf1tRtYhxqUA+|1g=`kOpDmeAjpk(+4O!{$2$Nvrq z@=^!9`C)mkDKqhi ztP>7WI0Ozlwqsupp914b%sc4j9I$64;$_K|ZQHcCTUvmflyIB?_5I2$^|JT!tAh!P zeox!+)}{yM0_4q60R}DkPS~GEegMVaPN3#rwJU$nz%Jkz&ALkQK;KP9si!h#?IOg=hTQ?qh%j>&iSwx?7IoG})NEYB=3@UKfFaeS_0hdWC!CGUmZ7W1 zAf!00G0BO#2lV4<+DI2+EWEsTrOw;kdY(se+eb2c(14PrCp?#v+m-X55Vbsd!I2_9 z3}mEv00st9!BO#^K_A;Z6(&$}+#YgLk8koBUntU~djN%0=`XKNtoCIeB>LlL{A)*8 z8ulkwg%~$`ep{9ss(-mCUx7s~wU8EzL@|^IbHRVH+&yZQr(hERgx1x%0JCZIRY>KH zKRa9n$tG5R^EJP8(qb;$c~oX1kv7=_Ak>cG(?dtWq`2-hao#`N+Nq=y*XH?0P?OePiC&zwJD->%f5S zP?I>kI!F3+T%^z&c2GwECRVOD$7eSo8OttbVcyg+{CZb~@db{a9vBSgy0FG1eR1~DlX%el-U-z{eFsoSPco6N`B z=1g~c{@5m>0(K2@kRDI3-9^tW*C=7-yDefJ811EV?fbm;vKbyq)4>uoz)l$9&2D^0 zRN*`Qbs0EfUO)`!PCic#2xK{$TC2i%J z6U?gHrQveSnqwR^7VrPNn(I>6XnZhD40JK)C|J< z5zM)qT^R5a*_rTEZF)Nou!Suj`nt(FxTxD{7WU?r%tmE5$Vo;r+XPQvHEHf|9j zIxoodI=UnPrxD-gaBKC)Xc~uc-B`>J4w8njqK10OPnbD4Img>O+ks*x%*@Qtt5UL)5Uh)TJeANC$>cN5u5{4hZr80(_) z75|1~ZDR9^9Ir(59EI$HO~C8F`T0sl4-hQz)9CBM9A0d(R+fgP=7?P8eP6C;_O@JyWbRpl>u zw6!d~y}C%#rKlneW; zD%PciwAL%V^8-*msLzL@m1p;-%o5u&fm@UsrXM&DQy*Av5RDH~W2oDtVV$HsDDp7N z*)k__CnPp}1mQX%-@+=b&b6z*JjEYU4bx;oQftD_viEWHNxSaF5$A#LjabC`;Xd8A zc;ton`Jy|oIeR6%>jJRIVsSwXK18``Z}qE0%959ZOYA$_pgFgUvAxvpFkuaEBUdJk zH}Wsx9v|46Rsd^pvjfq-=C&?@9K;Lb>!K<@_YMvg8=nY`C(y}tMa8Nj0{bSo_P#VO zI9!7^@1NE#yu9-fH@?fm#RHiWBbgl*4>{<1@)! zZC9(1H%~Y`e6v<7c!5YWe>3^Q%f8bR4$F#RCaEQFMHScwVj=jE6_}KyWr(L7@o`>^ z+9vlREeSx&eYhMn{?eJP`YB+nUjPkqByQ-!Hmv>^OZic{@l<(tjLtrGr{A{T+rv$7 z>CPFLly0CtImKR>VFAIuN)%j$8;F*yzTmL{Pkmy^Ew9kS40QFbi$Q%Hp|iri!blf2 zS8^v%XBH)u08H71oJLXfn$K^zei`x%^yRDTtZBmwmq&1!^jpqsR@DZ#WS0{LEN5OX zw4Am#ecuZ5ww?!Htq|6^P^M-C4t$$}gk|*0N$kQoRzQej{f1w(!zqO57GXeYUeB_; z7J?ETubTw8ujC02zaN`DNjzq&#VU7rX{d{J2*Rg|1-=~}$N^>Ea10y;;z}7u)Uq0eFgOE4cLb9qrtXo5O=pzhGrv{E^|q3;G3D=QWJNTNVo4< zp{O9k;#s90UPP362?(GlZJR`D|j+G7_ z_&ildTmm0J3D=VOf8ugR9O#O|B%(P@(QZ`hM=K%jhTO}vu9mvpUf1*MD-n>9-A0?W zeoZafC!kd{cpH+3+{^*()ym1yXTc)+suCp*?M27xqkJ~*f0uz8QJU*|>|(h)YXuzR zXb}Xiag{1ru{CXe%w64>(tUf#efb}+X&eiJDdeUuxRHgC8%<=fwbS~|N06f08a@j; z@G5=3QKedEN%D&cYCLwYGj1rnS3y$4Px;k8Z^B}<5O=J)4cb4vL5{+7p7H zMuE$iRp1akW@Vb}f8L&7b;r90%!w~bY_Jc*)97Q>J>e%cEHjUrlGJ}^LkisxMstfr7=M7W-oi!dzz%x2;`zYaA*{kasSyxXny z@n;i0QoG`vfN{P*h!1iX4`wWD zNUfbz92nVxRq8QhtnV;KPy{(-x2smm&hNc1XFulMb_Q@!Oy$Bauuf48xOCU3EMYi$43ER)|E=QT%JwsS;#WPSJ9V>;8E z{V?1#+&r`tsy-Jf5KXFx#T1@D|n=$WBki2Id}SwGU?4zm0|n zKZajjKyB3|!09tQC3C}fUhp?zhiemN`5N)Em)UkT^(6S*wP3sX?}t>m7j}l~QO&lh z*+`iyoyxM@d?yFXmXK?_>g(iIYDe0<_YIn4cOYBex>A1?4Cxcuq90Lm z@acL`^N!s1F#MB?eJJhBz_*`# zqO=oLeHXGF3jK^v2qeVlG3U53tQ!j2fKcNZgyHB?9}=F-g2hE>CNin|Xgoj`2Ou6Gr9{^+*Ntc@(-cTTGLYdi~(jN}pe*wNRgxTgb$WaDcp7*dzvt&FTCpxP0-c5Z!!udtOnEak19`;m( zC<@j&6IGFn(jpN@TcEU!n_W^DLLOl|to;LdswoHnw3H7nJ?l*AT78bk_c%%csTiZ$ zS7@Q2neQ!Cwnc*T;LD|RZHE@lyx&$SX;P3*1CY1orbD?~k&2lgOgcC!aRke!xDlky zN5nV_lNW&0jUl|9*hyL~QfV`6;V)p%ViNsKxg7Cm86uS`J=P%?+RqG6nE(_9iRO%ZNR<#O5RGrGT^6n`IMIg_P?V` zoxW8Yobtlvn@4m5@I$0JpVf1^^85BE?n4L;EU3mKP`bO+wv6RW_^O!krIY9%nYM4C zAc30yHVK@i9){NsQ}8#x!=DohpM2F%-n-<$fOqbPxThuQ_^Uu9tPjFA8$!R3$R zy;?Z3peB0HCuea|buQN}R(>u{8}v*UeMw>a<+Mt)fnY#%@+) z4x2xx$VaZb*9NX_vIZzr&$7Ps($JAHnNB&Oa%ZEBy#^4M))4nCo;;Nk2kh6^aI@wN zT0^o?tzLVYf*X^xYL|QH6rrud^g5X%+qbBfz}%tC9p%r%+#UM!Eg=7hAqSrh*f$Qq z$dW1DxDfN*su!cg$2B~Un=e+nPrI@xVrS>%P_vm0ElkKt{7qXlc8m3=RoGRcAE4UVd;8?zpaG*Ke-g(4a9Uh*$!C*f|z~? z9R@VEG(dUIJp8O-N9@BMj{Xm@J(f3<^i@?ik#;VPtNX-{DnR2cB zoZRp~*54+Bvd&uw5w&9T4AN(aP%U$!EB9w$mHe@W>d(iJDnyL(85BUWZ09>nK$mz@_wPgBmUa_DTg#T5&JkMWqQ+TF!#eVQsN7JrPn9BqJzYG z4ryG-?YEjQQN^rZLC4o7msF}+D1}nf430BJ;FwDlFI2)&P@0x4ZY(r|iF>v>uTvm~ zGk*M0#=WlMX!92R;;XTnK2Sg==7crUAsH))&E|0sau26v!V>y4KoW(0O6Wfv3BjtpwZGll2MDH|dlP~0(Q`kDs zercD|d#zGb1-lV#M!E0Wn)a?9XplTUZzJZnZHA-wMqiYib`M=fEl8hf8C@z$r=^#h ztcj>_c!B#4zxo z)mSCb(utC?WQio(GIp0dCRIdMc5c1eI>lYE^ZOWk2$aiUVhnP?_cp*!4Y-XWjqjpr zDpz;JhKU95MdU66ztG->z4a1rq|qf^A6ehWn?x-65yc}!2&2(y^Ru-C5JNF2Rde(X z$XQXHb^10hxw-i9@LFJstUK%M@KOmQ59VBfdN%yG?k^oNF|H$e58L~>Tmk9L*LH0x z!0l!H5BAKPfALvc3{ScNry^=q<&(}Y2jlbeL8sG*yI=M&^0!T6;rl(H<3*u7;o4oA zt=$uS_z{VWXRb(^R#`eHm6CY=Qc+fHog=j%%yqgc$6V23;3Wu<2qXRAI?Pz(pO!H+ z+30WN3F7j~gOI5UUw4K=kJ6jX| zfW-35vhH${`rn#czv%kp-_C$9*pfrg;vPu*XM~1S6 zVJ-YpTN=zM&c&jcFyrxAO3xT46 z^MO(%i_6?bq8KV@$C*{&-xCGG5cX>hDE;bWa7hhR;IJYfX6;l^(@wf`B**QnKaFV( z)3YstwjlNH{(DCg_0ikQbTiEvVAY|bDz#LT1k>fsmW{pTBz>Gyl0$SF@0NeVt~n>L z!sHp)9comO9vP*ybbS2=;tu?kcyLx)Mv6TCl2VaBk7;+5! zv86n#Ff)zm=tP2EioGEonSRBcqu65v%}8a#=gYb)+%U_gWi@!f#MCq_`HKC+E5dV8 z`+>(Y3Ttcav#ZiE&mYyEpD{N0l(J)V>7N(2c(K0talW0o-dLPqUsdqo!X`!riD{d&sjhW3pO6#2GzkCMwd7#2Dl_<&RhOJAyZdd1#7>rZNcr=~*fm zh~`>)6<4F~Kqa&lFWEI3ULkz-Wpt;!7geLy^qaKU)0pHseOw~PL6{z9Ls2VMPo&G= zEG4hFhrM9wsH~%-wa$erV$`r7#}Bm$pUW>CtcAL=?I_>=Q~ib;Rt_{9&cLbRE^>io zS1XiX=q78#=fkj0T`-CDd!RqG#Y2$?-Hk=YUTln)4$#r&y-9RceeXSUX}Jg z@@S9O9T-N{G4pIq_qRW<1V#(7_beuwHoknk1-g53_MSa%3;&wKwsfA-DH9g{k?)*% zeQ1M)PP41oJ#0`-I{YJFV=EF)xfq3b9{5)_Wp~5e8bk;$9-ERPQ;3z$3F;UL#Uu4j z0?r#*uiBj8_buV^fhbG#*-F(ENw!wd?}V?i9pGerOy=L#Q}Y3X9Qy_eUKVkW-$E3; zW|?AL;k`HI#>~K{ap`}`_~7OHz@ebo39$p3(0xRLD3Ytpk?Ex})qP9%fJ8hF)6s!8 zc#3k?;w2oP%@?vMR5p@?qAIvQ0yH}7=U7%34d{ta_!P!M2U~OrdFM)Az-60RyIPsS z#2uSkeBd)o7zZJeIKf+(GhphhvoTmxqPNl%D5};pp!DbdB@cF+M-2II7@eF&StXo= z>^61es`1mq+Onh)yT^fNV-Gk>g7oVu5*_*Ld`$EK2|lnH)56$57!pIHp{|Jc;gL}? z&vpmWok3Wl+fI>8_abxuB{yD)O%&>Y>X+6i_LruaRwY7j4BLeTOP6Z_1_%H7n{`o8T!wBGl9An}liB0qaU zM>4`}wjtZ0j6gOCqY)4o5<;}FPB?jbJ}XU#cWY9)38=|T*CVU#i4bKUS8&#>z=eWA zmHq)|5`)4y`dzKM@MzgyBlIHaEwn`@v+e2}`V?+J0ZIfjgd}a->>@=i7K<)i zQpMHMDQZX-T5^7NW#~tw2{(_n@8bWfwTf%7NVXN$=~goGaq`*}jO1cdwJ3MF;;8)k@CWcd_!nDd2}tbrYS)pK>O4qJUoWP4P% z8la;Ay5JbP0A3@HWEOjPHq5i%5HAkVj%ZpX`I@~!t>)v4;p6$im;HvldEGv2`?wSY;K>&qLP1J|IlBMQTUIax%2+th zm3^EIYEKG(Emg9e5n`olnNZj|T`$cYy&#O470Nk%aJra6b%qK4QrqgcwY?jTV8RzYxGMQ%5F;QFN|=$F>#n{im)3cE(Ap_Dvu zd?D!;7JQHT(CW#GDX0$SZ_+vQjzWP?;9p3U!b~l{BN`D=1z`eHq12d9yDLC3s+bO# z_<^H81POTA*6iR&=umvZq^bo9*_9sdP!so+H;Fx^dmi1o zG2+$1>1OOz)V$R$ZjkEZ>s{Y zwSOVdJNt{jK~DqBqVDu5J2o*ZFEmC=RrB?GsXPECY`pykwfY+r3=Ief2nxu#Bl%CN zAy=a@6%dei_W!o+Eo_~f4XmwyuA9?7er|{CiF@B)Xz9;A#Y+hmZjM>TK7TXLY&zY% z7cE|zx05cNKCrZctw+$xiK!=b^>)pA-+}#spe7s_a&@|k=o19<6{yfEU{w2BI6v)Q z7iT)XX(q+5@yr^mA2b;*eC|9GF zjg?bKl3E+eFr3Qhv@&K|TTETpFr`?uTPC$ABF6qkRoIGY{X}eAej>INQ>uzO=dG_k zztgH}F)X$vKebm}G|vcC3wzlb;ul*gIw4m>x-NX_HoKU5Q`4e4GABxCz3qBhUZT3X zP%KDi9t*W-@Qh;ij#(HRBFrl*#*AU%D__#i9>r5LzBW(qM@<$>#2nIF%4xVHJki_F z?!%$nojFoqizY<9%P<;bGMy?X5G}kuJtuDNDKw8w)T%SbQ=$9-l9{`*{tQ=+ z30v$9T{+?4eUdec6y=o_A$f0)CGk><#n}B-nVt2*wIp$K)=j5MTmKXng&O;AUJTlYpOMz~Vz#S2yp}PC? zv=gDoW6P(0ipOk0YZ!h~n1XHMRW&9NvdNaLtxjvH0)Xv`UlXLTX@SgE zZ(+WI_S-Qh#Z3*>mJJ<1RZG=$$n=#X)KYSfi;bZmq#THL)X8t<_)*R7*8RLWrFTA# zPp9?bcE3B9cZG7XxkRiS=6Z|aZ-YJUS@oJ;!aVq(Q~0~{Fg-kiQYa4KOcSkbQPH@Xdb>)|LiPcTnZ6y;7HeU*Ga=3S~?Yn1{Xqv9QBOVPQaMauH;}?EQYT>Eu#$2 zV|Njr!5r3vU^41vQ$I>${pE5A7ViQtSJU}|Nx}sKlB`AH+`r!$E5x$Ip)yHXN(>(8 zX{%D%y$zB{mZ@F5mwvAm1S3v!m;dgWGP&T>7FsT;p0;Bf?+SbJ0lBmPQKjbj;bdZE8#u zFP%fOw&?*R!oOuiNDVdjum-z5b-e+YM)eO8C~CaSZO+y~SYkYOB&j!$^E5%V)b!$z zI~%M`1kins4oJY83oJhJXv4%Iy=f>XSxW=lIJNx-64ROZM4we6B$hxWGWMeIi513= zP|~3!rFs0`ukOyC9W8GS8;Yno8^or3?oo6oBge>&cxr9&P~b|aBxcy~P2sDkpv9B1 znfQ8Od8mILXwtPSx$QjE*m*OQ`(RV>lcOxkUr|f!MwGqibNwKOL(1z}B z8YNPNkD%<(^R^zM+FyoHy91}2-J|7U7iV_3v&vPL3W;m{REb~;b)IrnvB_ZMdd8DD z4xzvq$Le*$8}7c-?zZ*PU>gUBXE7?47&YipiD@2LWTeRzsESkeYS;o@G*aByhUdGQ&@dblPHDrmviPyH|W56v|)AqZ5fR+ z2MSA7;AfYCa7I}nV*V1J`wKV(RY9@>cf|p~B1LTXNy_A*Q{tp@P)Q*U#9Wr@^uaRV zH)3#<04!c{z81RN#s|Rza+G3wh^Rw)o)A!fV-L;bUjrH`D6v66YZC-bl+20jG`AlS z)w#?8Y9Lf4@~CeEOIK(KU5RAh3kQ_Ff|87<(V)m|RSQ0oiN}e`NvH~^C+$eb07K{U? zF(D3K%obvh8bY=zqe~-(k$W5iKA9{!FOiu+;Ht8tOh>PwQ=22)oIPlm-j52a0YZT* zjc$fB#8$H!^Z1ulHlY?Fm?sWcbbUfgiXyW(0Ygu5l-xQGnW*$ShkU8XwVKSDCeS~q z_wUG|BQtWVMST%R?c_h`bjUN60>zqKFyr8U-Z@%U;zqW{**8;a-;!z<8}2{u>RmO!C09*uAbi^+{#jkE(R6uE8^CPlBl! z_)tw&8L<@f<^^klg6#fF^HQ}|w|fE2h5DMoQDKq9hGT+>rU)jk4hXRZMdy`B+z(#v zMe)%IThnk-rSLD#LX`&lDyf(wK!~NgMy*)(njG80?5-4r^FEs(V5LM&>sbE&DYUXf ziy>DF+Q+#O&Z^#uk$xsWmYR?A+6>U{PPU=8vz+cZh+-*CqiRIZyoz1{0Qkgz!ZN0` zfjkGlZBq$aWb6;J=P^VzL4-_+fKnVkHT0)cq(=Q80DwS$zXGNwE=H|HZ&0el>$X~) zK#a{Vv$R{P+y+@JrhUHvqQ9kObf-!q>LA}hEnP@JO#2GKwijhSm8@c4%C^-8lBros zWo;zWV;v z-uGLc*HU{t$*@ilVVKc#oRPHLUHh!hpyP+80ImcC zINH*J6^0~Mp1lP9vEq*hV)V^Ky!yrxuG=tIV6wLRAjKM7unv}`yjy_EBeR_wdA|ZZ zYzNFHTSsD^fQgwEve(MQ%(E+y7R$?cTFrO4jh#&1s;@lhn%#f>_Uo@Z4ZtFqTAq+H zia{qz&K~fe$CobOlYNdP+d)4AF6V4MNLYDo)h8{Is^O)CwO{($X|A}~*t1G66tqUr zbc~=9PO*3SjU=-RbcD;GSBvT*|{>`UQX7mGm0buP(y1^k61l@ z3_mYkyf{&Q8CKTW8DN~cC<6LK!p|pk#1cWpY*~`QF6xvN85Ze!O#u!@6J5;j7a%;B zZ7g1+{}yXH05ud=dS;+k%R2Uvb$&aesrf0-h^S9yrmlC+mJEK((tNMfvb7%2&TOp*l{LjOkLV>Hw>&{haY#T&Y9zS*r&AXJsqL!~=mE#*e@E*| zX0(Yl5hthW%PB21^urQko(Y^c2$y{e0g|r8R%^ITT7s(apE3a@We(yBdCyTV=V^1( zR~0XM8r|8+;mJPhPD(HNCjK5pe19))g^pl!8)%h`lnkt@VEy8?ie4a?2r#md-gyC$ zLUP3R!iGu^t)%Q(7d!@=7vZBhV98pbbY7C-{;WXFO7OkYv z;0q12eu4dkX%D646_}d@vy>|$F1mB}s_(x04iV~GPkr`L1``TzsQB%--+JKw`9SH51Aqgz@j_rKKA;8m^&9==E#wh}b-lOWScK>;9j@IvM9a0T zxiNcg!lK-*hYk%WV=2@R9Zrw3t%uvYs=8S&yoiJ_N=P*H8KQG7h>+2aeSFqppjMCo zRbZ%POrcOH2-U=xX?rk+U5jl%4T$K>l zHBbxRR?AW=gz)qAq23Jel|*lRCw8-MXfOK%|MK<7ZR{*)VOdp1Ep6Tig&9s?7s)P? z>D7e#4Ys)j2z?C9>Kuop9bGhod6BXg8f7Su$~KDB5W^rv>#^$!8XTV7vKM&cHfQ!W zV2xCK0+R&;mfxudMn5EB0Dp~o=LD?!wh^O>t^_OSRJX-YL!!%6)0P(xjX}z;sWu_FiV|fk z17IK%AnSaAH1)S;Ocy|&oK|z(Q!B5Q=@oDyETXaah$|q?1%(U^4Aod&SFp|@IQAMK zv)+{CE^E8ZebMG~wa-dhE-cU3MaXgueHo>m?`kzu?g`p!(a~{Q;sF5agtes+H&rx7 z8Pa=^6-DG)vU-PxiqZ~DgKG1E!?gGrT~hRFvz!5`$JQt`iy}vkRUlkP3QghziVG(I zI9qmJM({@g@|B}P!jNLEvG}8SHKY^00Di`8_AvZG*a&CVC;@|h-4gyKLv#brRSc9FNYs@ko6O5X+Dpl3o(}|Ab?S2xYJ>| z^zi*lw*UsOIqyLydIf}oCCn+u!CNRfV;3tw{27CA@|a?%K=Z`KI7hD1DEq~E3XGyj zH1>j(FcRz$U=%E70ia1~y<=YxX9#G{;W!G#H!m^F&V(bpe0j679t6DKoo-}?qvuFe z4G`!K=D5Q^G0`)kpj#Nm!HeE{4kSzy!&qRv_j6&OUF_JzdJMk)2cYovBRG(X^ZaN~ zGwU&-747*kp=O3Lfps#eNwIwC^cOUp$et=((f zuzmui7NC%U+3K3{J*v4q;kY`>8fO@uw?OQH&5w3}WD%Wn98C-&7>NVPbNIHc(?piH z&IZX@j5&AbrmK1{l&FDG5O&u`e&5MjfM&zAPoU*YlSVdJD%K2C~l@w!;0_l?=B&Y&iR<|*I1XF%H<^9I|ok$YVU zb^@6a8=yjk(Tl?dH=F7P0EMvPTT>p02~YJBRs?G z)DTNxv4mDa+?H8kD7`2S3mCG1Bk^3GsFt|!_&y6m8g02->@zrKfl>9w-5XWh(GqUf z{%97R)j2z4b#_x{ytf=c&pBFxN&8^H|DpbD`AoKr;?3I=dc%U#f!KwY7PxJ7&uI%B z>CfgJ2Qyl*QY5g+>!T1{%zC}etEI`6i?!!mHKF#k7}1GX*|TVsmJ}|DSy3D^mC;5M zc^=}>BvJ_;dSH5+nSr4Rmt8~pLy01WQ!yS?ZQ2ZW=tSe}bgu8JVyV4Wgqd+O^CW=i zK#cz^+7=%eENyib?3p)6e>Oqm_Gj1`^VNZPHRQo^rH+Av_{?-#03y*b;%6M$2cB7< zJv^wc@*(JMn*#lv-`~?z-uVGS=}n)?MLN9^EsC1nYp8^E>q#ddOpaI|)EiEqp$rsc zMJY42*BgS_xege%l{Q3SXB#acYx!Tzm7&s%^dYQVg|&3W;v=kS`4oGC39wB+3yVgB zTn-lV>P|ee35}od&OUmny%>5Ge$y|DAHOh1>vchAyqY6p5DMxX4`ex(p;D;R2!haA z7xB(57??}!`sh#O4P*bpBv}jD$$7H3|8#0wuiStH>6HsAd9cL0?mQOlYI(=!>T7?0 zF3EtU9dpoKc+<-!Q47U^0_(4|?%o}j@mSe`(%X*HIB2|WvWKTk2X9?N;q5}JZfFV@ zstKgpW6Kv&JW!AZYJ;^4t3I}HsexT1p9z7W_8i||6E1WzlxiH~Z9@B4>o$34#yboaTK5OUh|3~FG6ba= zl3!W*m~SW?)4r*vNhdyR$q`ieVZ@517Y5oH4LbFEVx@s!1XB*Q=9+L&X%|TfIL!A= zntLFbZJmMPu3UP196xX9xEgizMcH!F^UO-B{<9(kCtv+p5hCv5@ZVxiXfGQWKfAN4 z+V%Q)nb!UzL%hCz0sx?b_n6Mg(m$-Br1bp=8%2NBE?~OL$6!1}*s5+M`aD+ozpmay z6}+aPejnRl7Y1-u*qW!WYu~-$@)<~js#s#gUW)O!m7Pu+CbGks;rf{+hr>V&_m1#n z0$d&GkTv=SUr8ZFwiu~`v`{w_U5`!)7!NqCWIDYzN!lt^tzla%Wi)G9@S$ZG)5qk9 zgUs4nl%TsKRU>H0{tc6#Nm_!;*NjXN$CwAHXf+X60Q5n5oy!ts@1Ij$~&VIP#o!&e2!a1cs2LY+JHiLtOJ1~9S(#Otg#62kk zq4P0+_aTK$ALjmA z6@b}^RtgmQlAyqWMm*Rgu!`TLQ6qH|{hEDSO|==&;54$`c@%wk_`x*-bo|g!8XwtB z1Jk>a>VO73SWaR<%WdA|Er&0wk;2F?bkGD%FHJR%jlyWFqY6kpd@9xsiL^Ebq#dBp zCU7jReHf6AYBr8FI)|-WbRSgp&y@Ab9vzmQKsGuO#8spHcy;|5iWVZe%{!}KV>@h9 zl6Thd?E3P-ZA4Xtb*)%yIbPBTeoQne@#7Qc;OtrE-~dk!Ac&tqPWeL9`EgzivlzSN zJnriF?hCURAKj9;-fVq@%^(l;R$c6D2Wp_dHalB|!#F!!9YPGH=Ms{(8~Cq!t=u3o$#m96Z|s{OtVLB;MfL4c(&Pgkhj|jr4c=q3Sn~l+%S!uA~4noW0&gG zsfpnkU=H-v(}@xpSWW5>EZj~3xNR*1Cy_a=tF!giwZ0y}H3)sV9{u$I=4tucD^o@b z3jE&;fyL2pt*yoF(;*DT2KA(dTWwi(>`JnNn%<;YCoCw$_2HG$xIv@$mD<}lvXjw@RFV}%V1y5pLW7Yx?fnRKCMbZXY|xrnjmG1_Qn0>s zr9!)AQ_2|tS#e88=2c`NYs~R@X-@aA@wiSf(3T}gcI!-6@e+pdC2vVl;9JFe>1M%U z&ImjGT^|UvJDsC`FzS`|*KIoPIr(^Ua+bXL;V{5;nC9oC;x)^x+N4}orOhVgVB+n0 z<=kKDbo>La9zX7H?CRd@JbgO%i$U1=>G(MM@YkcCj@~4njt?Up{nQaCu)ksm%K*35 zv>jFss6U)ur@Y+iOnA<<%lOc67-~$IndZnAmhl#n3hbOw_fy1&oF99t9*hFzK|o$% zdUmZDJ1-{|grmP5y+2Dn9=$#c_&_MTgR%i`RM@M`aeI9Nn3}+ZO4SgM->rZf3GJ0J$E2%^+pEyC|8eaE^z#zl#qi{1g zX<;ux!ckZClT|QsVV-MC@#WxP{VbZ+sK?e`g zVQ4$2ogY5SWaigCm9jgTaJ5>+xJ=TSX`s&TEYd5v3q9C|@djaEl zK*9(8fNRav-rlzzHG;{h19|9nC&79)y>QR&qH@Tu+pwDF$UICf|AAB@ld=jO(J|7d?)2mCS{ z&otMe>fqF4!a<*E&ynz4Y}GJZnE;SYSt~@RLDqV*;Az%y4gsVV669-Pl|1HwT z;zJWc80&Z~7dg)ZlY}?@H)F9LYoLSdxwvA^TmemN%n8kPBl zka)7I4oI}k__z3~=ic`4hK;55$9V zcb}eo`uOIEyx!41>TbLiWr56LRpZ}29lty5Ds+3%;qu4t&pw`vmK_(rmf~(axC$m+0l1T>=X~mLmF7af19#I*?x?HYMC6JwWRBW^A-V6M_ZHF zfwkj)E8MM*>avw^uLjWXg;U^%g7nNLHy*~2PYi>2X?V`rz{8r<+txTWaUX1`e1xpATlnrdMQ}02F+SaWZyFIJctf;0Azh2I}w; z{FHlOw`WvpaR#q0C8m@UfoZBx@pLZz&4M4L$>@X= zM!gJVBZ2})x+L#o<7t|N1V0ULlBt(;c?O;|GK$XQi}Uni1b_ZCI^Wy**Nd;lz9QP*N?^gEL_c|1Q@sEWOvap|AA6HXtrfLGurs3Sp53e8AV#Ry zBEL0G9p_E3E?stU;Mr;$Ov#}Mxt2>e=TXYW_Psp=O}hNtx2lafz0SuN5(Un%@_9+! z=I*005TT=Xe@*LXO(2RB8mM;OaYch_CeQxibEG5ehIn&0Ze&pGnAT0eg4I{$z%Von zXK3{L+6;AdTO7?<(~|le>_+_Bs8t*ZtwnHg529$5Hgn$p9)Jc5HpY_R&DB@3lr@G9 znLvDs_r@!QLfKCELGa2gJ$z8{`Q8N`LyU#P@sIr+Bn$AGF{e_!^TSQ^n&giofS*UE zf`!q2-Phdmb7Z-fzpuY#c z$tfl*3P0kloO6?v`l;lT*GU1TDhE9qhIf<1DPxF7QSdjCDLezfc!7U-S<#?Oo)>k&SYhXQOdoIw*^3v2xXa zc6nM+<;wFJ*sycr&QCubo+O`6k3L4@^%_)F=T`|`2+N+;MYV8h4^+sre);1=uvhm6 zYFq_s{QFRiLE(7~VwbHOAQbj=u|k3(hiJUU<9M-3>`X92OO|SXmG=YQH~egiUoZk6 z>@AFN{Y4Zqy_I+u?=`YsLl+#}g3U{3=Ha*!`!y&aDIY=Kmz~nRn_&Z!S(6vMUbMH? z3f%O+lh>!eeK@V!o0A#{oVKY=X%KuP1AlPQc$B=DxbR;`-i}Dbklah;82G)8bGw39 zfr1WSs&YOH4k#}@Yy(r<$=@ZVZ3P-s#ESrn_A#9$ik$*+@63mgGlx?+Tg=O3@u_aB zvTq?LS1is2a%Hl#MfqtZ3p}+qwBtpLh#Opnm-=P?a`M9wl~IIs!Js5x)p&wK=HEeP zf3)-Y5RfMGu0x#9F4XO#rL2}T-FYHv|AIU{B$_WCHBNEx=$gAuMqQzd8icys9BN!7Ex+wjx`N|fZWc=G+^?|L$Tjew zb1@1Gr&;^b8oisM1BR$%=Vir9uhi*iddJAV&PVw#Q9j2WR@ichwhR^STD*jgvh>0f zdyQc?Zm72>w+(AQXYmx&_ECh2GTv?;TUmXe57m++F2caXR9vf)TRfl$y`>}8+h9=| zMFcOh-8MLh7TnILYqEQ9v~hz2DDA%o1qIMSLea`L7R-pL@}3MgYq+u6?d5#@syGfT%U)x}9b8FPse zHI5e}bzO6huEWi^Xj{BChZlNHL)9RL7@bpQYq0001O zWpi(CVs&Y3WG`)LZgg^QE^v9xJ!^C0xRKxeD^QuMB3Y3c&t58Zx)Qm3 zkY&ByKxfg(Y;$t5Zt9I#F4wzm*U05k6q{|`bRw&&y34wvuG*86-~8q`*LOuL;D4F8 zljT-6qFpt`wiD~R5tr{jXvDHBXJTEH68>4$n=O25#JbFG+u2Dc+YW}Wa?#eJu2S))EJeNRw!04L zDk||GSD!u-JuSRLDaAHx+M>EmPfp(Lng-su+(SqB&tu)(w*=V%V?GwuFPXT>R`;^X zQ}GGfnpW&uDQ;yYo2--h$+oF~k?;aU8xfJ$Rn&<}${di;`0F|aJ}HK->Z*gcE{hw@ z&_?D(12~p#mjl@+s(DqHCA1QsRa2gI*{aOiR+^??VD9wiy5%9ZS$AjQ{|sMe;xkMl ze$v40-r(r=Ti^z={8|y2>b^I-qReMPRu4r}S124au|atO{4-H+i9DPVcnKg5ajfuz zLX*J^DomGE*VOHn-w3|QX4^>k?@YXDyLWY!7x>_N6c%c_eE%IYxn_{d3gwz4#C?F1 z`?)C)qZ(Dsn0W{Os+f}&{n$4d%%y_*sk*P~$Lh~nxswV~y`F~nL|^|T_a`UCT3n~s z|NZ&H^4-6Gc=xBvkKdi22>8=Wq`5^AlPA>3$a1-r_zJ5+8jSCC8=$0lb-DDRTGhF1 zVw~d?UsE+CJXkK*`2TEIc5y4qHO$A&FXuqmn`)nk(?9Yjh9% zech%g#_2D0Q5o==hzQduttq4+3JhX#aQOf$7XFQcV??jhv-B*Q#?Z*W?qGT5E~@MF zd(cjEz_@Tw&Z9qG0M-a7{a4Vs(ZZS7clBliDx#mhB@9+{%Ox|-;lE&*c11i2JX`Oo z70xz`Wme9w(|4d;vzt=R=ZhIU`Kf{j^SoHWqD5u8SS-Ya_*hpmfUc^SH~A>OvDJHE z9O4yz=w%DvG{yG<5c=o0B1$9oF}@l+#(&%gL?k?+f2ZdSl$vZ~t(cq_BMp_lgGcY- z!vs$Tf20lv_^35~i~oHQGS*8jDy6H^xBS6jMgc3biU^okpS%Zmw%K^v|x5#B% z?_d%F1c9m2$qnrsBUG{V)!k*C*kt!o?3me1D0d&H(?;J5r^gv>bdC@JMqw^&nBiFF zY0nUM2-`vkj{^0Aa>C->$N1IZ4tLK+r;QOdH|^*xW|K zQ=SD!&W{*htyYt>8GrcZ3CgCscga$9EASC1|pi|!7&P#}Z4tSBc5 zqQNF;+JGZhRDoHzv^=Nm2K)zcSGTYcE6W|JVh2iCD28O{hocKXIXY;09YKSF4v&Qo z5sx*NBN+PmxNsA?eECG0&Gh&P)r*lnC*IROy8(SpXq^T z?~z5umKf}~)0P@<=BQ3!7oLfS3|E+qAuT{l16;q?qyG7`@;$$DlVcH)-Bj8%?{NRSfNuBZJ}occr!8TFm?z)^)^h-loRB$6VGh2J3~HlBj$MpKN67{F!K0eZ=0r$v!HfO14P!;S(?(^W8C1;qrW zNi#4nqV7XQ1fi4D?cpB`8srp5nkH<`gpoOU3O+C}`IJLZ(^OK2CAv^ArSwhtnC&?# zg>zlWM-%P>PLd3409k=?FQAdOrWmv%Z{26KLA-Wl0yPFIt~Qx^S5}-wgPS_EwinUA z*;1QEGg~sr2GHB%Uc2qu-i>km^U)ZQ@_x|LX4i)z8_MV5$!S0lxWOQ$Q4ll6q0(%% zlG`p;;E8S3t2R&{Ezr)Sjav)nCZd#Hax1!#0~+nv0II()&)P+^9g(7i{iXAKWLmha z{tRTQ_8vb<)6Tt6N#BE*&T*42U02ygCg@N8Wgt?|Pw{^n#EfQ3pvVQe!Cr+=0>VWCp%jfLC8VVBpOe*P$1Oh4jDo-Ws&s-N0=9 zJ>TCQxb+8a_nWe)?!6H;tE}M+_u7=iW1qjxTFX6_K~Z4{4+#+2H&2eVyis?)?4)g>g7puVk& zU!}OBe%7MHEK()_9f!{AwXhz(%~V8A^N6?6s%O(V422#8PH3PYUx$i*Rx@M{Ln!^F}!0ooCz~aS)&2XSm1xYl!1L%vEAdJ~Gkl_$T zq4nMa1oko3sJxXqBcQpsca%&odyYC7jxweYl-M7w4tR4ppbVZ*#`rxD+`(}2X;toW zxm3Aj{S~40?5Z{#JI2Jye31;%Agkt)-91A6jPe-Utp~eulylIRn!WkKy<~1A7Q0{z zM%81}Is>~ind&t+(~k&jiWN#!v+&22~8z9>zy@!I)%siK!gh<0~8R`W7z&Xnseujz`S<*&> z_W^A^hSigpFMbOQcJ)<+3JH}|I@C;2k<*hR_u6r3&=dR+=%;oQuqFwr|LVcvYpU^G zKTZ2nPnLmEq#P<}7akV2RBrZ59A9-Ol) z(G~USsm=7bP;z_8QO2LlBlffd(7-n zXpYn&zaJ+aXx3E7hj)F3XK)jL3Hr?gZ93(-7RpcZGuHNajvI?xK&lLj&gJUff7+ZW4JZ7XIx;dxuhstu4MQ$y|@ItFny5 zTht-(!KoY#NhJ2ZilImWR?df}sT=ndx8U>iJAPc`Y_=h>3Z)v7q00sPEvh7| z>WhI@b}+qWoL-nHD_~RpaaVQ4MiPB7g>aQvu_c3K{5(R(&pN1ybq?rC{cMl+b1FV_ zvI-Y0_<1+GTb(O~ei8@7#BmGT62{sOS_WZ7(whp(Z8zG8^ok{70|!SN40cB?I!Vxe z$O9IFvLGxZ+LRa|af}Hqt>C$C@I&mF4N8AHZ^f1nV71FMm3g4;kHjBy)G)E4LLnQ) z8dn)BadL#YqPo4*X3^C@*y<(?sQ}1Z8NpvU(HoJ7|GL@vfu;(rjle!eF#*_| z<`g}bV851Dgkd)#-I zyTyU|Jt=leH)s@tiSSg0#f%`50JSYGjt&$wcZ}~nWoz@vN2*>AcY=p>U&s=Rv4)Xl z--A&u>d8&im;E_ z4hs?}7X`iPl}sU%Da-O02#>Iu1?5NE)95+@k_7DojQ2()fGK^3Hbnvg@~6>NWyPbg z=u3U0O{}aRWwTs?xvp%1aLgG5U<+`nrx5}mjzf}BR_&u_f5z?8Guy6bZr|XR5d8Cv)>z@ zVK7~o`41VdmHuGu;LQxbhC?cKJUa3W^`t5_7R9+J=4T77Hpj`*@qC*!Lqs3#=QfX6 zYhy>h(yseMINZau`Kxwz=!R(}^72V_L&JG*KGCLRzV$+mhhdwJ_5sVywj4FbB5|QG zt>~qMmC22O!)@604tr2fO1~U@v*g?}Cyq3)#y2x(L?uK!;EXRswy^{t_%(9eD76sT zjaV133I=CnsK`PGOnQr9a3r#iK%wajF4(VlKD~>-MAo^GNT2D{r)^DxCNu4xx=7`) zUx`bxma;^{vD>S&1{gO?#asA9XSmxE&$yTSl+9L^pFFqe>pci$J7z9tVyVuT;{?=g z`k0mX`W@|(bA=8=K%}Tt45^XjFs8(a*RcFFqESBq=~$cCE;Ef!Dl20s<^lj`t~4>e z&lf(>yE;j|>pKtAiXc#5sKLysRwSCO;>uQohC<@>Tn7wfSj zd9FMnh4#3rJnrhcMM{(6d&Lo+zCjsg>9$123^Z5p78Z?3=VPr)4y-txS^5UmOphH1 z{)fk$>ml6gLH)-8ZQad84Fh>t`9u@sL#yUs7fc($b~4h_eHui7Qn74z>vi!&fl|}o zc@XHR!p#cAAK85x99bRywtK3k5ShEOTn2jB?c?kj&VYH~llE*c88g?`n(>d={r!Sp zPC=@DjeuELTugs#oM#H3tFHS1njNmTi+*t2mllHPWB&A9fAL`YDJ{aYAKihjTW4j7 z#v*~)4Ib=D-+7Uh1ZsWnA)g(sI5?l+9P=E8_Kr;XAFeqLOzO*umW|Fd=HC*x2r!E< zDu5qx3HOlMey2-7Frv}wR)E>9@T!{pit|T{@Fs_UuG^=FC+!}- z24k*a76)-Sq#wYRW;bnJ?m9`y;#jA<`aRanVPCDC943J`{q)@q48+Z~lk&CO@Jf}Z z0aKA(zB8>0=``6+zThA^Bl9!Do3#}=Gi*{uXVM!=j{I0WVQ<$=0$pzOc6a-MQto6( zMVHk>Ru+72mowB~$mP|;CC{nts4Ugp11$S7ET{h7mdTSz)?0-&Q6ADnDsh}s=~1>97&RA@3=|A)2zX?xHNbY`pa*U=F1TqKX1*&^)M^e~pNo0HI-2TdG5o7iw|xPu znnTv&*nn$b$w4umR9JTrRd8d#U@Ipi9 zD3q?P)9L(&dwi~|{T=v)!?>P@tGCrLpwMQxR&`r*1=DNYVdPQ6Do~5|d9>Paa+hI# z3oy_^YG#xsa6_%F^+WHJ{#nbcpDu@Spc98Fu{$r^>LIoZ;sY6Izn??7Nq=|g;H~iT zI6M!_kJUE^0t2vEs?HGVn*-7Az>ibU>9g|`BRyGz$?;ObSS=3Zwkbd*cY6hYD?>`jAgjDaQ3Jo@H**_qBgY&$Vsc%Mku=7B*29)-+D0 z-Md}q{}sW8BAepjbswSd&=EF1dT(ZYjrBFavJQ7cUq z=#Rwj+|D-(bFK-H7%Q^#TTEm^>lMYfiy;Ru5gdf74 zx$bhTzwvN7VPHQ z*Rk4=1s)HC7sp>dHWm%K+*9+bhy|C|#M;VkLT2(}7Bs=80kL;7C zUcFLpe%veHjReLeQ+F6GI==TKkyTezR>9ipe4xihD{=kMi8ud5-bh4dZ1TB}JL|ng zWN}1qSF6MlXs=w$Ek2su)k1e0z5Moz;Q|_6fjk69_5CwuCVo!|nyF-uMv^#PhBdWz zsj!Ob2Lg8!m2d753?|z<(TeZj%Cayec2+QA9=JTtDqQSIM2US$!P0EH77Nj1HL?{{ zFfSbHi_$*QpAZCIIZT;-f@OkBOKoHZSYgZF011mBRUs&UtJQ@T){RadvBYYdt>jEe zFKy>n@~=BEBqRvh^=?~AR}%T|Pv@i%{GsiFm+v@bg)lhVJ@CPt3Pl#G!KfgXP7kQ` zUw<`DFB|j@arCj)SJenyH+boF9t|?Iuc?7*JxWuUN-e+? zvR16OgAgc56;cbL0Vp^&taq*^?Gq;>=BJYT^?uKK_HS81+NC zXLr5MGYzP3oWgYioqlhRq*`hEOkIklV3q1TTDkU?+RJX)J7JA>{ptND7?v)mU&E5l z@B%UTva9lXMK^rOJT=_%PtXncipq5S^pSr`T}@*e1*c*X6*JK9Ge18?)jo0lY2j=0 zc1K4aGdxy$Yi>rv;t#y$AFn*?=;{%^rI#=Dr-F>NgpT@hPrhr7HvuyOJ@jt%k72h5 z8v)d$A5_zq_FeQ@IzDp7MQCIvx=dF&JO_)agECj&2MVCHtiVWPre<&GfyW*7VRsG) zJ``=y)pRk&+`XY6OUy>@=vR;28~)?OyF-I-X#Cs9Q@%OYq%sDwRTDcmWnDMtTVTf8()+FA zf^!76$sX}ykf4gU&m$v~&>sR|=t8G|B1auWbT0@$(B72Qgp~>ybUC97@|DHGhgLDG z`LXW4#pu3wdR1*xT3Zw?s$i`eHGkcwns)C9ESq=g$2t1@Z?srvYE^o-3Z{RlhQ+tA zpQ`hwY$EQVH>dwhZzOGXmsPiX78)bBXxjC|g5_6qX*3l!RwO$MixZ4rp6SjbBAm>| zF)}ZyZjr8V-PUbe;IVa5P~GqXMezumthow-HBJV)tIS7`GsDzWn;;U}I)e3l4!fu+^Ph-B0XC!{1eK9YqJvK*mfaK=r1)X4bGP&9V>c zC@fa)94Q1iO-j1V4GyUYvJwwNYwAt+0ygn4&mnltN1L*UbW+6Tg!86;&9%$iSK@>D z!5sS~?4Qq}pBuq#spqGvE1guH=0pqquEccgMlbYZbZntD>;asEqyCO!1uS8$hqG*H z*uzR{R1iiM>-0LH;iqQor7C~7&FOLzcd<}pAW*_eR`g?2&@Ut4d z^rkUw%0ThV+`VRvX#1o@_b`B?f6OK9#TbFuY!CF05Cr{HziaQhXe4;nH#)*s!9U~v z#(cbTy)`cIH||ugx9PgvwRdqM=zeZCDvP!H;ir~<1qbUuIo`Hyc<3xuDCzkMRg!6hCC@El>QTOc}KJ+`aye*o6Wb-P6 zUk91^r4OE9C6p=J^?2X@;JsX-mW(#Th%PXNirVr~(LHhY`FEAOHopx*H()CXC=4 zjX-62tbM}&DXuXULC2e0{$YZdeJo+A)YCcTZ}k!Vfei7qjw%if&_gR-KlO8AFIO%pFDChmgSEyajOIj%o<7^{!6Z?UcyR!Js8rzajtqw1>(A<1)=PLo)^y5wYJwgp#A_$4*slM zh$dx-^IFx4E=XKpRhj&x)2g$zIv}SOrxWj1c_Ml=ydT7eAXTCBVQ#V26PJFm3c4RKZESC6 zE^vA6JZp2~IF8@-D>%*v+0%};A5&LXzVg;&(&?VmrIT!u>6xpHPen^~tZiBJ=#j@} z^WPT$DT$O$iN#6Ipif5SHSk=P%K#|!yhScoEDRS_ zS>+-OS+ZKoyo45+EUEj#^K_ZWs#X0gi~1>%^;2=z6qd{z;HEKQ#5A4 z-85E!YhEr5T&M68#=Bq_!Nvca9)$ZpAMF44;qk|b$KXRP6h$HQ2=apSQ@1?={^dON zTF@ZW;q+AwdK4$(N(DhzKGUuht{jt;S%x!;^6eZ!nhfAYk=6SJLfB=U#NfyhSVmM;E ze+Ai*shSVuY{pkeLCxd10?Y+SS7yLZnXhsBs*}2lkOT2 z#V>nD;l;t(r^91-H~@S=gTFmH**`cx2gycWyuSTG!yhhK2|6v}Fpr=nL`DMk`GV<1 zio(3$NeVhm^;WRgqcOV?P@1N59({pk8kYoZnPfa=bFt*tiOfw=K;{nhAkX^;iNg!7 zd0GkfPb6^!7(wp@BD+pf?2ksC7baO4B`}}<{-Mv3%mDVFA_PIc zO3Gz5N05()7eD{ik?t*(BsR|aJgI)*4d^bep7aYJJm~a}%@yW&E{sEw( z8eWxBbMV)_vtydrPR+sD*~wW?`TK*@vxEITq{ON9er(iMO%bk6FiwgHQ1T%t_zA4u zlQn8laBXtlmL!f@(ZGu}CPM4oaPZ^#DV;T0`GFFRez4RPwUZVga+1hBrLVKthWS zm2py_AcxJWw5wrwGA}~XE>7K*h@m_p!a+`v=4zb^rD=m8m~EcOLKyQ{lNLs@0&|r^ ztJh8C8V#2!Kqw}%x{KFt-_;|kKu>oy-x?&Y#$}#GtX< zasHGhKy$TLji}X+j&a2@RM(jdwSO@zM7kh-eGwd@0fez%BB8TZF(F9M%ZH1+5)D|H z-?eS5$MhN^2 z|ELnsl+EaHNIk5v*8uUw!UAe=E(`HYJO&eLM9$(Sgkz=`I<4+)=$+Qc3H&y?0QV7` zg3M&6r5anL$)d%J$_ZU{w7quM_(3nxWI93z=*d`6;x-c0Q^<2z<#7n!cJ4Oo=OlG+ z=(MdUgD6E#j4a67#X<+x9boai5f)!L#A5Rpi$8CW3V$irN{t#VG<2&qNj^|qH0TCd z)-D(!28S8^n12Y++vK4PN0T0knj*p*MynXcc{wvN`lovz56&Dv!{tHSm^Mj4u}+h6 z*ur0GEVFiy0v4E!CIzEG7;qmI+$@u5IrOp6w7TWQ2=`!*fJNFZ)WT-%&&^v$M1QP`MvEok8Mo2r?A3@_%P~>6`{IB zSqwvvnJWej#8$?4^!N?~cY*mw;AQ(vvyY+!*E~;9YmXV2m?f;9a>-$jpI=p24I7Qj z!P5{hMwc8ED(v;Ewb~t%uU-gt1Be9utZ>V?g#EG>6$cq;V8o*4EMR+0w^#wZa0f9s z8?Z^!AFT!#;x~kdB~4b83Z4@kDjb1?Wia*N|HIA!%h!zsHc)(^PQE1T76hlC%r;Ef zBB6N!x?9Y)2Fb30f5zS*lIy!+M+7uCkWg5L0Na%ZD7;i)tRcs2E_a zLAINy(U|!+eplc}HtOOTxX+)9ymuRG7qpYA7kIeh`Il;~Cl+i-q4ueNRM45QVtHfs zMToVU;4y=p!#d@6tvlV!Jg$80HaD??cK&&uyHNz&&DrRv8=fb58(j)4p@NPOw|{v* z3EnLpW`3aJ;X{NERuXW@EQv5uxUtVsOBw2Fm>yIhG)u06p}L~SFUAj=p(Lw>+bAiL z4CDEc7(#ngzj=@21S1Lf8l)vgC}%aMJ!q`(?V|`W3>Ko!9wL87E`HZJbP%96L#jGX zGr+XcruNC}989nlweOXz(Gt#J&P7~HR)Ip+AC2m_L_o%-29Ib`d;7c9Jxe5@1+0k- zR5bkX#L!}DWHcrkz!d)DdX2%>#duthiYZ~xN}oF5H-ryLkp&c|G*DV}Qt-`o^>cyq zZv_$%>T(wx;aAN6C-cewq^Tt~GT(L#QZSc=z5MV)P6>)R(5JT#{_mOJBSyH`Q?L|y zvhFb`gua%Nn%Y;08a(NmAZK$%GlIQoeTXQG8QWnYo?DemJU+qIb|uLvloYWi9*8*T zoxvWPsZYPAy{6CD9a%c531)6UbyoxmV9WN(g*Kx;9Yd}p3uZ=%lkaP3Qb;;()GwgY zWGoIc`rEb8=w73jG$r^|$$98O*}pm;iHp>#A=fixwd-n&4XzPIQ)=g}nOqD# zZkb!ykdw=7dqvK)n%Y;-)^oV>|4eZ_>gUAFddVoBMMv={A&*6%w#>N_hV4_{M7rGI zEf|tU09_N)cmrziN(QIut8dt?#FIWjxyK!=mVJz^C|9EPU>pB(b97D}_H8x#hz%{| z!XMnZBI75r{w@Q}akESV8GxqnYpp7~PRc!ZMDMJ4{+Fe4=-~HwOf!#ke zekpCheWq<6VjGQ&fkQPNL1s}}#q~}|ors}dv0yy6NtadM zt6&^CexkD3rfV#~XX~AMt%Su=R%uLnRl9RIq$&P!mW_fp0PFdg)(?-$b7>YZaDq~}FyJ>f%w;Q+H z+dj4>s<8yP5$aJ1jHvGDJsNKxxP2@Ma#!M^?@$k)kJNs$)+82QQXe%Rn$zRHPV9p~ zw@JX`cvyD!W%j{b*eLD#7)_@uOxnx^V0GT*b>CL3Z}n3EV$0&!pHxPaEM~3mI%8?; z{_h+87xj6vW~uq)>cS0r$>jwqoCi<69w2eNW(Aj4AvvA_tbwv2l-3Zc{)TRQn`Z_Iw0%{2CsQRWV&`U!?6 zNyN4~QNn@FO(Q9RN@;OUllWYulb(FB%ehR!BO@+2eZHyH=7$(-ZzKO#5it2{Bp|mxh z8t?2GmQ8y>CYpMAZuVtsh&sHfWqMeb2Uw2B!DEcT!-hS&iHA{F)^FA^^9oRBKE}6)-E% zK?gNe277$U#Kprmb&Q4_z(^mE0^_VFtKbXKKgP7qn#4YbzOz2iJu^o=vj2uV;9qB^zRE&Y_s-NYQAgB?kGAvMaKHq!=KXMb~#P!heuBU zpDtKrCtJp8_CA?)U+-glrGxS9-o*>EP@A@YCnm;XoeR~;GZ^_T%=`w1z6?|U1jZWv zz`ql7!P+O0csgIdlBHkA&2MJp3-eI2U2Vj(cc*m=OhT_m^G6j)p3 z?FVV9b^p1iu0u!AaG*Qhgb}Z_Vt37+#H5B|0JH9yF;CMWIBUGb)C%wr#+qjH$hg^X zU;5}Y;%SHS7V#;PDLl*^KX`|I!aE_c6h-EjfB`obm>Pv0Dd#aM{Q`$t!X`lQ;trj| z>!heK=N39E)*>n$oZ4Yj7rS6!pgK#sfN~@JG}Qq_mG6?2b|Q;TenY<)+-s1WYY~!@ zP3drgT~l-7*E)P)VCqNdA55n19kSyX&42vefBnwslf;eGC?JvCDFMsvo)8! z2E_nl{cIc=xCcKCrFLMp=lGiSo_ece`<`R#(Cw-*$+cQmeJE9HLHb%*o0_D9Zgbc{ zPjjcmW?@L|3yIxWaJP5L3{6n&-|2yhd}tq9^rp~!MJMjfHN1<5#w)H? zbI@4dP4#0NqjFL!Z7TXGup`QviXOOb+f8<1BYzqxr5i(C5w%&pgSRz*t#4~`BZ-x* z=t?zRICSm-j<6ABI6E@2gC!X(xjH|SZog182Z@!71;cBBOcW7c3*+iy!1n24BU*31 zFg4Q-UaZdOrm;yJU4bkru;n*GAy4qsfblDyWWfurz^ziCc*c(vs;AnGEoxwvLjHf3JV zJu(N*sr8I2Y!0L@^(;kZ!?fjIeZ9;C&_$kcwaBb)OT9Kz+ybZzJw5eCr7o%OBU}5a z<`O=pLa3YMgWq4jdw2PIH89QyLlmYkto;*k`E<4gw$YD&U>-#5q+dHO3${d0#XMrw z87kB_e%TcYD^#fm+Y6(dRYeo-7H9;8;WSy^uzV4qjd>>c_%QHY14=X-ECI(rbL4Ty9ow2m`FNgSHr}{xXlA*aLNqc3 z3U6UgHpz>Q8Tmc$s_DhVnhpjU6$XXA z36Ywi|9S_Lq)}esrLLDj`nEx;50qa7>$?W)98gyf4KugI^l+i?PjMnnwLXyfZkb5x)=v4fbt5KVPVDm-{*)74e&(g0*#{?sehc zQ_F|ReH|S1+pg@8BseWlIH6!9cnVdH*L2lS!i^6K`Cu^kC`x^C6Z~eprAdwTdvsJ& zeAg60@34=Ofm1lB%Nh8;T9{4=w${iK5EaSi0%aiz6v3ua$nQ^ zqKsW?oM5!{Q+>VIh*fn{^i@<=^$|3)P|6|V?Y)0a5!&y86m{vilg9rUFN5@Ku&m2< zIFeU16da459D0#XLI>q4;e+BPIGLE$U@}wBiMPW(Py(t>Fi{skwAa3_^0mZQVDW-p zJ(klR_z+V{U~Ie;1vJMUF>DA`5(MT?B&ArX04}nE7b;ZVR8x%)MSkGv%R$gRr7#SW z4ECb**v;Z?q>(P3faYj{n>Qb&?62%?*Pasr+NfV*%tSr52rehPZ)T%0GfJR9CtXmk zPm1q3dIYsgP}}fLr=ii)>zRfwx@S$kuU!rFB|}_wrrpQijW3?|E?rnRr?h3|1g&Nt z77568$<{!1sqfIJKnWmGqBKDUue7(n$6zy5zzzceb%rXNtCTX8`=Z~-pj#=rE_4l( zihP|+Mx9dR#cZPKzfe?EtBhsUYA$H`QVYh_0-mUuL86r8ATA}E*b$PW^dWYwL{AU5 zo)1T*k;naeMk)=z2W-H;SM)smFHHZB7lDL5UMhL4IFW=4@cStDsMe&``_p6*-~vBN zzTmCNInOfD+*ZYC!K8lE+a;b-%*^aTWE;K}=uhpH+{2mWC%UgVQ8c_zza6i%_k}7} zT0XH2e<~F2s%S3=Q?%H4Ggk|`6g;MF^1`1?u5wweCzC0B*uA3hf#I)qqqUGyh5G?q zWU+4Hw+q=JrNOVz_24nu`kxNYPmaS6CujQy;rY)ezv9(l_oZRIv=hmop(FJwMz!=L z<$@QatMBVO#B*Lyf}P^hX!H2|9(A*$UX7<;ZQc%%HS#_?vro!|E;27vYM-C? z-BU*Mu`m+BdC75XU@LiSzu*s+qZ&IdM1;d{ML9hA-oF4)O9KQH000080Cc*PT!@p{ zmx>?&0Ii__02KfL0BvP+Z*F3BX>4RKZE#_7b7gWaaCzN5{a4#alE3p;XvoX69fTK> z%uI$iWRDQC!)*e&K<4(&c=Uwb1|7EKNOFM9aDV$%_4lWcfy`vjFTqlOR99D3S65ee zmmft(?_d98{cScPc}3Ru$0V<_Nk+=8XlI^|&dK`I{>I9qXt$VOm)Y5Q9X;LHe7+8U zevFRKN%W3XMIMdGXEH73GpHQZB%Q6SOv+*wCCOw_FG`XmQ8t?wWgVq?Uesxw6?w&q zjMF+DP1C9(l_(>V;s_9#j#qekNyO8r7?V*Y-U|6tU(d7rEJ~~Bm}AhNA%4^BQ~;;= z?p=+@9FgFKMCNQ-oUN>6ljyjA{9o_)lHFhScK^PA@VBj%2tKqdYa$_6HP8#YA?m)( zYEq`t6;-sKR<+38sp?;|Dyxf<6?m0aZGTmldFx5&dT1=?hf?*XzxEh?j7vH0}$ZtUh-iNP%TM+RLthtlyu8Z zr$f8ajZRKJ4tCbxr0bK7^`C}cUfe+Hqv*x@I6KSg=p2w_C{?ul?@)fBmw(R6KW`|1 zrI&xo%0F!=KiF9Rark93euhQq=TUSxs?(`c^5Epl;J2IM+KE>3W1gXeMWgeyOh-Va zDmuN6@^nU211Bdyu}NOmpNFE_5zuu?)@3cDtsamoM*4j`*xx;Ty$4X><=4FruMUs) zfVE>Xfl-9bCbP62opTTEO*k`a|dnwU-py8!9cv>08WWDY?v z4vL(xqS%on$?~jDl5Rz&lNdC@6;ubrQPy&zJ?6z$l;w2{y_oW6+DQb*ddW!prYNCj zIIu}sg22P5uF^9C3Zj@!i%SrCU=WT11R7mt^*Mc`h0Q`~G)jSTQC&pUd2y+VAqtCG z-j}VyfFfnL*O#3^?a-$*#8$f4E7l8+ey^wMLcja0gFqbiU}n-9kVn4-FDOYZhM2Ft zEtkj=u--uIq$(~rS&A#(EWsrwQ*q7BtLn6@lLpADz%4LBt#~DcD#%fqN2df;BS;OZ z#4L~M%Obi=ud8T1f+`Uxd1U=5Qk=B|a}(%J_z&^{MVL~BG0$0yxoI@cCKFQPGzYLa zkZVyxWnz`8zasI1ffU4gPgRUMK2APjtzH zA_*pS*^ph=^Wbf>*V6_*nO0;uo?1fl?Qzww9es5zj^doqDJdPiaMbXvhab!x=W*UR>h^CZELF^OSPpaf)8dv)C zUCjaX_4K+X)jZA7C^=rtr({5phCf4^|2ds5palaP-8>h+Ex974$6#TEM@x#Ef=}XT25U{=IZDSCh=YzosDmF8%+fQ25|8_e3K)&?N6{vzs9#S6m_@auJieqge_y}`}K?Ty}wJ#=C5 z!B8|aF39y|QI2u^e(BWZf&k3U1gV4%*#!R*{)Y0_aZM`u>A)PsYQThqUqy+3VR=r0 z!t@Lrp@8zSd}{!gArU*HBCoTYA$AItE;=`67q~;f=m`^LyJVIp3zQca=`|GVyxTiE zJV-u#JUD;_X|jKiy#H|c?|Zw)$?@LN@lgk>e>Ko2i9zLKtL{FRs|`k*eZQmkLHb;1_L2(F3U0Eq{svQiA8fAwG&~tU@z9AB(*$MJh7K!xB<+*# zqyCfLUqLZ6k=Re7mIQ_hsIzSZpj}U!ftFhEVm@6|po_D!-0AAtwvRBM7U|S3y6r2O zdy9VOD>`)q_-9|SGpE=~v)Is5loj>3BS0#t%^J{Jr)4_2Ahn%2r1b)sUuezIqI591q1AjjtC%xBoqk#rHL){e%tSFt?VLWX zRyZiEVLD2Lov}_Uq?N7WJ5MkJ=UY4DF$G1+5tU&x?=P4)siq!yTMTDVes<0_<_JkO zvwo(ObDDXH$!AXTUorX90`w`U;#pc=Xa#PR5qL&w>c(Nlh-HJCo;LjGHW^OL1FeQk z>`$_M%7{!R|)Ibk;*7BQ)!~UB%C=p!V`vpLum9Wn%0` z&szm2$-)m!5)gpS3hw9iL%|Q@KNJK5rlA-$)SO(`l_5TlP>ds{e03)|dN!E3oaPY` z#xf;gmIK-unn0+fy--EJv>{fEhTfudQ52d21{9FLA`)Z`M@We9e7Pm&g)kS?P+HSR zoc^IJJ^`?74{*H|Ksg76L7D@*C7#QIZHX3q)T;+;D778ek3K>rK3G_xK1>f(c*Pu~%@tyKNEe6xA#0$GhD{h_J|_f8D#|o! zUGafdm5{!SHX<0;rY!J8jrNcd#tuJhDCWi z)66txH?5xJtG(#E?Pz^7OuSij22AU&9*|2q$E)2|N)Of^m|8V~M3}V~Kn+-i!5n^G z5^EgxqSf1ovx<|KT=8-6RfJwVl8*a;@vRW(j+DtuzN*$MSqj0+)$oLENRPEG z2?T1=E~r)FdvF>*Vy33wgQxoV6bxre`^~NOO?M(Tg~hX+_INP@0%T(HT*t(P!Ek!E zwf-z%9N_+o0H*l{gH{@vy0lUc^jw3?DlM$lSYJXVqq!?;4uGUs`&pQ-d|qG<4nJDA zO$@Cj1&{8wiwH+Oj#*{i2aMlqJnh4`6sXB9O1;+6A}?XMp5@s;2{&7#FQ#ewU3t@LBDdEo#*T{E`RC)1VR*~#hp}`7 z%F;3W<@thx6c3aKJ5=c`Lut&3i!WxQbFEDKNw~88&h#1pYJ~U+KI3)JW z0r3|bjt6Cpsm385{5*ZABe*g0ACX+=LUpLn|a-ZsdM`eLZJR9z4l|rIJKx9v~RVX$t-9 z@|I!-%5q#x7CEk@VVL{M8bxuFDxFSKSQB)yn#To#$qXf}*Yi2DPGg8TJcX)fi|-S< z9T)o>IwyhiW}yJT&7s?+Ej1lwutD@0(xRfVQM|~jbV3rU1&+&w+%UG<6nak_G}F98 zA*G=cgdL01#;<*5ix%z+P0Zf-raOC)rj9A0!mzL<*X*&8MUM(VyJ*Ub%}cXHRwaCY zOl%XeLY5E&`x($z3|E-SS&!I)rVTIl*tT(6UQ=F#cJbpVz$J5g9WxsC<(HZmjJ|u% z6nqtK>jX4;tIQZyMkL6Sdqn|Odrs+Sl68Qa*#hf1&iK5_{@7Pq6KGbr1s@OSMwt&9 z5?(N^OfM5Pyzb5pYsd-Nun*JRl@}7tCVq$l(7&!$2uwl11~=5(a<2t-kLc>5fmdy* zOVxFi$b|_z=OB{#DupMu=0wa-8OuWx6!qK2h<)NfM=R17Pjp+I5lugQA}VpDBYou; zt`K6aKAG{u>*z|RZZsP^&x~X^j#>S#Cd)j9&bOg$o#2`GeziF5>gTd!t1I%b%Pv3p z;1Lwh;D3cK_jW~(u4kvk^r3XcPI&Q%AXNp0ZBvzL zkuO)};u3J9RbFQ!g_fF{zUlcz(iKmJ49z@7KW_$7$&CYbkyu!D%{@%>>uy&=?keW>drW5o zM4^zkqbv5G_7<05KWLy#q@C=*CX0XKuv^spn(un28B zfbfGfy8y0OWb4EFX$F#IQV%cCm4?(@NXFR9(+kBQik7oJ<&)xPdzR#wd*ms}i)3_8 zMi)kRm6pC;v|5lC#}yq_aw-S&&zZ{Q`2#r|dL{@yG}{5;qN*Td`KTyMGO80gh7}m| z)UbYBL>uh-gamEy`6!5nR3}`SthoxN<)mMx*WMXl>>_VzW`-~YV7k?<1!m^@$_L$h zp2D#Qa_j}$G!YBPaxRt$d^)BhMY)fadu_Y4t4fcV%A&7poAz;go{gSC{^(5eIKkkT zW%#O^;;|Lq(AM#@4ISXEdFB)jGR!U+;FevikyTh&@rl0O&LpFf#vxVRWe?^dZ}7V< zV|X3~V{JC6*~LysE_^iU{su;CIUjB&*M7 zq|QdSkb^ahr{N;#a5t4$6kpkL~>Eo@#J~+lL3+XN^ z*ARJZ~JmPl(`-!2>CbpWf_ zM#**(*~kP|2v(^kS)gtmAqez^O96fMFAo5`Z*_pl{>6dOUEC|s-_4>x04M-|&18PS zz&+K06hTpguePfWRs+9U3D=uNKEeseD_(e*Ao*it#%bznh=XiIGFYW>!B7cd=}_;E zgveJ%N+e*MsKxUi&Fvj}2P(Kn^EoYDcHi5qw4pwLEh#`sKFS2nM)@Axl`jP|#N$I) zo$sfM%A&FPx~w_*hTV?dou-S*f2xJwpH6gI25m>^D|S_xkBlP^zXR6_8|rPgW-WTs zWy>_9X@rU=zQ$KAfLC+Xv%GlVGfW}yoE+3xO{4&z$WZBR5*(rACupy0EK zrkW2Z!FD~3X$W|MZVdq={*vV{6hCdjTqp7NsKrLi^~IVM%T z3!QD?i-_8BKdr(!;RP1--gpWxpDJ9Zr6ul4ChAGcHv__g0JA%jys^u@4ik0pr8rYs*9n zmg^mZQu?bUU!tEVVB)#8siJz1>Q%n9GdkYm4ea`yRCuMwD?|2bHf$B=Io=U6U2Ux^ zyJtXyTHRS*TP-iQww~&Kld1HUaHtREYY8rqX)Dz4mJ@sHPg^9Lb-ZWMLLr*9y)`Jz zLoyFAeoY)%plv9od>{0flkuvyL8jMCw)Vc~WB^929=1^+yTYAZW$ z-(ny%zz54u%Hp3GRlDx`?!+4R92@UG!gQ!Qmb}|}&%y%FF%tEFo+;A$jfMvcfx~0@ zY(=#HEGd_1-^sLTjqg9pS3+N9_8HB7DPL*!OPQU~_&QlGTVOQYl27r<4G`w_>!Xja zytrF**6^p1YPK+J4Tnu5)NE1GBhYsr-@e}eby=W1X3Z9|jKie?Znh{lSppAUvqgD} zO+AV}kkO*7vd;v@X@wB*GJJ(0;EIx+80%E*R2oy2(=A0%;x|+=2tCFYrJ-yvD_cTF+3g$C62}!9xdgiXT^8{ti+N(Mmaf4MZFi)%LbUn z(TqCK>D4LB`6-$UZB4M^=0-H1rs8P15xcroghBH{VcUR%{5-=I)mk)~VVA{j(JF6i z&$iRKh9&V#oJ^;1@NYLX%`VE4o-w6cW_T`?-h}Otf`;jX{~O|87r%NeGLXBE_c<#T zm1vej^){7Us$~mpY^ZJS$--x(uC8ZYdj*guH8aQDBf=x-cTMQ(RU8O}$Aq1KV39}V zrs(ky*dY#g@8s9;_C%fbh6LkyIz>Rp_dg44a1z6vf zqX6J%8h|m^L;M6^ZkULilJd--=LqC&>~mr->7|eyrbV)Q$6IXF>a91&G4V$yYTs>s2mGim=KHlcYSKhPXV@7C z>(|ho3>wT=Ph?kd*UUt5{b;Z`#BkEytc{^P%5^D{k;|F`l`)m0m-lo-zl5q^y{%Ma zGAAOgkA=QXd`ER?7#gSEd76D6lH!x#nRC9X&c>B;n}B*at>`>-L~4E;%CZC42H$Y# z(n*UUrFBH_Bp(>G&E>l0iPPKZXg89s=73aNG7F~og9MvY^hY$VwQ6fa%NRX*MmX zd8r1u;T}?C5sP8Iavrk{uedui?3n;SD_YUiN_f?h+V1q?W;`Q!sVLKH&}=>NQbx?~~Ay{FW^$EZ@L% z$mQ;}vL^K-nEV>0l&z`Fsef%Q?cB;Cuhrvx{!BLBn}tR=R*Q66gl@i|XiM4y0E)qR z_%cM`qk{0I>?a}~p2h~aPqT!tMeZty?t;pg;_##UP5ts}=yeui*DOHO?u)A7fo(v< zvph5y8jv*2!!N{)lUH+*$68l(k9g0XJ?I?-HE}#`J#jqKx}+_cgg9ding`cL=Fda0 zzK8C6(mr~}#6AzSieVV(zS!4QFgn%rKC@dJuBMRWy^UATTJ!38Gq3R14Zd||p_A;- zE7UD`kLJWiMf& zHpCDEC7BhUi5@Es44wLtketoOIj*RkMqo8C7xR)jHXv|Rhr~sK+_XwUHyXr;dj4<` zZ+rQiroApdYoa%}phuPIx~bHGBQexGJ}#1~vWny+(bDf0@N5OvAG@~gsF3ZtD776G za*wCYSnz9(?^|n*9~?!GR+6m|JQ_u9J~>L<)+o!+uR*KWxEspWxJwsD3cDt)@}EIF!{@z@@M@JW4MNkJ5|QBjP7*L}<>t&~A-QDgLtp_Ro^B!w-#g(i*dt`0U;R zYlek{(6ec};g*#@Y!ilAwm_)aIDQDviMaMcH-(kgWImr}?8mg&jxhe()VJe83F#pH z4v)|{$ai*Oh8^Qkkj{!EJ;Tmfo&ctVMXpImt&Y3ic8090WSZLb^^Wb>C&(O15=RD1 z$rryXanDxiojqTpe$D$+)5!id2C($TD8KlhKZH3o-6L~MW{EAZuFEgPaP4;HAExl+ zFLE`|t0h`@n6G5?9d(^nj(YyyNJ#oiCpHy%;F7zM@Pb^k=!KGyDy0QE*)Nqf(6SA3 zcOaw)hr`3j#9BXiP@1Oe+UAbZhPkD*(WEC@YX|z1oEE2Qc?-?aZJ~Z@!DQp84%=Pq zmp_B;wfDNVZ7_3OX(5Q>7GVQ0{_~D40je0c4M5pyPo2SR30p;YHDHU_pwc6u%fRj1 z!Xiz()F9+d8*NhT^c%Cc*%5Y}!LSR{<{jT&aHsN=hpjXZ z1GQ2C?s_im`vT0x4ne%9jAZm!g){zAq6cS<*QvKdc$@Ct9rCXp{g&@xKD|aE*CF_{j?$AgIg116x@ z;_>H#RCVt?mwV>i>NnvHw(W0FGztR;U(Fx+T zA; z#oFrb84VsgE=Z;S4q!By7HQ4T;oCpI8~ixpuXjQX1tZlnEc}Qv2GW2ga=0$zQE`xK zXB}y(-tnv`(tG_YOfL8;M6AS>pYHA}-i9S*>vgnq;@QBqw6W#)9XycLz_M6NWAnt3 zE}vl!QVWNVZVu~XpFKO8f+g#baHS{ac5NYpTxovQ`>nWH^HQ@lsXCJr(l4Ppct1>n zYar2QhmXn)VD&=x2uMQn$O`OWr?jn{s3S(?Xc0={F8wjcg-gDM5o>_(4q7d2#UQv$ zG%-=PDD>d?LDBY3)(qUWcJ{i_|J!(QS7?VW}d4+at(Ot&65HUfj( zL2rhJlOymdriuy>BLc$kBVs(@3-?v&ab5I~-V7gF%(rdfhx{OD0OX%NT>ZfED_p6w7hd!P5 zdL|XEQ6z(#OoiCWmH05c`%OG9O%ccC&Lq5rLbr_%O?qUc9Ey{W`9HvADB@(;M0R4J zXl`p2XydDCtox`PGZu*UGe^tK3oZ#%^c7b>8G%(a`kFWD?zLAaZxVX1H9okAghrC9 zinyASTd5PDpwldK!-p!}#tk3VCk`;YU%{qc8!bpS@G|V(HpmIMw__-pYOp2QuXwfH zme7CoD>U)gZO{`#Z5xn36m}bQb_*@blLcOZM+s*)_4Ss8+}n*CA6teVpe`D>nCn%OKdjw!m|dYxgLDhCf!Fo4!^vw-^mMXNlfeUBJ(Nipv168I z_)|~Dd1U&7PuS~IU}d_%Uz~vMkBAXmBbpWTd#uG+T#Ca>aJHGF#<=-EP)h>@6aWAK z2mo}tlw4-N)}#~}003Q7000yK003=eb8l{9b!lv5FKu&WbaikpaCyaCdvoKqcK_d> z0(adRQX84xIBnjqCkmjie&k)tnT;&^=tH#_52P15`4+p zOzyp!WGxZE!NI|Khkq}p8ODpGA-rFyQNI4IErO)E?(wAxRxhp-ixDS@hZ!A zMZ8*9;_SuO|9nFK{8?PDrFbvPEEP+6FOw|a&|p!?VAC1!fB#Ek&c2~BXa6MLrIk#m zvB=fPzO9mM zF&Cc*jk(CmxyX~Cin3xe7v;LH;)MS0=y4@Cc@!r!0K*Kx@UqD8R0O5S)mMd29#rcj zUKnI9>8BY}?eaKXVZ^mY-ZR}6b(}2cBHS#KIHjq=tdN9hFc&htkBck?h2|nAA{2Qc z>EF57fPyp?eWT|^Mt_rRr2#KxE>qf*FqWm6}9nZ}UkraepiZBV4Nq_Wpo$S_NzctzaWYuUzm|52F8pa>yIy#{8L zWlVBbRz>r)%<3YPgU5NWfMC2wRFaIz zrC96~Pk7>8Bz9RX!gY|Yq{s@A+=OT=VsK?8wpr>B7fY{MJ$?%e|Z1q>c*nItD|=koMuDI-Ahn~7XjLbM@9A9*iz z(?H`0m*=y3WZ-O1kh~o`BfSyy1-g zhj0z*q`J7do$eEaSlERV7Fk*Ty_Q5PATC&7NsPzuTf@CG7qk+h36viFFsL+7CUMa{E{v7%^n<-5 z(+caPlu2aGR#p(rs;G&QSXp)9=$=mzqv7GJpD!;*HzaU-Onx0jNHanj9xs*|zC@qxAt#HIw zlc4$I7_jSrgk>R>_988*m6L|dv*Nerd2t^kwLAbkXQd;Z@d?K(KH?gVUyC+^1}Id3o)3dJ%bxZWZ&o`<#e&6zRYuF z?O-i^pG-yN`!2N9-0b?f<(~CSBtGcdIG-10P}9t?JcXA}h|SdiUL}6dXbe9gnTZh| z;9=>`8UWZaZ+O5R4Tne9#gPT zcws#vSdoGDIxq|-7vko&)4<|kLL%>4!m|#F-D@LZ?hNtG@_fL!F!>mh1{(?Q>BcxW zD_QyU-Nz4h5#8SQ+={Q*o%8UIo0T3yEbmhmr@fw?V99%9eb0;dUT-WJ-RBe>#LjFs zL=vB>*o`+>bn%qC;JPYO^sx7?SsgL^Y~HMOHX8*dIm#07C&)2<3vqo@6j?Dn^|9#j zC-D$@y~`bR5F+oT;+uvX#4P0=XaVH6ii1QeN!lMW2DG8o&YK*Tlh_^&T3bIgSnl1+ zMxtj!Ad_@I7O&aS*UmrWYrD?Czl9`Xf2zxh?Y@>hOv_ey0$9YcAA9iV4j`WRk-iq& zxP)*fiLwJE8Au0kFQXDCU~XfYKMd-U6+sb{>(P#ofdms16DQ=+6Tm*RPw#&M)wYlM zlW|VN2O3NdjZ4g$%-H(E^tTPP?mIWxg91J#XF#ejU1r)>hYH_gF}#ZdcMt!KS$86|Awd>*ppqmp);mIJG1>kGzZQbkxU!W+hp9R#>n z@-PGe{ZZ%$FK9QMxRP_E@^CEA{;F7>9fqZ4#Y$pX79&l+^^bahi#X3-LlpIG!x!JwKVT z1z`^ZOp3TnvmFi^+TX;iv%azc5xR3CRi-58LM?MB{^O#5rSu}u>ncI4bOXJB$rj3^ z0zp0TiqoiY4GY>z1Ta1IX|pzAJEqvwN(WkWs%wAO_OQyg8O0v_QSI@&*3;PHNq=YF#ssau&{f?W)@2mabmJ?_ zyL7x&Tq)2F@v*aY;75cRk|q~UT}3BpDJ^##uPD`uu zAeH-V-z91QKO#4wwF1Y7IG3fkYUpC=i65OYduw8wsjz0+J)iK*wSWz&Z5_wO_Z;;0 zd|sPjKol^#G)bzYLHL^?G;=RA}R8 z8eXxJr^cb_bQq?qG_8=Sd)+2tbt0jGw)8%xAJd`tsXoqsz<3mOiqkpcVVi8N%0H%Y z`YBLemQKebLN25^<%5`}GL&T*kWtw))lW3bGu}8_SyktvldXRS%TC5NH1!1Zvz=uB zBHl$t%LZ{muu735ms?hIURrNbQ1Y1quSdZ*DJj;k!u6h6R8HGi*!Ga1i4LNg_%UwMphfiaZj{dS$-Vo0L zq!*UQm{@*JS4^5I+LPo&76V*nQax(TYjeh+1npyLsX%8C1COX3?s6=y zq}25T-;$e&1H@7|hW#9N10fgC%oKBxa?LB2)naANi7#|;;A~tN~q_aL%q&QN2hto{OrAb`R<3qz)-jX{m2;|rOSz~Fc4fI zq79VMrg1q4Oa#=7I>H=v&Ux8>BU41gMx<;ZvfM!;X?RD0SWRl$=vO0)n*8UM5Ace< zyrwS>mvMEqGD+WS61tnFBuY7wbL6f4vMEdAj_-pU^-#*)?3XOvj`;4fDBy5m><{#p zQ)=CVo4YjIruIB&<_w`K#6V6kTYQ37*+a-9vTShHfY^KS$>RXoowZz@(}E~UbOpz@ zZQHhO+qP}no-?*>+qP}nxp_<;`X_qVs>%lpP>U@1vR!EKz;r6@&k*3NHUO8d&#Er? zd%^+F0*P^;IPqV*=hwE)kNQ02ZFj^XW6j&an#b|et~#k`O=6*UL3(Yv)5;{xm?_@7 z1c)K<#W~TxJec^R=^+2vmMMv2??YJ3uR>=i@yQTxq@;*brgpxVlW2$OLMv;*(M(x8 z90ecw&ujE1rAU|*wXF9nH{W$Hyi}7H_Yl8df|5yIygxvvy}(H z6t$G@0+_Ou30~-e&)*OK`Ou#G?G^Ma-8e!cJk#bi9fhb`2iL4=h5S%4WE~CPdj{PI z$X)C@=b)Ui+{V8@>;=#7iYP4D(ko#y@wH!R)&6KHdL~53 z4sBPd_QbV0Sc>n){G`~!X}~h@5&N}WY9(KU>g?>Zn1dJkU-%8HQ1RoY0h*oP)tE9k z>OvuvvNWMa!)L+s8!W)jkg*%K=4=C=Q;g{H)z>x+tlbTT=>Qo2j5Q)CHpj**CnU0Y zUzf(kqT1d|FN$Mffw-u{H_VSv{gA^fu^3|x*cSi?Wa=I=YT`bGp{Ow)*%89)-~g?8 zurp8ak?QvtG&q@%m=J{PnhJEjh8FOa*y1`Dd6SfJdPm%H+;0c-xXyTCIFdsLDE=3A z=VeDk*D2(COnzv4!`C?q>_6*c7bV>SMRE{6`nmWe3S~Kfiau;l?!&bfC>9;D;7+hy zKg%x)aNCP2FUQEr2`46N=AO(ct<=4jwh0mz7qvwaRu$f|NyWGAH~o@zr~TAn_eRyg z(b*um$l2A?Vsj%E*fbr{PSK89F0Nw?xkJNMdXefZZ9I_dBTEOOSX+BhZV4V(L1v`pQ61&RYrZ)=)v>O!RiPE7|93*FJV z&s;PG#jFDv(M%HA{)i&fa(Fm<_@ySAJ%mJrR9LF)6_G_^eSW7G=u}JB4}kZPAE3Tp z;uKGatkLrNj>+Gj$Jqy^1EJ^nDBd;?F|Y}cHl>@X`VPS zlB^D(HaSYeVp?OkH{543KZIr$P)9?NE2v~8!&3q);8@5E2K{Box9>PdL{R#wqJhLo z8a_9*3tyv}WhBkIc%=HXn?o1)B2NA9aT99FG9 zKY@BDcNyPP-_lWls)oAuZS)g1{{pPDtIDpI_gAS!a|A=aW&$SL5M#d&ogjn;@T~WV zB-B5-HX+WsV^dd~UTnGO(n%nZnrA?}3=$Ld70XO>k9;)gvZDaFt^ev^ccta7m<}DD z66%=Ec|q#fu`Nlt5d*im?EVIm4cEedw+PC+;#1wRR3^z~!6|>^uq==!?$bYNbL8z3 zuPl@}m{qno;SF0;W+9jfP?oOTRp|@F-H?%8J0XquTt;o1aP&HcRdYgOf?UK>-;ycF z2I9_Z7-PmyypaZy*Q};Ny?_P1>+&ljKcfu<-|3=a&<-Nq*Y!3v%`lh6`HmYSK4@V< z3@g_K{c~gkx2bp%3 z*OqcXPM-B=e;=~R&*I;+d`1dypF`g43pY3qbkE4MZ8V7u2B6u*nz>oib*R)k#?7*K z-JR4si9tzu((#@$e;+aNe;4TVs;R7L&B_!sCQnSjy`K+P|-g za~&d}t2Bg$3K}H49cC}8M)x?`0XleMG!p+M)HuE@Z4?z~`=|Wt&TL`twe`TMEuhVf zSvI_Nu{B}QBMgx}G?-Pj$Bh)DvtYGsma|OpI|$U_%YIO;X`fCO80pt}oge(LHZinV zLyWo1%6q`Z!ep$D(s;O2AAE2CV@)Bh>fT=dsYpa#V_`z6oHwFWo5wxNFdU~}a%Y1O z$$f088tB*alT>Gn5ktKRJW#2xsS238K?XRf$&o+#7Kef*a6+-BMALTW1saa`g*cYX zSICYE6#QL)s##w5Ji}!o77^PhzPzjrh0EkXCMGaNH5=0UxtZ z&yNp&(V|t<@Q@15#_KVNs{>GIs_CcU9qEZJG>+!WM{e=T?QuqLn!Qeh(v=~IhrT}@*IfZ5g|7N~_PsP_+A5Zjlglc|u_oGsxpNNsp2kv`rjN%%gK$IS>Q^v{ zwe452CqFqdXcSBWk*ETrtSlcSM@EN`vdRlnd5)$c6;GKirIOWBs4k2y=9Kclv(o(5 zb2R5+Y26~rDJKnCCMp~8g7efMCloK*snfLW_~kgWb3W_PgZ<*5(g#wv%PXp|L8Z?x zApU6sI}l%mo$kE>s8kNwzk_QhL2|~Xr{iT^cRzOn9`3;s{oAI^>j5iz_tF}W3g*|44*0+03CiT8J z55a3xr&p)ug(i*^8;(H2wMu{I+`d?N2lSN7A`TWI$wIRINw$8zKn&R%$FgSiHF`uH`De^cn4fEuj9qnC z-m~_dgN|8Om<3nCa*>FT=V-nzSV~IH!hM{O88g0*#s2%;sLmyGGphE7FJu%pQk!u= z(f6W=4(V91`!Sw9!ut|{oA8$VSrYWhYEOt*pdR+e>m6M~F9jsFeg zec{gr*vBPeXD>ge@520Qwr9BhV>7_TtgRG6aBjYz&{SOZ)R*9vpl%gue-sbigT*C5 zyycbx&wspChH7UlWu2R*uSjYeCz|4$Wsd*WkJmLU%G5Y%!&hEW*#x^}D&OL}Fxg?%Pxy*l$D6;%;c(Os`=6>=CDg`LIp+R{D#YclpH1p*my6&K88LFdJq z@q->G%BWhxOZ5h>QnjGg~AI4^6WYr@mv`5)l_ zy`rp`H=msTHv#<$1^~eNe-lt=S0e`}dn;387w7+ODJ#4`?pth0eP49~NmoTF5-v?U zTQ{F_Ju{@UZ1!6$^lt8Vvo8%P5Rx_&N+;pCYjb~JGvEL~Boq^pom)%RxRE4a!I=XF zy#RDmM#O~{8_TkkMH0o?wu-AnvrmO_SIy&9MMb21$-}PQ7i-yt<8pgbqRQx`?AxO+T+(Ns4ea+zE`Cj+ z{{V#@?dV2Mm}X!e`--(cC-Q}0O_EWmT`6m=d|y=c(nVWRp-HH}6HZ!F?$voa5>*qm zGrqTr8{^b0c@h03ua@4RJ4V8gA4=CJc`6S}aw6;-5?$}OW|9v(qXN!Hn5fuYDNBO< zbw{;7i?}g*LPs}JX~+-n95#X;ue0q7pZ@%uz1TRBfbkCvn??0RWiw?(nm`>B5Zw?6 zWyy>{&(oQb86&3O&na}Ho)8Me=KA=2f7jIO{+xv7A-Tz1N%q#5>J%>u5 z?Ny3l6+J`}%BixP2$5NO5>2rL)_n}3Nnh`%Go6}J^C$xad z$s$mi67pe1E}|zpytq>hmtqV%bNoR13(eFSW$97C4oCw&N3ErZj;&r3Wm<$ylTF(Z zaotd9ky&nVJ~0dA%UW~}sYuX^BcWGM{BiMe0hCy5iq zIy6n;Oz}trGPji=Tx0}Zz>K|vD4(X<5R^uSWaT>$Iqz2uj`JX)TU3Q(qA}^EaH#0+ zhL582LNghKL@O_y)+G=Zr-|G{sY<26G&WI3DR_-7R3vRW5m`16Fj2%+ztea_^w&f0 zU={OWn2s9Z?w_iDK45n+WO2i93^-`Ip?_n{DBY4NB)AagcgLs5<{1kWD;PNpQbr$9 zUfr>)a$PWyB#|!GOglw7lW;Hz>z>ZCl0ABffh&tekDwObLW*F1Z>S=qQ5`b97vuFHvh!{326pVYc|4?JaA14*f+)tlkTBDXnBt#4kU*ymk(kdmtuaI0 zP&dPUx=(%%%hVwEZEzgN9F=5ZV&D~8MJ#lTRt4JeN(^d1uR1>yV_U3_Gx%U7kVUt^ z3_tUaR&dYX31WX?^8X+#I>0<9io1kaJB{>kkNqn&vsS#!Yz{&G=J%S8#p6FU!?S8{ zramccPvV|fQwi;rncItQC7a+nB;w4Qp8JvIm5$ac5o~kV0>o{sp0h|X5Y@nq{j48BLT&W!lAMF%|C&!OWulv2)T0(v(L}2W2 zG@?UyRF+(Vf{@Y|Gfq@9p_QnI1Hp!=7Z`2JPBjBtw3MWs_Aa6L4(FQ7Pcw zi%_jZZEBH5JEd2&xyZHiBu@DZvL}-Ib-ZYY1?CQCsNoE3iSah+uxTi#) zlye-n70Z_Sd`?yjpIDqSLBT;gRmcNrz{4;i=EU>*Cab)|jaB5ZH6X)v+@z+=wv9o9 zd^^|rW2*_t)adhO!e?dPyH*0tBeTp@-ot?re)D6UP;iy31>?%NKD4>OM8J-a{tT0) z+G2nc>ZE7^+U_dp8czM)9?eMLg-2(U&=NQxmm^uqFgi!g<$dZ#D+bn)B)EEfHm11n3 z6)@x+G9aEcpY~e#0CM{Shjkq`Bt=-Kw6g8XSKX=!rBEvHR@S5W*2ZB?B2NrnO_WB) z5RUFO)h*3=o}ZhwH;T!!*-x~HxyzKQ$%NQ0AzKE5?gLL+O*Cs?dz78eoJi}`rQAUZ zuvtJ0>OkfyemQ)!UBDw$zk#FXC<1z<#sPcTf`Sr*yw~>wW=|qq4a+@0E9nua%KA;a zx3Ii$1yR#sgsU%!!E8Z`X|M4TS-D|!JOjFljP{*@V5qM)U6U^_6kqNl6i56tW80G# z5-u>PUOMU#vwfH@7hlWR&Q~x|?PSP7lh&TP5An=Ui0l&%E+07V;s$Ckz zq?_1Oarc=L(z|xn0=mTbxCv(i4NcPx=@Hf=3fAW~+<}dWfAP;II?>PDbigNUytiy) ze$$$NNmEsC>Pk&1g=FGbWa<}Z`F{MQnRLt!V+#03GpzI@7GR~YSQ&6*NpP*zQk{7! zhyVzF{XZ-C@4b~hqAPw$1O>ns3&garT>cYicLc zEWFP0*I*oVWwR4&e|r>5{NWi$3l7~HL#XN@MCdU_y6&V;XFrTSr%K3gEg`I^O#}0? zR?T>z%!$RSeu=2EYrkh~037!0ZSWVPHf~3XWT?}{zPiS{=}6GyL;-zD1y}eSc8r5e z8Ozjij<5t%+brF%8B`&ILkF5)XZG&XaH|zz>yVIg7D;YX>5Sf(ZIVF(6 zJYq%xM;!e>z0M!NfiqE3ch~c`aL-2#3SsRn&{6LFdD!qgMFhc)erGQ45^-hJe)uq| z+O?z%5G`P1I#92069u%O{BX4HK53ZGf&z@-z@ohK0ENlwo|+<_;>%ja2-*ac52Te= zN=1#4p*2uQsZx?S5h!Ohcwueyw(E9?`3hSFXYi#9wAgAIIp=TB$NdcF%Oy7^IYms_ zHICX(UtAqGjmT^0K>7uOP8%ad51x3ZO^0K4~GH!*Wxttc84} zyZ&71d^|YD3$4?-Xsv${_+`o&fBZz2fOHV}Oh{)W+X@wfmdQsk-sH*nEpqElEg$YUgw}cDvL6eLCFYUl^<#ms8`GEcJH=Jk$wAo;2Zyb^lRFEG{ z@60PrS*jCMrW_X3&y+rkbT zxfWN4UKaljj)TMjY*6cBM6G0X1R%1Q@klzPGz{5R*_mBF)oyCxdav)l^bp^k6=2vsRftX+V8iemz~Y^ z#r5*}z7CRQH-cYZW)>*ygu6mJv4YdD-!{qHEqFzik|ra8^cdR$P7~EZpFzrwJp|;! zYd{DUnNz<6Comlg#=Y^Lw*+;gC9GkX8{ ziV`NG2>+AD0HqqN1?r|+1i`hZ(gB{&&pBl`0*-e4mV>iE)idHfb|MKIokVJgn=;WL zk#$}(C{==mv%O}?0?#hwuahF-llc8voDAM1tQIc()J_@-t;BeYB$7aRFKnTTTv%|A z4+we){bZl-&sggQkb`FNE5+ay2CszD8iA&+zU;>Y5Lk+gGq4)7YRD#^k9WLjK!@J_ zyYmb}yDmeLi$>&Ar37LE3Kw~6qsT+VaC=kAir)m-7y1fofGbIC!L5>j9wDWQA_>5R z^fg=t{>cEkQDfJ-kD#TkpIrx!PS@!EZw@K8JXyg8O=H(=i^seLLw`MykLBXA9X@Ds z9y|{R)3z=-=KUYv&PRxt>5oPliSR~TLX{4Z&9Ug{FFIK|T~DRD%I!k(%vz$+!;oYmov*v&#So)`z|@3 zd8@v)JXWr7`1Wl5>S7~4oXX^#O8(eGE_ia&PKy2-&Z05l6}6ENIanYJ-dnCj8Ll{J z66h*@#NQ7T(0x53k9b&z$X8+#4OR6-gY{B$Z7V@4Z~!}sOYh^3fyN&mZsaX{hYj-r z760oaqOi2F?Hjt(<2#|uu(9&b{sWTMKR zbH?_?LO3Wm-BKA-Ys7Bu8G2zZw*~%LV6bg%PI?L<(&^#{tlicag86Ph2IK@EA$Qpo zxGI~mncIb_4CD0tSoM1J-oI>X%u+0biEMw5jdz)qUT5VkD`O&S338~uGR-c!XrjYU zvp1%3*~;Ab-RaOdtipO5E}33|19iaVw3BU@^VlT5=Q#CQ$-2+BpJJ)|?nrhq#W8Zp zY(JUXRp|J;I=!${>B6zVEU;H8uHT4C_vH-tUt(kUc3$YKD^t$ZWzMDiz|D&{riNRy z%4G(;;Yp9C2V5ImlbSi7Q4VsR;RXZ~;gA#_b*vaUPDR3VtJOzgmk`$O?q5rNabs4z`$miR(3F+GV~sD298=K)YJ>B zKd_<~fN@I*RNNT6@89XX@84^4*jS?^HIvf(zjzf6u9h4}tqA|~iQ3%Z3kK+b(y8qJ z%3n{SpuZl|b@zYGGiT|&B-NI_w3LF8d|TZB1yQO2Aq>%V0q`0%SW(PQM@c~FLvTD+ z@YPyUGVX;iRW_idYciBf**20C{ix+u4w&Q&=!+v=a11DCEM+i?vSL=)G${Orvmi&G z`>nFer{gWlfOtaQ1R%yDc@D=SV$wp~bh}Mc-JidS9+JVdPSy1H^Ui~*@hJ3_8B81) z`BGte6jSxpLh#3{2XW4mm}MBk%zEqsaq1RC6nrHboPh<^G3QDbF4^#BX(>5zVly>P zvXRyOTrxJd{KenpPAwyS*4@2c=YX*aP_b5^mykoip^mI^jMTLc;M*G-g=!C%>tkGC zQ>290G9?Rcfi8he!By6mWR@)!R7ChCy1v!gYcH)_oP1#iHQAiE z!W^Z;Yu%DfA$@rEhJ$#25Al6phlH2&>Lre63%VVywq%RD2>DW{{@c;VP zE;DNJ`1uO(yVcakx_xl?;k*O_FnlpQ6odEge!{pxaC-njAogr=cDU8XT37Zn3En>p zstRHi8*3SA2gxH;xORTBT0?3cUVZKjq6)FBvb|vCcM8Opb39W3P-R1LLf$e*S zvurdO$wmUvl`0lcPAUF+Jo+I;-4Yn}@l}>+(^X?MC|u8Ib_ts)AsIX0&* zNS9}vh^EU?0)CXu!P?Hkj`-MLn1J7??ZkrPw8G~ab|qp1@Iu%!Q1o)Av7vz9wPKY2 z-lKS**F(_Bz=Wn#u)Av*VcMnYNpkaUmoC-s7x(d-^KolfDm(H}(Hm&C zmkOXzy>4zG#pj71=dqBQGW3&(84Iqs7X(FF>x!{lurQnQaHQ8Mzq={3Se$`skol7~ z8A;dTDioHzF@#5vnaF7|&wW&<#PwLmr9e8K;Vby`92(`(2(KA9=1zkRw)zSZ7d#9# zt&2WC28rd}JMXF38WLrk_h#UMofDvRCEe0y*Vg_w*vF;QTmVrvLPi`|x*=rcAgwJY zf`3CP$3gh~v7}|!kvE1R0e806qj4HX4m(>mCMWY;Xtig46X3yMz46!!V{(}HXjm02{E*V#JX%C}OH#%PF z4jf>(WA@LyfGjQ$Oj^rNy#g3KU|6LMJBvYXSA@66Uyd=CRa=_sth}P+c6b5o_+E&^ z^@h_?3|WQ?L{OkBFzdahipk!tGajPH%sz&U#AYB*5cvn;65C0 z_0H#}8#jzUEkY-iy_v*OGX0dyZg`VFcf>3Vemz3wO^P@8>p*nuF6!EC+gC!!`F|pQ z7YD)cvCE%+rXcS$cpN>_wqxW?ICa1s;+-(ofDvOpG$hrgT{>eBP3QYs{x`nKb_-8h zI}=}kKGm6of9Oz(JpJR>k2LBxo%Ju+$2yEErc#3@;c9h3y-^@9va-f<`| zIehWlul>Ti{+1FS^V(Jips|qJZs6aFZNlY!$nN~oGRW4ttkn;L7iicxZp}k%t6;|k zDrdNQu?%BqLNTJVD%v+r*4zr*Ek*9MjJ8yvFC>607XYIvW0YWTk zrFAyCO3FWv>aak)$HJIil~CZZK&kghZzu0jVBab}CAxoabL17KI9Uj*iI*6VzwL8E ztkA<+v7C_i>X8+8Y!u|G&m$3mN|f>wiw-~C`iXtbu+ypUFPJfcvdf`EH#e%9@HDW6 zz#DFFR=s&m&Q~qs!SRZn`Du7G!O}tPT$hF6KjyLD?E!-#KmnhyQ?otwmq12~&e&LR zxO@$LjRjRo@FW+eo3Q%}Q)YKf__Y{5RL^!k{KvcBhMs5Ne4n~)`4uKsU=xyZ8Cb}& zFu~Vhdnn!Kf%sWky3b)YJl+a}voiN`7kr-IIZV_PWWa}#J!Q;2P^3z7VO{{(y{uO3 zjb6*y9W1c%ddFK$y|uK*Jf8C;tns~$OS&0zI@uh(k6Jbl<24mFduv&4LFP`7AE-u+ z#~EbUax3W)#F`ZuVXBK)SGguX@z@&g0IqWx@s6+w!Eh!Q2b$Zx3z_Hc^0HBi{PNA0 zKvQWii4RATkO6CLCBO&3NYKa`&Rg>?nhR~ONN+>yvN7bX05PYqq`r6RWYXiG@Q@zc zlDb5D=e1_fc#Hg|1fK5r5$4k3gMGEYBY}T5Yct*qeAidk0bf|BE!!*P2$-Wy^5J%_ zP#53CZ7G8Qtk=sW;xcTdS@9Q6UmXol>%Wi!aBT`>k7u}5w!VuBjU&l) zim*^GQwn?G%%P4X$9)2_2EB{|;Dp%Th() zQFx_!axmsf8gOWVAmC{7q9aueJOI`G7=AnLH`|ekR~{fw0mp7hqr#aF0K*eDYxJ&e!Og8TQX5q~=M8-Fo=p|6b$|&W;=s99*LIRq}`|2!*py zx1B1LGC)xi^u>HkCK-(8#%Y)41$0w9=-jn$6cT&NO{e+%7xr0b%#jV_iq*+Y+(_UZ z_p>PkJi-)DoKnk`ZAhJPujsjThzZJ>bB49U&2r|YOhARq1V<%Ws*kGLb3iWvN&pb) z)K{)8rN#J22jzvbzM?)os5lZ;Vk0-sPD8td^fovzb1aB&{NI6!eHGR#VBU;P zw+BUV%d=4$l^)zX2r;$yBW=)vposg7Z0|nEL-1g$7ZV4&u{PolFYcNBq6I8)<+7%G zXdeO`xhDw{C8%Z7b4}7Oa zmf7oTvxL1I+g{L6Nr@hW6*94|6hICq4Cc8!2nAixd^x+ICPMvU%DpE}; z#54*6@TTssm(P%Wm#pvlWhsdrx>IgJl3vv~+jAdV! z+DJKUhM4 z17VgSZp{ne3NX=U4Bi%3#Vup(IwbsE3WZS*D;AEBjaHZ(wt&fyScx?TG zy9zzHx4ghp)2vjaD(^C`tax-wBg2<0N~jW9O3|&1r(ZxB-~VxtS&_UlE27pm^AsZ? zSG?v`A|d+>W;bFo4Ze68Z`fere9m^66??_7(K1nWAz+;2mz8Cfnz{OVf8I2y*Xif< z;@g@ z6GrZg$lY5N z%YZw@W*oH1Gol~zSS1mI->*kCV5s?HpGlBL8_6;Js2|XWcHD_xnx~kai)HV8-x1g| z!uZtf&VD-{1>V9LS0ImbFW$L6_ISj^ys)TeALjTp$f>0Skck;@?KO1fGXro{77zCI zn1GA+ZVOk)i09i{%(+N>mE{IkTr+$@7jfm{_ShyN?Q`trZ5H8OtyQ`ls=JY>aB6&i za!A!F!h0efd=(flHV>r;P?OBgQ3vMQDJ ziQn!lVAwK|AMcw3@o|p>qnpJ;ri6SFpegJ`=*I4qara4}gjeXRw*j-hNQq<+2|V#E z)TTdy!71-t>wzg`KvdL7)Z~sf?qb_A9M2END085Ip5-I=J(Hq;mv%r|YqF)*@j-C) z52C-^z9{@u390u(@!4VZ60pEiU6x(a*Ok2e!1v%5tr(Y~$NrJRiY^n0?eQ`=pEpX`YA zL0ak$t3#%E-c@^D>^5C-)LiuVJqGqE#m6gcQZwR}J1rT~LkLB|;( zz>9`wytgSotEwiS0mK4luUcY6EoKsi)W6Dx!Ey9~CS0b2NppF-$kNn=nFUK?%# z+30_bNA~hQ?Rec7W2nD}O+WYaEM=test`Pz4oAp_Sn)3G$c6;>p@HQ{^|O1?8)k`T zITQbw7IO82Z>Od5*f>o_;Iez>E)w!Tt1Ts_)v3m`codC&N9kqX z&O&R&R-BqQ_ii0E_Zl{6={tGWR5DAz%w*TBRHZG;k@-Qs{fByr#5-@NaW535clyJw zXxUMi_Xo;6UN|p z4e4e+anH5mgKAr23*tR;-8)@dd$qr^`pVCCkarjKbj9M4t|p2XvzYCoG+nB|S-xb_ z3C8Lc+(|)pFRw7`?4h-yns73}GI1BI$c9%&n$|0OTV-LZgSJEvH}>SESL%pkvZSfF zDwuR8n!Bu-sBW!embSc>Y(oH@(=YGGNJEzFA|ZM*rTBTqlWPCO)l=1ywc^7@y;PZW zXZ|MJ;u6;PF~gBZ_HwV)i^9J~5_GacLs_NrQ+xYls5YKgR4jL8Q>j<>;X~Eu57Iet zCra8k(|Ax8NyVQ{^3qPBn#(jHF8U;$TGd#^lUc6+G*C?ww$Ax+?3J`zf&X^d5vT3T zKlMm`F6cmqKl5ax5u6?BFUOzo}BmsV?In# zW0+r!z9i{LiU%8=l$BCv5%xn(OO3JRt||J=-;Q0%jB|}QT^28jxp)6Xb(*;XB$XoM zb3(1DyqsZVyvcH*aHZuub^<|mdrnj1Jz$w7;{bNM*nL$4`a7qpHP)v2Z*+wI{7 znh#AAZ|J(hOOQ3&q~-hH>XW9Aa><7*HAk^Nr>IAp=m#b3ks;&URqeR|BlBuMKiWk0cEObI1o&i)9F$g-F8&?13 zLvT~g6nP4Ivw38z9GRpt6#qQ`$>^QpVj21*ePYj?3)?)4kE-oG_BJbh(2?oL4HEeNwkgr!xOq}UKQ~(_^ z;g+t!^0&=iSg-j-;Xot|g)wS+wtjebx%qv&z!`c45xy=k#NglcvV_l)21rE1&|&J5 znJ|F>D-rs2OWXnTVfF%e;StTx*HZeA+NwbWnvfvGUJ6ibnENR_L%aF81ghQr{k#$W zes68Rf6pE6(wCZWH4yBZDtiM~nDb;8q04uL3-$GY?9f@VxwPH2wR-@5e|ooy^!b-3R9-oHA%A$>WhE(zof zQg@)#;F?2wh_lGtjf^4uE{&75?+;9O7rP)@^$dt}pIZUk!ow(tcMe!r#>J)*^1uVn@@2s~WeE@THY=U5&w`C#a! z=Sn(m`ED22tr5Jq;tOXzy?3L}Bd45bjeaezjbm18S`^3_s{flc_;DYc6~*X=7-SgS zsb7lIK$q5a8@k=xy!dMRuUP=_+fa~t;E!N`@%>bl9g5rSM*60Kk)^4j^UY z$s`L{kFrao!Q#qw<3dcJr{&hEqHsT7>cbBKI<3IU)ZG_k?uK1RRV%syrh2w0dsFDO zqSS)Q8lF?H(&!zv+cq__ZztGp-vn<&UnyJQNe`p0Ho(~sc2%7}QY?fn}G=am`#wYcMC~2R2Z#vEa z5T8@*86NEtT=zLpRZ47{q*}qnEYfwdk|T2dr75*2W1f2nS_ITTGyxt@%hFj7c&NXQ zIn>k^?hQ^KzuOmmv8CA#my8s+cH+CFq^IPLAla{-@7&-!AyG;)3-&iywtSDQ0Fzzn z7%xU+=q>)RPeqGOL;>O#lK3NY4=4es3G3ay8nb1}@uHAymfqGYk`9?C+M{aA-_k~A zqAz}f=BHHb>%}b*g7ROm=oLarDve0%qC#v{13|)FfC1Q$7BludfkG<)8M-J&K=x*Ox(Q8o8FPPuex?=!la2(r>9sIa^7e~ zA-q%Vw!O!MGi&thIDA;~;jC7Z(3D~d6 z&x0ioZV?GoFGSD@AF^90Ko-nF2x-v(;Xli!Wir(n=d~nIWG+AhMGzuRk%Eaz!hUg- z?95a%wV9A~pTM|Gvewlqn_tbPU->RiPkK2{dCI3)#I0&GMshcRiG z*s-6+ia=dE-C6XkWXz18AhmEnN-4 z5%Sy*7FmIai~-Wq7b$H~t6(i%ISLF@!u(xJCJ202bmBz5sz4;1%lcb(b1a`&qS~;} zbJMxX!+}IF_@4RGCn=84!5q?|Y-6RJuwu9OD8`{BwS=94=R%gYDb-FIBu=(8EV>B? zQtBx!Evsx*69}^6f=UX~0GFi;>cKx((6NaHBfR=DvZb5yg7GLUs=x_~;31}jdpt+X zIEQ{H>lxZo1=cw$UoKr8HfKwY%=pC&DV5Cx!#(F=kE~S&98-QCZ+{QJdYA9Gr->f1 zIzcYVM`|M|BUh7ho&3|ZrfRot!>R8^59zqq5{5c)mL-_&Bppw4f+4|otSE%7aRpI>^Sx%GYRrEqu ziKl}X7D|3!#E^sy$_R?n{s}6~1u>~^Q%1UgTY`#bPKh8O9=*-`IST&;OeA=D1!9aL zLpMind{5-@vn5$a)r8BTLv_X>$6OG0F8{ngC$IW0f3UH~71L<_DDB=~z~ZC{l3b8V zN1QRw7L&m}hE;Y;P712I))!77uqQswjuD=4$}WTge#`>?GtJA5!heCYlA1B61Sj$V z6o7YeNwoJ7B*`Nrm6*gSJNcidDDx8rfb3t39!exFEy1)!h}NRX`GI1}v1xr472@)X zT_Bnvl<>vtdt?N{0pRDG#Jz&tH5Qi#5i%K2qp`xk*Tv34&gbpezyV z9t2CK)`7Q3o>{eqTCbiDc91iEU9(|pLU(bfYFT^P8h*&8VAk|rg(8IUV$GFilByG& zDl?0Odbe>9O>!%+2J;4_P^BFR>>S*-g-kMIw%DkPGH4#SQ)^X^!R`~fY`OBmI=P$> zKt|fSz;*fBp(Oo3iZ`r^4q%NUST^E&V%pNadS}_E@fr?e0F-2#2>p#Ir7aRgmFl|sJ&5qV#D{VYY~AdEM2eE} z0*8V+q(>_10&JZ?2uDGF2w}x$9qZe@B&6rzJTOWIN6#}WY>4x6D?^*U?{o7^J?5q- zf^vUZn`9~zs)#%EB@FE=3`4+}6JiYA9tT>oNtapl>5KK)u}VD_?toy++MODurpuD$ zZ9N9_&se{=6sWkBIV_||RRLh1SAkDl3oD|KmnVq|^!ZpVd_cY_0GTt)o#J`iH;gKd?gK(MWlG$9o!Ck!4N z6wT@@95$nJE|-DY-pBL+hm1PTUhCps9Mmm=N>C8oZjkdUUxffS)^eLsxvVqF9u zd4h#;ZR!+MElJhbSYFSf40yFm+!Mr|Dvrb){JZ>QfS>HWfI3yRNBn2Q)U!pr>sJbH zJ?#KuK!XIo(7qWYO9K>;w{AgQtOKGi){?iKA;BOb*!2;9j89Te+3llWw5PhJ;CKe! z;pHVmug5Rw5B4@MizeoUO^?5?Mn4A)fA<*G;y&stAIr)&?slEJmjparf}Z%Box@wp z2OuNLEI*2DYH1Uy>Q>KHP?LYyS@WX(fb-4q)OUd3G-Mav2)SI(uK?zwvst4Y0(RX% zw;(d?2{=yUE#>oDN9^`+au;w)RU}db=9%iL#6s)ib7>GsciI)^`rK5mWPVXNQ;A0qvN-uOTP`XF}padGnSuaL~YRI7V^2T@aD1Pl7; z-Li)=;Z2ZwlUe94r{PlkL_`)3@{lR=MiN))B z{h;rO$Kbkq-;v8A7MmAhP@*5JLjD>uWdtQ-<=>&c60*wBj&>!dK(f*Y^87z2A-cB0 zDX#@OnfQggR%bk1K!L_0+)ZpI^|-?>c%{bSUNK{!WX8n#jSponEIq+bWK$Cqz!IcD zkvP^^aDzH6u(6alh)Go`t8sd;gHyV`7Ur1|CH5Ay=|>e~%4W)HdrLSNMJE9(|kzcy1pG=U;K4**3!|(Movb4BYxfZ zVL+a5`B~q|?cL*T=C>@K*E-fWzYiWo(Nn>|h!$un7Or~&3B7C!!QT(kR({MMDxzWk zoW+Gg^mqK-=zfil91EqBp`XMctj9nLjt_ z;I=AsF(w;fNeF0Xd`CxcJW!dyjj$9#YiZ7R0&JR$yFnN5kC2$v(4B~R!t;r2YckU& zljI#qUQB}AybF2#g2IX`e(w1)<%~GTTEG?nlz-B;G`b9*sO+$b>N|%G09s5yCrCQQMTnW3q9Vc#-UJuXx&?X zP~RWdC8t=ub8xEkcgWKb0!_Yh+G3>NVl|Qi8yC|qJ|v9=&kgk+wRx5xN-1 zJ4}$Y8MHwny1KkUK9UI;kTJrdWB~4&mP{0?wYCx*Tr?IO9frx71R1hIDP*kfFYmeD zXMp2rm@ZBKnXJqgQdvSSf8cY-J*yAg03jq_K&S7L6_A`6~wRd}fWj8(Pjz_8WUb;54BH1;(6J>>UGw)oLcn);00_K=B4#Tqa? zG&MEl>C@AzW(Blwu|_d@@LB16V?k+9`boc5Zu__-m4ZFp(KOOMih~Onk4qab&yk<@ z!B~#i$~ZOrKuk%EcOJ$*nm<&}f=2HEPN170>s?fJI)G2pKd zp1s&K3vD&I)-MA!4DGA_YC@2N)71R&Go+_+cwQ92IK34HmuP<3QNrzm2k>JrxB@CZ zm`HdJ87oaq9S`y!_zMtOG#-Y8D+gf(`Wy9rTw1NA*ZcF?Bpc$q*2LJ#>ABr$t*|Pi zBlP&Wqwy}QDrv+2MX}OMUfz=7&W_SDjVJT!y1BkH)k16{B#Y9z6}qVFq|DQ*+6h7g z`V0RGR|BD668Pcts8{0Q={#Q!cv4)&)qL=D$kHx>?z8pF&{djT(v-YmU9B69_LeOO zK9ADFNgy`2A8{^mC*B#-!dHJnT^dH8r?~GsHuZv55K>F5-~Rj$DA_i9lw(U{(CwKesuXKL_`6v|_&iB7jV6%Xg<5fVzu7$3 zMw9n8jL`pXdG)=n8>b@VZ_p3E-*VPJS2j6-V=`^P=>;*j#r8|=K^RwPb7ZOH zh3$0b_>A`VUa(u&Wj2`CY)S1=T$ugg;WvB24vaBTOgLPia|phYi&e<}v_yMa|2KnI zT`w^9))An>aP|7I-^vp#u6^&Q$pV72sWPrzy4^kL(St#m*t$28%pY~#j`z+Ao|VD+I4?TP5a>BHUj;Nn*evl4^X0vBSA)l}9IMy=~t(t*&Ts;O4qj|Z5|Colh=47Cs0!w<0A5pa5-i$kWRz|L&IxgvEJr5Buf^IDO)P*Z0*@H2w1X@|Ma*QefrmtoDDY5`s&Zq6g1~w zI6xMq2HjJb5G_bdmXawBkYq6U%3_{*dM9~53X##4%X6(A!mNLLjmJK9iH$P4E5Rk` zhiU8~?3n2n^+b{3Bu#9iKKyK;TkABrM{{^~NUgHzY;te-rAi|4e7a81*E4lh>Kj3E zla}Z!Ri`;Hz#^;NZ#~QUmuqR)*|M%X&tKck2%bGTQ5Af`S_tS=vN=Z`qQfSe3Qb`ON%af zmMv z7n%i>cqa}24lsT+p3hhBpo>&AgVm0P0URf0!QH1>Eg6kGBj*`nDrAa(g01<~Lqc-% ziIf_rwfnsb!%)I# zluh#rb6#-ji;lCI*!$F%QAcMS79OCmSI2E!hTHCEl;5-?Az#0j?vzE9{3oYUwmoi zIi|@-^Z2<}7KT%opqGfMq0e`ngNUpdLQqtZ>b$;TQh$ISjJDR7z;Tu!&d;0r> zMx8N*-Q>`=7^wqY^U-SI!EEkP;H$@fLKq)lfV(2*496Uxau=HxwwGO7!}Dcszr1tF z(lszQXeNbtU~>nG?(O5X_~C`C0>QNMA5j9i%Sz56tHM<*&6?*@eWg~XAf}|AIh~5D zRu!Jk>^zK@gEavFA5*q8n%ysbt7>_fuCRGxUW6r#gcyz>ymS@s{&kz|m)S#SWjfC8 z`cezL%GRBYMw7I^AV8h^h{JlrITvrw=9aj^VOXCPUtsBb_PR2~-LB)A`ppW%Ly~qt zlCd^$Hgv2lsqh~v7Jin@x~I*sF}c#yzJq?w983|71UtKAyDr}fb=IReSyzVnlVEK& zViX}07mCI|kpXd7jaBh%NGsW_wyd5kYN@DgZZT`IaSNZd+`6_L=QFhV%NlQ6k8NV6 zNou{P0Foud(f(I-uhXp}P8f}GYOQ6ro?L~aA#96vZzTDqqKx$Poi zB)UGyWBo&ZHV0X!yhjt#*P`*A5Ba(|t~il0Ia4`S)qINnifO0454~W!b)cWNpu5^^ zFzZ*0eMgTI0-NUB;tFkie#Q(5!kVWskkYK8o~7nyUW^7t6uAl|cn}4Few_D{lw1_5 zoUAe7$%D*!8L2OMaog#_awr4=x{n|754zERmS3j;9XRq0x~bc7$qI~@d6Shz9zjFX zN)O!P;&;fvFufdC!Z4~k!GqR_Z2t?(2sIq5Qogg48|i%d`0~Nkj6H^}9T3;^1gjT> zeQ5i;@8zMVz26~=wDJ=+rvtKGbE?Y=H4#OJ#tFWTN&CG1w_kSt_HO5IXX`zFb2X*s z>bxOu;}+n<)(Ti^N8n?&xwJ#_Hf%?ADEwRWYFvfE-_({biYx~vhtHu7N}d?1PX_OF zDeVXyZ5DW>5s}rO-MpoqyhmB;_J?zUc>W}J}AMIzungd*(N4xnw zT0lM+6bupFa7X8+rZg?r=8nFKts?xUDT3l5$0ak%VLUd>PqpKdBb{aiJJnkjkF27S zPc|jx69-QjbXZ40KC=qLM%t8e5*AB7*c1W&*A#hNiGhfLx{w^>veB#Ilh#R!xwWB> z(^=IKAexD-rX7Y6)+d~rYy@_FeODfC*TiV&gYMG}cr(lO{@+-9lkMdv`eWgrww3>P?R z2t+s47^9j+PMLBSFYrF%;h%yak(fo_f^)PuPB8c(MqpLFBVa@u!C$KsGm@YMa%7`R zifVLD7DYQqKT3EGQp2VS@GNY^8k`AyLE%?8+O&x=ZR`fx9&i}?8CQw03wccwrxJo{ka@cc@o45O71Au%;}M#|xjk}vqf*C0>fDIuZ` za0MW1K7xVngwe~Fib6iO@eNqZum`6c1N|10hGIl{yfVW10kXmss>kjz=k*oY<3v&9 z$_B(1m?>TGR(Hvkk`ets)b-7gm_a>p`$!U`4}!-gVIz2R&h*0cnKWgkKX}6uy*eGF zFvU}%hHU!a+lznWwRzd*UO!4FJWvu%u^(SPyFtp0SSQoj>TRkjpV2I?wAEY0(x1^7 z9#&RwjQpnE#uO`vIAL0cT3l=>yb&Dc(pd!1yhTH?n^cstBz`0Txu^q$nFRkwu2Gp4XdEFQShcXkXCo?OAS98!OsP-02Yl?a{uY;2NIU=GeVS^YK{1QgYw3M7w28NS3@Cy*Px zlb`q(EwHosK&~-Dq{l03$T|ObA<@VUg!HSr(=0H5ED5d=HLT1UF+cw{QIe~ zL^HUj93Rg@TrleY4zx!ZTe7h(Qy#>JMLy21<``o^T-SU0q4h!!Vf;jXabMNxbQ3jT zU5S|o>YCLsy?6E9_~E!jex9kf=Bp?%5KjFu%tTaOVLF@mZaRsFAV*al)wl`{>bKr> z6;ecsvRsB=lQ-0=_%!@d4}PxYfW%g+0$c&oqZ9VXggTIAVj+HX(U5mA_mBuD_igh` z-#V@3Ilrew8T!#8N33E_v9yy*j>FUeIuB#}nH*;OJ^5-_lFXAg|K>!!Tzte&BOX{p zUxi%SF=i!!;Te0jNhw*botCPEpr$#x?FhGu9M2awo-bbF@`p`*L0W z3_P$2<0 z$qP^YlEJt=(8L?QRIa=RwM&$+8^M_f{Yu(UO5DsIx0B*l1V;vh)}_!_ts57PI%YTz zvAmR!GRn7uGu|i@F$M(wg(={C<{dfuQUgusF`s+c@qF(d&{gyRht8T4u=vBN3rB zK=3tY8Q)=B2>A8&r(5lT%)F6n!EmIT&zu7u%T@#$k%PVxzzJ{NQOCN3Y()`Y#3EH` zbM;4=cwEt03;QNxIoK(MdYHx#HT{!GI*~bmq;C)Zbm7w8m578ul%>vg6(DyjZHEz= z4$V@u`1@v(33?Gz5~2mkk5ox5{f`Bk`zwt5;G2UW=~bZ-^vSv~6A)or7ngPoX$Z0! zX384HC_bJPNlS&s;%~L`xQTdzcOm2UJWfWVjA60~v8TvzIx^Z8q@mQeUJTe^RnAE3 zosjBcAwo!vNb|6zJQ@~IzGSa1QTC-V<}0tskQ+psY3&x@050!vMk$%s<1harxdwN z;;iLUc5&AkpMjWYQ>z?lnUOX1m4vjwU&jNB^CK_Nf_dt2TIaUT8||-wq1ngwTv4#e!^s67rBb;PHO*6!UjgUOI?8rtS*C61LrnwCxm>%=PLi8c>)7l7KleKn|zV+-$H2Ko%v#W&12 zIZ4|?)#+X7`7N!P-dR%uksY*kX2Y-G?NP%0nFQv{l5 zHq~4YDpMj*n9|sq8KAAK;hr4NeoWm2gDtb?_}7Jb2OZQ&)H3)Ro#5dtDYBcOX{`rC zs)upK;JpuM>Htkw0-8EN4GGfRz-3H1wZFIShwP!z%wQ{fof8Q_NsYcWWyn$_Bcd&- zaB{+6jZ%bEUQL8(z0luDz;=A34ET5;HvQ?sKm<&vuH!%F1+3CLdoO@)7}?NyHOHu< zUKo9HC8?=lKTzt;(fb&;kNEW9{Qc?C-tqo{UD}%0SlT)uDR$#QdLh2vnlf~U5G#!Y zg%Ht5~|j-gT9w7kx8|H%T^}UC6><1a;y5{98xmTmh7occz!sO z9Do?Hho=hhTY6QjvP$(`>#OC00yW1 zgq9sb%SqvCo7J$fhXHA{dD)Mh@Z#u0cU07`F?^vXy7&e=$e>OBHQfxz2$`gp98+{z zG@nM#?otf_-#!%6)Phx}Nrehpa_1qh6QrETLp-=5m|2BR3e5LlGX!ZT3e=P^!BNov zYv8mKh9)i!dcx7+igT!=SvW`_!%yhglST_T15*SVBsC{dgWPy*l1OyE00Oj=r6OI< z`#cf8VKiF7gYt#k2_Dj~sz*JH%4aOPH>eKMRvfJ?d%2zOo@lHYTl~Duh~h~+gTpHx z2aJBpJPQCR_F_7FAf%C*tSWc=E#uAl$^cN5wB!E z9S4N=gVm46Zn$s^@%dl5TQfzBlZT^IZ8ZH_A~s9m-=wqKe$~v%Mi$6W7EpkolX?nw z4kG6mscGlstk+bQiRV0yCR$QGnTgKQ`YZq|(jj_N3NM{D_>nFbZdkD_n!=0ZDkXPg zkCj0iPS|FfhqiQK5m&UC*V;SN^mz-S?=0TYSLq;ae=yMFP#WYvWD&cjK88Jo#}oRl zO*RkKa+bDqe<9?B2}+!6AC$_`%T#KN_+&+a8q~P1I%RZ@=8rcdGa~kzNQn0-Ua5D& z_eZ}T9shO|TJ{ez#Hpne9@oJ=vNaxKu?!Y7c*8+_Xq~kL7VNc(@gf?K}`F zkGMaHZamU!K_okY9MC{zxcBC?^fnxdc|o4P!qASRKa$fIh6fL_tGpmzjuT9BnUX98 z+wM3`FlMeyl>u9;@5t)?gczEfZoY79pHg&i4tGbtnb9YheTW32d-5rvXxD%xXSa+( zdy0B(Pcz?M5fD>=xr0yh;55Da^fmPR#Nz27A8!T(`n8-P4=Pafb` z(z*i|`u|?g=bo2HW-JqQBwXN*Lj9jAG|n&rdEe3WuZSoQ_v!17v6Y$Bb`>U(=G zy2r;Bvq}Gn%y;B}rv91^{3}XtKx<8QgI~7fb~*?kh zr3lF(UCzx-(-9`b{1VyLTd#ghD4o0~oVzStJL2luaI{7Q3;L{<_{wZ~Tew*t?0;5M z>{aMCwK@b^EUOr!6tQ$n&4A4QMzfUcKZJ8 zoD$o|rw0pjP~$6?j@(&EaW2Ifn=4OZi%~HYb~@DT{_&pKa;s~esOT5bWMroup_s?Z zR$*+|DCPwOg&RV>^W>Cn&)ce*2PybodZlkgpa{>N=hE2#gH{JsrOT9hjxx>OUmxFO^p&ufQH8vj3Sp13}> z-4nOUwY804?>ZfR3N%yS0L^?8SXvxG2aRk6-(tl+t$;?xStIA*tmODs1OUnaVjw=U zbDKy5w7{geD6=chy;zscCa129HiC=ooz3k_3K&8*9qhi1A%^jg@<;fGjx@2?LBYz1 zlF?2@2A2&PJO)>L&LP?bZYb}@lVmy=C3wK#FQ{I*N)XR-hx*mgo`^j5-7cdifYBcE z{^$VJ(7QjsJ&1pQ_cq@9<@5}hBCOqx+a5~T4FzBqAQPOFb0$)(Bormy=RnO1T)Dkq za1Sit(j*hzZc$(*$9&2(eK2&eO(=S(8Hq-PbuM!gGaKW6>dD6F2a;9A=J(%!`@`n8 zroClZ0k=9mNmMe5MJ@cEmQ9k_YZ8T!m&>7!dl z?C5q8Cav*2s8ZSr)sR8fCdCwYC`#%$EylJ^Vk0<#GecSi6sVBGLk;dlro^OTAA1mB zNAn@H1OtGvuV^tEP`qhQ5lBq)1W@E4v;r0UgVD7noq-!zP>i;u-(fB_bT|ZUieaa{ z6m?#8mP{7Gew$6R`uGO@T=JD6J3UG75{xm>Ny(~ZK21lCq|*TK0|&5T_BAED&1V0h z{D5KbU0RtlL2lo!uqDt~WOc(Pe10*7BM0iqJQqi1hNgH$c%d-?sXzo1$wF6g3UR5U zdS~zgIf8qrZ$b^UpC7bA86&HkXmi$&v5hH9?7W}M^B8v@pk-ck#%4gS<|HR=+(>w9 zOlP9>j;@b{M!l0&04yIBwlA~Jn)=u_ z$-fk)GA(Zv=O!b|*HxfAaCD7a|!TsH$-%K0*AX&785nEbiq=0j1+ws!im%}$e#MJeA@ z@hBSuS4IS+ZrxM=>G&*$r%zcN84}MxOapNSR|0MhzzTq8W;ash#p_VtOKG{p8Aw8% zKX-y<`=In%akLcNH{QjN%V@KtPN#|w|B1FI+M(&s2t%94BUq_slys`)HR~P#6aS>1 z+-K=zM5XmksaqmW1lC9goSNNIsjRQB|Axqon|oQ*y9&wg3aAGxfhzV`dy14DGApAA zuH4Ctjg@=M6`#Tk*#yMxOpIqP21g8p=nsOiop-)f&){>~kzyigkk~y$x-P6tB@A9^ zQ>tnsl|=4vEb-Cf`t`)JNODD{b1o$|d`h078e7wPM#(3I%WvSX4Godm7_~7X0l0vQ z0%Hk`ROOUXNDzJ`IDal;r-|yRT&B?1^hVtGo8Cdt;D4rN5g7p@c|Q=1t}>t=4d6y_ zN_1*)AYN!1u!~g4Y}+Is;_!`;m&=B2;fLI6BVLgn@rPj=DGz9FPgK>RoY%hk^5|=4 z%NpBW3p@=xqqrsxW+(UcHOxPZLYJX`C63XkNGq`;P>j2q1h%2Prb#M5(V}E!doCa) z0}!j`=tP=PJS!Nbglt!NvaXhER@M=VN1F_ijj^?&nU++aFU&l}uy9rz8v^PO#G{`K zTdNVR9a&d$TfNU6wJv3H<N!r2 z!nD$P;ewbIRgJ?DkI6G{4|pdn`HM@|Fe~P38`=u&P+MreVWfm@rR|u=i1ADK;@0E@ zBs$`1&A|)O9<;dYA;jm`*64s;YJQo;Fg35nAxSE>xTD9p(mmfV7HcjI4JZ4>AuTnt z*Cm3F*|f$js6p5HLzB9iYNqk^be>ZfN}j9UMatI!P3ARkp~V`C^XMEc-!BZ2U>C=N zrX`W*NgTrZEP|`iPM3Bl5I?z+byn)2_IZvnXhlM~f@m#cFBn<|Q!mxiW<}3vp=(d;p-TD}Q6&{rag@>q)p`~l_T@fVRIcFT zq~uj4q5>suGFU$%>~d0LaByjof?~Q>7aJjmyg-TpI8b=*%IXS)p=>fLVdhr_#&^b3 zfL0f6j$t%{VqONtZF2w%X3~mN4vKo?=!eN(tkHRSEOVO40ZX%U5hAS+Yt)0jd`X~P{nQ|+Kl^@;r?=`ykfer4?iX)nb_42$Hp4N_N!TPn?vK0`SjS#jqLo(beh2K zoY1apxe?HyS!?qDj=}Lf=U`-#EW=_x;TwWM8nC6k7Jp1=|HSF?ZBcxh&%ACVXT_9K z{Z&DS!etY6e#2WA4!Y0YB~=t)l9MtG3IA((JKey!P01N$RP-7HMST>L35sd=Fzzsn zuyuT#Q!Kfxw&0NE0@Op{s%C8na>#7>iP@~p8hK#kIQYnBkkh%`5rbqMQQa-acrUb0 zZjM{)tlA1DwZK^WJavY(29{jz5s=-Twe?ghr4qkzBZ;V4DLH#HliN@d+l^>C9~9fg z568jDx9~htzt0F+hAnqekm1TXOvY(Owk-;&$Q{lcs4tC zc6f8_iwdS$nYvrH$fp5E(DI6G+M**U4Lilq(P!0d!MX$t^cLiA=4*}^#KVM|Sop1z zNYWUKsk2PYfuHI!iP4G9Qh7r^FT#`E^Is?kq;OHJ(wXh0r~wFG1Q#KPgw$$VTUwqn zt{3JDx<1k41bEyxxUOUkL$4$yeJKY?MUHP!jH3sLJ8J~emT!iT{_XJSKy@2Qi8bQt z8crVw*dL}^L$6(>a1s8$JLmy2qt4D$XKgZGGX3aEut5h731OELadyK09k!<1)+Unl zAoZ5?$A0HqMD3UaBF?+rw{MU4;**2Z^Y^De$5JwYV+6T0(5)ohH>8vZ2liGnNeryy zgBw97i_)mqIDg6wv`L{W+#WHedp68!_TB{WT|95r8YoKs1}kZD1A7Ig;TaVy1LK<06YB{q?PN z7V+eMGeP;GVrNW5OSq9l`iks?7MM`RK*I1HB9A@INxR%-V{{>N^$gN{cs)(ZPo7om zR2QB?B>*X=5&l8TnC)Kh>f3L-hAQeT0j8M!C)xu7g|R{4l?mE%;z$o*QBa(yobA#? zGQ3RW9mFfiLIcLG@d-0Byek1pWA)AbL0pN3sADKdPdLXI#;%={zmL#s0h#q#XGD#FbK22`0~b{+_WP9X zdXU+s0jvT-S9xzt1+wzg8G$_;^CB)&O6hBzC7|^fea7Kc-3TZ`AkQj{MbS}hdd>cD z7#cIbad<98MHwUELDm1Nd~7ZafT2M90UV0SRD7O`T(#oPi;xvrkf)L9N~!?rhOHly z(y^1|(YOddCN~MCmB&ITt6QWq*Rh&~a)AuXqS9$(n&7sQN4AcombdDRNqU!BgXKX* zi)cf>olr?`6aFK+IJu}&ex8S)4IG<59~=}K2?3Isvk6&_rNcR0gnQ~sVZA0NC_00P z3aQ+YT#bI4p0brlKFo!dSL7O(#~&tJCqv^$467f^_#&$smf5WK9M8zXCvURolC4go zMZ8NlMK^pqusMx1l1F1yCbz|Cm{wQFG-(~_<0NHSAye}>;Q9<6a9znHGz%TRLuy(1 z%X4>hLcxD8(Kc~}hNviZ<2lyn>qjHyS^t2&ObzVsJ9$OA@N~xM)FJH%V@RfEPg_SO zZ);s%sr-HbG9nS0RFx1ZQnT&Zo$v1XTVyo}LU;nD$l6^R#(4P{?jwrp+ZUnPXI*sAp? z<}HA4vMNIlKGIVu$iA4rI^c%xE<_=%cn1M3?-l}rt-2btGU=9D9GTWrpNfa3FxjenCtD znW;mq=U(tN*?DI9DrTO>=L?vP8lM);{P5OHxS)bZ_^e^^vk|;a>)>iMkb&9$V=q8g zo-`SuQfXc}liYIvFelBdOmDJcUd0vqr`9n8CIeKyoxehx4E)w=gZDG=WKkuL-!Cu$jg#V4@wi$~L7V(TuNA-DDs>d~>8J1S!HsnPR(i3F9|{TbV4} zsZ$t-LRfwX{3U&)bVRr5>V~#<;i^5~fBkkf8=T*yL`SLM zrF9L;RyY8XrQvrHtFc2q;gD@!C;%#Ei7#3IEGM86Ij)P_pdLaiv#ZhlbieWbARJ%>maTDSoh@SBWQM_`)%3SzH?KGspCw z4V^UphN9cBL#c_LVb@CxuuuO!uQpyn3ya8S)rT?f3){h`*9XSgN0rCZYXWcW!++1H z*>I75^Hqv^K2K719c5<`GvYUO|8hELYOuZJGjtjXxngY$U>L5_9&W{+{S5A<|dO7QOv-qCWR@etx)1? z8k)q4jk`SJunlZk*kQ9VJG_DDaTD8bbCZC_99W@$H=XP}sOC64vX><{;;JTXvS_VZ zS((8+hY>%I{XUQBBCFNs-&5EwGFxYuJVqYgsok2h1XsjLOoXE`2}5?hAr9oG&Ka}F z@Dj50GYn;+>3Y-9qH~x5$g~pGt<*I``B`MU4~ZW1T*@>p8)kdP$xA1EgN@G$t$Aw< zmfwg^tP1(ks?pwvWs6UQ@SJcvraPe6gj#(8pJ2PR%tVQOA4F;z!*xw)4}3mrST-hW zf-WaH%BWMvZ|HU}Y{ z<2RuWih(}#EPH*s6W;3?3s1)+jvy?u0q}&5H03FfxMvI7bc?GvKZS30=%7zjY#)oJqiU9*k$N4(9Rt+DUwkTxCG&W%=+R&11eJ??M z%ouHSs8A1;LS&=E_tqpqt=rnQ!!ef@g$J00Vot&OI3JcW<=KAqT@S{0gpvd~Ve);F z1&+c#5CEDG*Xd-^L(Saq8tt&BRRD{xEC6Fn@PN0P!h8-TyUK=@4O3yw_{SBXF~};k zHG&=B542TgH@K{^$_qB}esl&*2WP4U48|GIo>P@EU#OC|1oz(36W&)5cDw_9)~2Jm zURtIEsjNXpWgY}G7$n%v0+W3xG`xoLHlMUO#YXTmU+W_h6zYw}^d(;_BSO7ks`-;8 zoaUTLxs(`ZS2CfSGAF$cI!af3NGy(W_f)an9 z2pO-5%%1YDl9O3x3~3h7SEUgYnTUiX#2kec1HI&a;F{`atJS%3c9koBVZbdT#e$|) z7JunwENmm=R>j5=OJ~(4FPy%%uhWwb%UZFj&h18k$Lc}$m%whiV}bQLzBKGk@JXA$ zGHgDFk>q2>=UWmDk3a#D$*iLvoS^f9kT+q^xdDzAc7bUs!1fj^>*7g+Ot)6D*xDy= z$)ddXO~Qu5;sz)oTPmmrzri4BQQ%?y1v$XiEdQC(+<$--7v22XLLT<&F}dEnW(ELWMho+8pM;f ztdhe?QIT|pWH1urT5nqRW0hdfI3yb6n{XpeLUQ|vXoiJRh8r~ZO%E!~3dEVHY)L_U zhhG|;1PzaOLWS=Fe&ao#$jzdi=lJrLNO5PpE|X-CRKXC#2e+BW&=w?hk=ozxg$t%R zle_F^JfBRY8Mjm)eGMt0#mMa@-YXRU_=g1;SbTt}SEUS5eoQomj zFCD_t+PdkxClH-wB5fDZT3FSTeL?xA7ajw0th-^giQW!IBO7)roY7c<#a|o2>%-sQ z9rW-@e9qPZ?95FQL0060m9L)*ZC33t7hpCU6m5D_E46tp|gi+q~Rp%`Hi0Bd05QuJKe5_XP4v&yUgu1qu^ff zm9nbP>TsQDB})2j6}B@29P9g-)Em~~Xq3jIG@TKahBm5Izu?&hWY%jawsBFj`i0-j%CCGy<4sq2OFy~kqF)aSp@v&(2Hc03?4 z2ZzrBvbkD#0)(ovyFW-qH#0Z*#1`IIsZ%3}%aAkHC5rXsYi z#k#FP`DSd44*DZF+AakCN; z-V)xAK`4C}_-$Wn|9O!kp>7}kdtPOQSl=daLkP{+!eO8ol5SFz*?*=xWc%)5VGak8 z4KFR7a!g>-VxZ->8^4i)9=BZPxvgfS(WLe6&naGJSJ$n;-BA`HnEfK62>EQv|JoE1 zOA?+K9`(BzF?&;b(VJ8Qm^H^X69;X&&IqQcQLgIwcr4Y+x(Vrq*d5vCmrN4CZ;pT!0(s>W>hB@qovt;dKHjyitVzeNDaI?%C*A{1%Do?<2ng zV92f?gNM<)+`)g4LqxB}kCkE!&O(L?eT|dzth%c^a_M=z$^fveG7|R~-a?84$x<2x zzcJ6>qqL^1>}r${5Ao0qBqd&WVuTSLh^hf)z7-{H9xAeZzTgG*LJbE4&|(j>dw#2< z3@1eE2M-!1;qj*(8?SK3BiraS3lGFD9=ry8cZ^D|1Yy){Dmcxx)OfFChTtSY)6k}d zPn-#IAA@F z6oQh5%-)AdD;&2uO8bKae+sq&RojT{14A8lTi(&Q_`?1O^h_}bljJ_^{P_1rwNedH z1V3{B|BydCe#lih%xxr0Js7Zl;;xH2nMlctNw!#OaRlK-Vy0(6nx;oZ*4CChSF=5l zPsM+VNv@`xtE|JJ{e-a}D$Y4JV$N|>1{5=81V4tUuA?w5mJH34ait>nQJv3h1V_i` z2RnE>PZ>4%UX&9d^1?~-``hHchnK4q9-^tKViD1eUtI)$=ohnp$m@7^%*FUU!sAQ> zfm`T0Uz=dlo4~Hh^v`u+DFAZ}aK?LxBp3sFsKwU<2GNZ%Iw+)hjTss0c_Ne$oXm0e z^iBM3_jlNH?t|hcEyt7MR;w}3&2_0|;e-ZIF7{R-bzSFVeEThx_-()XHej#toD*fL z>;3>&PdakKexg`J0YPyKCrL>+?)a80Dk{g)qLHbDvdsdEN|CIV`bby{6*FiGNja}5 zoKVHVC+U`pLrn#Lurn9-{twr#K(vp13@ztTDI_k$g>w+%gZFBiK>1DXH4&jgqn(68 zQK7JBftA`Kc2{q;`S{khqOyzVi~dML$U+GBEoQI{a`kN zeHDW(#ghB>E?QQrnAcWxX_-a++v7KH4o;uc(Uwkn)RDUV zFp}F#5Gslu7QDAQWmYv$kgp`)ZJbU#qD_}%HQH>pgbt^|;BUie3ao6@$o1%)!@MHq zbg~_`n$!#(I2niM9!|R>b}cR0?WfPLWavc9IBkVK7G{z(Td`0Vr~514PDrmWw$RLn zzHKkMwv~0T^F$C#4pAwl_D z*9sEWHZEOK4pS=;0ZgFCZ!vt!}K@2!yQ_weH80-9DIEVIIM^m z&3Hk}`rZ1fSa=)6VAi^w!3qdS@lebt|Av9yGII9Ot$~;rkN)ELkshA*r8a(4lqChU zwOI_U+h2m+^5%TTVNJiVg{FJtb@dsoif8O1VKNIG2i)5hU)*|_1K_EzKM&`zMDX;E z648qi{=ifkhLYH(JB1FymgIlNOK@N$!<3WWQ@GC#9*4?|gxzE`(#$J3yqmzv0)?^u z@7ZKD)!j;T0zawqCgvV*y9M{rhSlRj6Oq-&1#Jr#4oLf;=o8GCOI3_UI(*yP%%&Bx z@xEcx=%RFs$RtOU>#V^r)FOxPPT;UB4IGFUq9BT#rGoSNCwc7V$K#^d#(!R|%cCAz)JJh;thIc~ z4n0DHgZAz)mr#u|pnMvmVN#BqN?}O$nqTjH9olb@Ch{$Pw+rknEkWbSCFrZwNF$9x ze|*YD8iby-kAXtER0=01`ekS45RkbNUYYs#5CJs&+Kt+Vyo%cv07T?u(i7ltV8A!P z!GHRZH673`hSF9qp%%prG78G+bI~!1cQ2JgpfP2d^Qk@Fuipk+p{X;K7zU>N^?Z|nNcKCCsU9eS({om#T^#0^`2t31$5hzUGwl|w86{? zYR5E!>@`dTacTDOca~K($mZ z4MM8u^k$?c1pfzXU8TvTC$ba+q{~9O*g$YueglF|GgZBnv_$s0gM>{{hQ%JRcw!<1nK{}4N}sI^kqn=(8qgnS{whDIU#qx2ObUIXrnOEX6cYI84Y zpZly4yrenV)ZO+V#IC>~n_%Br1zVGCS;4u$q;!&GokMUaZMQ~a+qP}nwr$(CPIO}1 zwr$(Cd15Dj?(nNS=}FJJx_0$``&rL|wdLOP#9TDi;CNKmRmDuk$swQkF0#z#HR|vW zJ9;=Lpk-Xj3Rv(&_=netLWKJTpDDC;J0rZfV7#jJXQX*9^g_7~)8_UHVlCDBxk`hB z@QA?od1?+Q){2kAm;+SLA2S>csF-^)?`KYF?tOw`0LJ6}P>ggAnCSC^XZ9lZPEX8h zBQy3FN%b8f!XY$wbO`kiFTYQ*rVoSwO$FqZzr9EfSax@%Xp>upujKS;m%3o74jZR| zO%BabuP+bB)IgCIG1iC;Yh8W;1SD3Thf;vTjh^Y2+~28w6vkrc;qT{oycr;Aqklhp z&DhC5wdN!T*SLcw*bHC~Vvcu9MA}fulQ=u}kpf5KP(8oFQA5rg%M#K}yz-*-_^?gZ z%!^D3>1ayD?O|ZYI=r!Kw;N{|K#Y78gM}I561h|biA;_0VWtvdt&rFmKVoYS=PwJA zr;;0#SZ+Qvdvk2xX|qH();J@);8mLKO&vkwJ0ASqqiB$=Sj!a#kQF1f@ z!UXJqZlK*af^2h1a!$60(0dhH }CqMz%l!3(_IbZSh4Gm|+z8Iec}q3i5_{HJ)@ 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

XI9GjL)=>OGA8OUZSe3j20jK{Zv)z%534 zm_J%1LZ|3aE-_o;lyE$`8HVhQUZ8!~&dIfpgB@d;+P8$J zOegH@nyPtM+GE!34D{tcC*>1r=Lsn|y=ke-DkaWmd`3*!n+27XQAwtTkx+4dyt-!U zN|y9H;g?wdj7GG3C64cn+p`8UKX3_lQfn7;^?TkNAVM-f(a%(fzc0Dy)qg(x$+#^g zL;OhX7b&UoJ~H~jKAla}hd3Ab`?d|y%y({?54X3szaWb#T_Dw!3EMycWzRr8VH0&~ ztiMcC5}hQO`OOH1Uy;1De`U`z8e} zN1aeVLrNMU5pWz)0ywngk2Ma3BnzALl4N0}o&$eV`ie*XExHC^asc=P9UxvAw=v+o+B6&2nTuEvX_o z6c%s}AA|NK80vz~7+wP?G#xeYIi3dSWJik6`DpHV2dA|Ps5eZvPuVG7)}lKhmfk7k zlfrY2qfsPZXd50zzKaSe7nV(E#we1pnTsn?breYMqFjx_>#waa2?e3 zX_%0ozXdaru;Fxv@cn%UN|k|GkZlNk1W|FE@*|UB+ZqWN1ASOdX3NVNF@VYjtAiO| ziibm&W1%(@&Z@lmXu6YG?~XT3vr!*2g$Oys7ytqo$WWiNGg)OqaABVXUT`X$-E=bf z9{^Eyr|};9mi$Zs6oapbSNZXsUh^(O`@qz`x`zkLSxZPjPm!4GtNO~$&)QLnPKI;u ze~jV6#+dH1xxtFC(cgaGuDWT5x+3Mp09I9DXI>Cy2*umOHMv}I!uwqqul^nZc536O z3=#36o=IgKKcQmWY<3gsn>Cu)p?<*D!yXv%`x=|r6l%BZvGiKSFI(@AW%4Jq=ob0~ zZ3>(z)`b@NA3<_Y6hF`-e2wu+VsrprwGMP1Zts@V~e+b;~T*PHH;q_h_9Q(e{Vksl&y;QrWWnZCR~g^l0`b$ z)6sFTe_O;Y{^DsUp3ekQ%Q{l@sK(sPu6~bUtYmfj9ddhg$!h_$rbEG=(Um#&;sY#C z`CYdYQng>;)m1RHN}cS@!2DER_>l~#Wv4=6|1(Q-i29Miqi-3LL7&@AYPc5IK~QkE zm%uN%;rKwwAwKX`qr8NUjIwMOVXxL8c%D~G&QA~YgP>57WSC&u`Vi4_kYRL6U|mP0 znA+;OxBlwrvTbikX|3A(k{bGmWD$Lw!8C}a1||#nBA#q(6j~RaX$WPkds@C`a8PBZ z_y#(``DP{yzXXt>)>dtYv0$e>V2J=A`isb?u?2vnEIY%9ujnqme8Ld)k;45Z^x~8S zBkVR*tax{r9M`n!udi-l2s%|7dxx-@ZhLp6R*z$_{IApAyGok^#V=I-(6XHl12XTF zgJGEncmrR6aW}|il0-nfw4FdaEmm|2f^>V|lIHoPh5LmDk_;%Vn?4{#c|nxmoLe^SeL660g4`{!jG#P!&EEAxvF z4@s9}psVHw?vUvH6rb;LLJIIKsn6w~Sr3&f97NYYcwLk?SiraHo%$EpG`z(CH+hJw&ifKKV*;Dh43&!&G}zQ^hd1}?rjE2xIt72#Tw%?D%DBZy#vO28n}kXC zsJGzH*yIWsjNw4-35MMHeMz7s!4bi5@l!|M)D=s59Fu&nZE+q*tG4M`O*Vu)*COgC zh{0v5pZ>lefpyWCUxw~{G!ehpLaJhmpwy67o?=O$H=GBdMEw0)+1uX}tvqSI)`RN1OC?BSDL;gA7~6*u-)Xam%^8{$@@dW^dzH`DGA| zdT<}Sc!zIFSn1=Hl9Tf{D6VVY&&J!C?9wt>+4Un~&A8(>3@-L>WY^no#(*igefro) z?Au!eGnzblLvhbFYt;|o!8FJVV|KlY2CWq=ZSx*S8;fGaS0Fhpz_WC2k&=d~NoaqA zj#^{bDpy={(yQp)a_CZeai-v)kLQTlg=ldTaJ8lK9CCCM@Xy|g5^-s&C|@zG&Bpl= zMEcZigu@i}Vj0#I-=J_7H*dg=fOMC3qCSc#>1>K8FK;WcDq;8y#tV0ubhYR&TXamZ z*CrZ-qaUV{*UL0x+jXzG5D=M|Wz3652)Wp365E)a^)d)LSq)4R9RUriJ+&9T!!4m5 zC@N0qXypVeeFo8a$vAr@6Ej2*Jw%Km#>t@m=gC4Ut0dM*p1q-Vxcv&sgGf(z;v6+p zJr4J`H`#SjEp1LmH5t1Z@JHlIj!{Kv#tjsrX&VTo*t(rsU~s5xvA$9j*#cFooT}0y zp7Oe&;7!I^(ge~4~>}xaHL+)5t-nD1bPWh+=LL81`qPn+R!$I(Do`#D5p9(yZkBU2-ptZ zT)}HqlDxG)7YVA3)eYLqv1y466RwHn%(bj67ukv^jRP zu4r%PN~K$Gl(ol8Y~0y zzK&ru216J9?XA5LbvmcUtu1JE3$&#*v#LFc5zQofmHZ|!;OE!hNQ85M@HkrB%VLjavoND&!$Nd9Ue z8C?CZyXMVT2DX!360&n4`^0_L8oU~2_?>*W6g(oTKC-5=kfyATnz<}?i_kFE-yo_> zA=d4v!e7ifUK8~0C+G4uQx+mFx5yL*hc?Z>8wJ@_C-8OIYI1KyFa@D0g|8386+gyW zM+1B&yR8zl0O}S1zjo1x)r+^_^*@!#BI%Nu=oT@1Euq@UOk1?Xqk9(NR98boEnQx_~-!d~MuyfA1h3VCKyDq)k2p7 zGG5{tH?U7n+xxOiqy-oU?&QghaQC=6^XA)P6iZ#lG7|!gDAsfpEVZ_nbrh(-uPDai z-6Xm0zLu#e6#xexM?uD96375-lKW|dRug9ZQqPlFVH4hVAuA2~ z3p-t36iL}N4s~o_yG%BWl%C9|%z@18@izP30c8TjJ=eW2c^-#v^@3 zBI-(;=sZ{aoEZ9s4VgewiSf z^-~{VhsG=SzATTJ3SmavVMwauL1?jQ`gnG>{*kH`uQnLw@v-B$LEqPI1M1X7znQQl zw~2*%KHAGKwexco?_bfb!Z~HI*}D0V0b`Oc+<i+E{5$)L$-zRB&FCZ zgS8gW>v$`e$}q&25g7jE_{KCa0?P*;uGAH^E2OsCHm=rr*1LmE>$-MjE%5H#C&L-H zWRRo^u6O#I;2mmlI)mkfb9t&zgp7O>PV=@D-yJILlst@i8X7{^?SrX2LQ z0#BIKqD`1ZK9v`RBwUDM#raMiFNS(ss8XM{$4?X-0`zTvjDO^ z3!nT;HTWG{7Y;j;8nui7K>;V)FzoHKI}qUfgbl#x4FPP}ml>sLem>SauY-EO zwk!QwKv(5aL%END2s2&>0=7<7E-=6MQ-~-T3V=H@eHw^6-1w9^9fjP$zY2vYmfex1t`g9P?Wbw+u& zI+L&Oz4;bk$LDwgf0yv^C%%!#m{&VL`_LOcQ)t(U*kbKt?)s${gnN@Q!{M7b5j#c zkPNF;wvhYK7Fg=VMDl~WGC(@4T7%F;-R=%k&9H))R&t$id!HAgc+g0Ki9yCm>j!LS zt~^>~*6n*P)#a9*ZGu7Z)?>kiYCf2x^Ga}N?=J=p7P++1N8vcoz2^aymw?c7~rw4kRQm6QQZltjz}to;S;e5Ar|&xHAK%!%(Bm14~37) zs)-b!y&jaBZ?_x2?7dYi4w|}82|~OlKHK;`B*#vH`n1K#sk-4_UO7KiKGfodLkZBzNemci!@n3h!h{rAX3=sii)uHr zZq~uLn;8#9h0?xOE@n;SaZ$)$0>wg^&|)|i?7epegF8Mwj$wM_=6UluO%pHf!|&DQ z%+H9r;IYCvy%*wo@H=7Iz2tnCN3}!e$TxqG@f8MLjvsuadWM?p%vfv}mm~cuK{-pX zI5aVo2st1TrYHcpIeld-5Y40V1tyS?cM%CD&OMB=_&MC z1Z zo)E}4xQpH@=6wLFu4bQ@d9=*9OE15h+kt!EdeL#zm_w=c`&DXZB{*DrIcKxw zSR~D8qY*RPiTlir^s|~594nHUzojs9N~i3fCyegqQK9U%t0QPZ5dnKWTfI+*Ga113 zf!T>>n^&O6NFz`O>HvQkoCtS~TLo&@N4+aJ_tp2zWkl=W>R@HfGU3^VgO#@Y>ox=^ zxCy!haJjlkrUE%&p@0S}tQV6dcq(fg`!+D60PfGYo`Ci!Qn-UCyej#u?Uj9T)ykJ7 z*U4pM)}_;N?$O0svhn;y?}6r0O~Za}VwKx!x2IDg#9f!Bd*ZPzYaYXy(ps36IR72w zgrtEmE0nx8Hm@aI_~#z*u2XnncjqDa73Gfz@Y-3a^8OXy$hC;zVnzuA-fj@PWne#c zg$1|fAe!X+a9M>FUKO{yHXqHe31E2m~bMYnYnQo+DQfKWOv$g0X5h9frqW4k-c(X4@QPlEg!?; zza#|}N8~X!xyBotgGisQqd#$bdcb&0N*y}{l8T%g)-QkHsr!}G;E0x5pTCmYxr)=B zpTn)!N&K+o@jyIr{t-A>RK#p3@)a_W3~Zml6#O};CU5#GkuPI-^PC6>DqwEw;d`g_ zb^rV>9mJ3QPQvTu=jHNqcM2Qi=Rag@R4-<>-!9||g|y?3J0bDQPF{RJXR53*Bgn|{ z>zzS2n7y`icH#U`J$5FpjhPuRo5ruh0$7_Ag@s}iUV57y^-I~P=ZK%cSEZBu$BqIU z4C3ePIeD7o%!2l9o2_o~z=L>8DNS$Dh{i=%5^55hA!imZ`k9*tD6l18n^OS%VCf4< zcA7)0#lP)%S3MU!!JbB&M!dyqc4BVNHtu?@xRZd)9e6)liOg+~Xx>V6BCDonP@aXG z0`ixk_KW3TaQ|Hq8#UM9XfkLSCvZ(7kz>r0vU3hgr0HEz9(J)gwve; zS$w9X1_^)AG|bWhePy ziG8C{Hf={~sYKdv9-N{MLHy~-;?olf%28_tp)>QJOS4*y{lh+p z$Ui9>!&oPtee?U++vQ8na;_k+#?tpb&?%JQ9_X(p!UD7GKg?7R$1{u8G9vIsy!30U z@6LLM1)P>Eja@^;4QO1~qvtmCb_$VCNidKTr@@l01N&zrA3YyJ`}33I_EL{> ziL!%m$fClf4Ak7}T=Ko?)a=Fn02}#V8cZ)~<h4vf z!COO3#*Beo`2k9C*%c<143!@+tA(fX&^N7%ARBLjY*zFm-Ms9CDJr(6!aAG~e9$rLyWD|oUn|-dB<%44$8#hBt;FrYW5mg~kEvFemq>oGDT?EK zXg8#i01%JhpRvx5-|myoQ5U~~BcVjv5Sy$4NwL#HIBC=@$t+8_N6vA*pXBRp&k-cR zzy22Y@ufVphuh^~_+1vg*dDI&|2@!sH^2g9y_PC-@5Nqs_zXt()rGZ-LKvscUX`#n zat!jDY|Ql*_CWg;Z&+_HB!gx~i0VrdCMe4o6mM3IZ^q; z^+-o5b;iF!Uhj#f&+E)5V|<&Z<(RIIt>kUY|Cxto6}boQX|AC@I+`}s?0n(h3z%gy zkln5aq&jaJuT_M7Nd|h&P&W-sX%W-!Jwfhsuf5L0P93`2#CKs5(108zm)GZbICu@( z)z>YHYUJRTr7xT_9ZeQN4rXz)iDPQsE0cjVyOu!lo7aF3_?H(Ie-g~vR1kDHZcCh; zN@t*UQN4#GB0sxj+Wg{UB46=H&$OI^=4AEkmw$NnIi1Zs6D2RYPoDBf_wwgU^MXw9 zMkSxx1xwQC5DPmN*?vwLg>A*g&$fu@?N$(UYY`EaIR7}ob2yQ8#|G-MMc{h3fp)6% zIqvxvdk5omaRnSeXhm&M#gpOjb-z7PV0j9&-do0WR7AqXWAt|og?msJp06?bdrff( zpz`jcNPR=l+>pl=&+SKIKXod+N~AJEV7AxzLJW6CHY7NN&o*L=@?^k)#F(h$Kl}h9 z2z>rAn7hzQum9!oc=J!1dzlApvm+HEn-YcoFl^nZa{YHKWa-p`o<@6OHFUyWH@f}Bx#@4>Ut>7?IUNQEI=4@rlEwGjgamOm<;vzHmUroYw}gpQMpaY z_!mXh0e5;`it=%Wlh^@%x3^U26Z+E<7-pNpzq}amdrAk~tO>ff$8Ok`X`*uod2`Om z9Tm>BuU7I}Kd#}b7;?4_FxeQ)pUEG?%fj^iYM0vB-5!1~VC(CTRPrA{9bQ1=>>_F+ z#|2ae@78Jz@a5AJF21Ud~DLIf5N5Hm`oKulz1FyL{y0HrCltZ6IQxi--yZ>%?L zn`0Dh&S!1UmCF@^SFK^5{4s81Lu(?J;mk$j1z}AV+c^K#n2x{&jQ^5AW--sUFK-1t^ji_Ui2OKE`%ySv-F z6-g~~4^RYcrrLilC4P#UnZ}7iFw6~LJC;k!-TG*S-Q5LSg{_`|NgmFW(4$>jVK|Lg ze_a|y?efi@@OpQEOj^Ye)uu!()nz0v`i8l3%Vl(G_IDbv*7dp+teC#VSZs&pQ5rn~ z7u~bW-cfhx*}4n*GNzx^I1((|DX5QW`uFFUV~w|~UTs_2#_g=_5wzr4a}$83NAyy~ z)*K9d0%|!0^oRQpIphWo*(51_v*;!Hb{AU%?L_c8Y1OV449w&2OeolKHpnX*$Xo?D zutBsFHmTe{i`?J~;jhr-5+u3Cv3)x$>Z=ss`(Wmn^LruzH^S1o(4#wXzIS!-b7AlW zVOF1-3OIk>L{u(~{(7{X_8zIq%ETkBgr~Y*@bfyxR(*m!;DNa|p)x zI??Wkt)_G8s;08a z7{=PQTV?lMq*ePParm6;E|`RFpS614L}l&j(n8&#Aqt5ByUpI21# zlD*Z2cy-3v*9p8VKMM{71C$JaTM;;8YR@jAVJw`we@*C`oeM0jKlh^kI0JN<7(A@ZwGEW-Dx#|G|5)oO{5k8g;Y|rGiisw zYr>^#)+Vc=15zCTByXlKC1awGyTvuAj&XU9*V7xmD?z`{&5wk$x#*5iwv3`T6>$f5 zmw1G~M2d_4##)9ecej)8F*;#97${fC7oxv~P0l&(o*{eTRBz{UT3;1I{Q%!*xMB~b zGn`3TC!Qv!s*1kuqNOHMKmdc#FpecJYTZ5sWpLiS>V1J}k;=uwa&`mY@5R_9hmcmo zeQ$P#9#?WK8-vVxgzcl_xVi>=Z&~}W#`(HG@|aBJb}H}RSV4}! z3lt33M!H$nZNT7mZ4n=*ygJoI5qNC8Wo$~CyRM~6jmn+JH;#3(5GTF<<9zN8UhFV^ znTawIrI828t|hTgJwoSWlXY6yOkW6`TV#rBU;m|U5sS80ONxviJI-p0z$%1=5WA^s z@$9yOE_fuL_~XrM64gP@VzE&MFKeAK*JvUa(D=*q!IpZf72%$2uLlF{8H`v3c(^!{ zj-Sql_-4G#c)#+h^))JxZPU%!OuXbZH#O(YjT&1#weGri=XS49h?HYymMR( zu=rm*A6jy4;T-R08z4I#>0(??bDgb?HWT5~*`D1Pc}{2ix6B)zk%MMK+_5RFpMx_py70&bpm}t@tulqWE)sb zAHsba;^tc5`)$%8e|zvxa=5-fb#Q0A1>6lUyj|=gnxCw7IYevl0wR}M%?(C!QSKOt zvU%m};(-38(VJbedG09jy2Z9g@65!0z zOdjks{^K}rFn&>IG>eKUX!)Dx!8dqhRGO&JoxW^AJNRy0Iyit#qbvNA0f7#b%W$5= zUkK~gZbN(R!`gPK`wu<&OVbjYORZ$1_l;@M-)YK>YcbCA8C-rZ$k8e^ZAvMQD{|yp zIs+=8pAhsYfT;C`D3#RlS5mr;mRT$iDRQ%;$m~}63eYR6$-WO7p9uxbL-H?Hj$0|P zs#^!4{04&&gks`J1+Hm+RImX&olVFLXeTOGAtd0qh^z7(hlDlxqF7-=WL0M$H!5EK z$shXFiw!E5e7;U9b=-;U*`;r^I}^+4$QM|9z9yRzm7u1_3age?N9ll2Uwc|N0G6v6 zZ)O_yg3|lRyc}=s}7RL;cm3wwmE=I{REWcDm;rR6GpqUeeAj-S2hF zbz64g==pOq_b)=zb&A!$j?8f*da+uq?gXLpT&N!Cp6XpzXB4SG+oI>S4{Ac-r8O7( z{ifYIzr2XzPDZ(P8IgfQBe3>6WXZ%?BMWS3Ny7!+@(gW~Y?@mgX5E`Ej&hFNcbBXxNbcbST163C<0sNk|Vy70Wo6pFxRSZt>GCZ(Ji>j>05kWD;E-u5Gl<7p{1d}ok zpyYsR#uJv8lF$~%1Q>r&<#Ect6|4Z?)656Qg(^Nk?q z67Z_RA$!~Fx;(n{PgL*NX(7Zf*&lVfRE4F4?TjO9giFYgc z*k}mXT3WmxPANv(@=vREv^5_W`GvxwR|?c+73uC9_3F&G#-2B6@~U%JQ3&^*=t5dO zh!iki~F8ZAw``7ECBfpr~IK)FX0??Q)CrRHW58xfkr#jF1~fT z#?Qr4q*(rnt-wdlP;o?&3F@DIa#Ol!Jft(zGCStp*Ak?Us%OG>3$0zaGW0V!xylhq z-y|iVD=u@@h3(<(Vy^&X*hO2vn#r=1-UBcw?C?%gM`^^V(0v4G=IrY@l24y9Jwth` zv#n?PJd_#vf~-g1-KRFO%svruTu%znw5y3{2;DuY1Sgt2xItTrJLYdDpCwLs2f0!b zMaJ|*En(s#mreV`=iO`=!1w9m&Q&k)0=QwY`!abTN2R2~QJ7j%I7Z)CUblhtqz?goV5W!h@ zL2DefYBYg{MYb9fOY0B{qMW;q!)}Gkn}to#ruU(uyv)U z`e1=;F;AW4*Ex>nd5qBV@cmY-fH1yWts2dSI3fBO+UYn0bV*3ddohcQbl?KL6)mzMP_wT}Qw^@{CN<;%TzV zf?8fM%jCtBGOw{Z#S6umw-~TwCt`7=q<5^`)$wpSHSF$XTY%YZZ(g_(TP8-rTO}|a z+ICsdQ>p(@P_kx>cSFcP5T6BRN)0r{&wzHrng13fkfiDH6K=1`0?U@mZJbh0O+ti{XRD;Af?B(c z*xZ%GT5NmCcukn=W&VnwKkId$los-cdh)BcD%<{LJ%Q`0 zo;!(C?rjtywRt)=1EZ3wHS-4%Y=~m%ynaRMlH%HxG`tEplyo`?9j9;9T~1Hc)(-`y zE7Xn>ve0yroi8ghGZ|FL*Wq)}CDoJhl$5UkKlP0K3H(#N_pFsoDydRQ2Sl*E##i95VwRLL}HZS1~>+y5Ca#B@_4;JBZ}$yUiFvJ#kxNt|7|X=sx0C1}yW z61WqAJ;~lQqdZZBHBCsvm~`uQ}!spGvAxa zhIAzzWGI|KmQW%o@Y|X6ZI)oWPhXex)h5&_`9&H|F_~J9BO3Q%{WbU~;^v#bqmcmO zOP8?7g1=9go^#j+!Svafa>Ngaof#Hk$TIw&yN>4A8D$6)jK&bZ`USIM`W@oJR#>VF zH0O5#li_Iwx>rsa_6BfFm@rdTJf?>+$U0t#=CbPO?FB|h*306=`451yp)>las>-%I zD;H_oe^$?W><>>ogSy5pOIt0ey!E)wktDjL;8?A2yIzMQIMgfVqBdIfb63%bMcqv< zAwPZHwm*56ZcZ#5hYs`TE4W01+`;I%a;5L!c)<{o`s^ftP$?U@H%mOHbt{)?;hbvPR1Qi8IU$Dt?#+K%yuS|oxUKGZ-_#-}^r zu@toDA2(aqxKMU-_wXttXbn_yE%F^GNJ1BeOy%FET+M zc?)IA8{@hSNwrfJzYh>0uiO56pg-bdp^0z40^epD0NbNC8~JN`#nkE|};qsiTeK(%=VtZfF$R5N0nA`~#9M`#_q zY*ZK3yy;haN=9?q6SroW^6ha!3^3csKB&X4I12|ZnJ4$~htOd+6m@g9K(h|WFvPST zPRdx!!%Qg4jcoZ9GjG$m>phD8{*mMEt3oiKcQhTF4Wu!7;y^0A*D*d1@-t zv(Ao?1TuTb>U%+2znbMGIg+B+QODu3>}2HVuHwO$3T z+6mTy1q8mQoWK213D_B8I7)%vA@mUTc2HQquPJ=5w&AvM7j6?RxNXEVwI_+lk=-dX zClgwmT$rLqa8#d@Iq22Jj1PbfUp_bZJZpzGDj;u+BD^$J+TpNQ@ep1H-bVQGaDMw^VL55^dl1ym|@4QU!0{lSX z#}!y0EmQNhBYO3X34n&ZFW9McYVKY0jhA0fJbJKngNz)Cc(I5lFdanm(J|ghQZCPn zPy6bD{Nfb;%K7Y$+T+Ip%n`hXbR>Q6mG=7GU%j)fwd!xSr?-$Xk5ZPITSNj}%4?tb zdfSc)-R4Oi8-a-7nK2cG)DGjN-sT64`8g6d@nq;G(W{PSC@-}@goL90h zqPOCR;f(uiojvhu*@lA34fg@hYOv!VJ#fV%N=!oTBVWkySvijHFvnu4-(*rx3p8-W zgm_`Nz64_0Ldxo$U0rUL=hlgw&r;}4X-r+^A6KH>vho*Oj(6%a);AU!8kgV+oOf*W zl&$K{h9j2oJ_P&d2)Sg#-t0p0a>LZ!zaZr+byM4=BF93rweN#pL&iL?E|cBBsMPu# zc1Ozn>XcH4OFY3;op9gqGjvkdl&&k5Zh}n}(j>+%{nw2JxnTIY3h()~56R@%bIwS5 z_Z8WC7`I53ygq36W=3MMe=ty(H-FlWduu}_bO~1(sce~kkskb{@ceTxbwPA)t#j7x z4W8sJDxXesC%1Ud7ZT$D8kdW&c#E?shNTDG-KG;hAls2~3;Bc`*Zzpx9e_7~A->nQ z8kpO0$UDH0(3ovmF1!Wtfg4*lBDD$%y@ML2^%qUx*kU&}$OqL(sK!0jI_m&XE`k z)qch1(O?=QEl9W1yzb8MUeWvScgv1r*6-RC>djgHQ7u zPo71%MdGJ>+4E4*^f^-M$eYuGo%Ce>88hWVnfy9v=)YE%+0C~Y9zUVkIRtI%in&KJ z%c#^Q$1fN785mIU1)KF+ZWdnPGhW#jh!soAOtk8ucjnIP--*5qfZJLOI5@T+6gStl z4HPd5x~8tFYaZoh-|CfrNowwx+^K0?oL8l8lNsv2B+L}7A)_x|Ajq@MG+@LiQ#ye%3$<~R*7tQ(W8(=-H8JktO=yn~z$p6B5NgkzqLzN1Vbgvl)w zOvC0g^xr@ECg-Jw)2Rel&!$R6gxa@nV<&Ijw}iDPK5e^g4BUmE3ham9?Bkkqk%yjw zb3$r^z%19j)kwJ)xAt8nLwDjr2+9kTn;8sdb}vsHHF}aekC7h=u{OKY2jUm^)|f>TVDPs)1vWq;+=w%wW$mT;6hf|Z9-IL}yw9h%CoHFYo0WBw`le(U?g^{otsh zyw<{m@~}ZAorEBt+x};xTi$0^WXx_$g zoul`+r0r303so!UcXw- zu_8;6$eTa2eZuB5O}*9o;_}KSEl@CYjgKgpK}#=_TW?Gtr)KoR;^pKroi%B%ZaA(m zmCw!kV(|JnI!AtSAYH@GH||$*pmx-(F<`0$)x*c7rD`{I=rX@3L2{UCaG|WsxG#uf zt!36MD=ZX`#q&WhAw`i{oZa)8aBQDKYKcST?yVG6z01PWLphoJl%k{VQA3>K=VJ0l zmyKUiI+@^$yC!e8yr8k`?N_=!wc##9dQtACZ8RKjGsJ(UlhUnyu(oZz!|S;~_s&@h zo&9@JR1Ns%pcP@}F`~-OhBR!W zHXgWU_BY!tHY))00e}PScOw9OyO0>`UAtzruXZ)PVm7j4Bga*`fw}KZ8SqRSFu8<= zp$ewvlle38Ze11s;dy>uF~O<0N+LMLbDlcA^xtlp+hcE7Q4Y|)m7MS_OetB0njiv? zky8!GqQAn0?qu*O7?ETSs_-LCprq%&bB^|h~du)G& zh2TRCEl3TtMz6y#k8@tfmK6xOss{xfn+{zz{3;!wDyv9v+nbY8t{|B_|AC7T%R>NE zi?zm;6)A&a(c^N;(5}yVCMJxFgic(>s|Yo17bgY;i*=1j9euV;4L7Q2(XS7HW)L`0 zG0askUrIXa@CQl}^N_r=E#Lr-XzdczwUs#3q}51aFg(;jXVl}h$<9E9M?z}udm@fTWCM8bFwXTPqt_){~1ZV|jM#Z*(BrgS? z2($)Jaf`1cUky^M16{^zYUkJ*+YVW;T+*vgNf6b+=)m$K^T<7^k8xXQ914IME7 zSusuSf0vrevK7FF1OQBAvZtA^1)7VIj9426qU12qA2(QoXan0b-ea!NEGg*s@;7wD zs7y|CvUjt@1fC)M;>U~vM;c5b6cl&=o7YQ@1t$j0L4L>p(4#_<-zUgG6AW6;pM?A= zwH1JI=60z6w6c45t&K2#MnixM^+ap3vov5J4(R(>t>0_zu?~!|B)hO=j#g^D<4-r! zcfguKU7d&#fErM|*ZYU0l1O?^qz?8iU^1R~XF$wdpq-XFgvKf00&k5C9g-bqYwSWS zUutN1$9Q;Bua6SlgU`6)TaX`SZh&(LTixfT1p8+R6$1hX+*=#uRp4xPp4a;u=PLWe zezvX*v?)~aMI3*^btLHURG-EUE`EsG-+McCI3EV+CFVj54DK1}2d6PNpbh|!O^T?m zPaaIJ`pt$c(~@Ba6l#oM?$T#sCQB>>wcyB;%;Z7~)M)?DmqEo#fENhADZ)(?lU)p` zyD|ap9#pd}Qkw(pI5qeqoDxRhl>|)c$HZ}3d1jSy!xABRM4AXV!nAA7HiRo`k`@Op zXvTqN&@WM6*%sJpQ8QZsIQ_mT0HL|q%}mM}bP|>28snPX&e73JlX>f{mLBZzOi=hk ztSLlXB}fKgezvvrC1N@V)yHwAf$Kx5NV4ZL zg?+i;AA3MzSJU7VsJ?kRZts6hh@c2(_dA^aVV4J!Zd3K+7e+%y;ie@SR;NI=rap{M z@jJgYutDW-YdG=5nK=+pg#FwN^+~BPA{bxpUKp}YRA%UZl}^dNpFSWo5x;oN{m8i^ z05M-!SJW}fyB8e>2W^ezzKmtIo?{QAaL@8AaZboYuO_9=_^iSK0EiaS8vU>rUpPGw-vY9 zdatv2k*8sWVIz|+yp<(&&_nATQ^Jkg`$C^Ft2eoy1pB09e872smZOHn!M{K-!Y6S8 z&hDPV0bKW=B%5*>^n7mW~H+yHqrDVQzUy}!!c z!N{tzMc*GEJ4Mc%dLd*I61Ou+6|QMG(#BM{tuI1w1`K<(GKc|+EK`X3J#5nfF*T&fE1Mk5x!u*+gzZV&%cJ>?5i$$o@e;b%K9Fc>ofJ)nuA zHi{27Dqek9+f{E)I^8ic+ zXM7*naL5YIgUf)y+psH2Y9>*eB#J<(08ufeNKo$u0v;%gGb&Yw-0aCh>dB$MqN0O} zdA#okhofn*0KQT|7!1(XMe|6LFGOkHHz6a?cml;>?MP`|Gkg`Jvw|Wm3AP)d{gAZ7 z1;D+4*9nr~&;6Fp1+(bEi{gjdq!e}aq1v~Vhcx3|HMAEWU;tTC?`+Z#yNa?7>6i}! z=z7vQm2bXaJxTI#kH`gPABUW6Ho@})#IN`x+^njY`kUeG1qwtl1ki|VA6Vaj?Mmc) z9KQA(%xemm_YkJR^ULWyoJ?GtBB|I#?+rolioc(|*b?vN*w)1`KKEeOFYm2fd}-YB(ZdG=qY{=N2IqZQPio zgyO7QjG`t}~A>eVuk%1jAa}>G)eL^4(|)L84KD z=zb7G&iZe4p^=^D1Vh67g^Np z%W;^myZdb!!x$6=)yhNKSvS^sa@|DsO<-R+*GCU{q&OnUEEo*Vng3 zA9z?IzOcwUMw%(GsZK%E8nnWiq|FR%$7vg(3StfZbrADMrn9-;qm^vJ@}Y~SUQsw8 zo$an%UR067myHI@g|(%11hUH4Z(ObpEb!=65Two(nO4c!AJfk+S0==x25(e9Z=|d* zCy6^}aIJHUYc;c9v#UA_Bxs0AXlJ61{J@34s%f|a`gtQl)pR9ByA(o<+PP?#EcM7e z<#`I{n5**6)!y$egVbY0IZdiTQ}9de^pD_Nllx9A)kY0tx3mY=7#>88tz{Hb#CT$B z*UEu#aSUza>19|ny*`_0y2D64ejQ(ZzssJUue+V^j~SK;%yjNP0;6P=LN^Wm(0quF zCET2L+j#+&r<6UTt`U~+-sVh<>5sN+_Vhq~Rr%Y+TuT}_;Es_HgI%3h+d0jZ*JH-M zhs(6>qtFK5?VIxEA%hyqLrnqV@Zoyf6vP&V_J!2u`g}ND^`{+v%~Ahru*=XTmJFz{ z5-MF`nEcN)rtLffdB9<6vdInLLGqy*W6&tserngv6ys%Vo?MM$h|nbo6i??o!PXLT zV6;_DUV9}QKz^*k7jyjdl3?OMVjp(!k3zkjxg{&(f?6-F^q!iK@k6SZZeIaL%yO&8 zJ`9dQ8E5__1KbLCnG$fE6 zz^nK0Ki5ws$+CL|qONp`3Sh|OIlmwCk!W-6g}w=ZZju7roVMJzZK>SX!4DS34D;{X z?HG37)Gy6X?P<@QpVrJda?O{fJQiB7){~?i<+xJ(B1zP@Lcerc2UjIJ5T9V4-FatV zof7?U8&4vuDbc~#YTs@O_zNq#?tK65R~>7((GspHxsELn7Amyt&-q&x&s8$Yk`6Qj zCfpit^YT6t9xWCRTcug-`HFPBshYj`d^24F?0I^-WWU) z(fAMTrWP!B0=7(d7pAkVy2Uy2`k(OtsfV=gq_x>)Mfbc5w~e~_s3S&q9Ifp|`BovY zdqu5YhKAE=SMSC9k|SK7UDqACAS>{w^lDw{6aFoZFIw!7UP+_7yvht5+*~z1Q?1S} z77f+lmc=qS*o&JR=~Qyy{RfwSIdm~iCY?NYM3N*8m~EXCpbr*!4kh`N>@AV5{(e+L zIZjkgVY@XJJTyE_fND`U?V-S;D6h=Rvolk3z9%K{&DnNN&r4=VXJ$kRxowyIR`O=u zH8l(ZiR%^^awa^?4|SS*PW3H^dzQUI*n)LE0E~dah-`WwJJw4_tj@iI&%*$y(?=iX zZD6o(=Oa7E*$?4ur~c;vl4F@zc8Ookq09P)LvNlC(EOk4m-<7bfG1BkpE9J9O^+t` zPr8A#i{B1yo{^mUj2H}2L7hy&O$feb^`p7~<2qS!_;n>}i~j!OglsIw)Mj@=o#y(W ziIP~aQOS@|f<#}DZfY8$V9M})gHyJM+jDwO705NE&cc9^$xCE$@hc@bKERQQRo?P} z=(&)`Fdltk1&$Z%I!Gv&?0=Q%`6ADaSYljmH`;d&fI$m$XkN z);iZv&|%-LZu*iZs(~PG5;VMZjjF4uGq_Nj8z8SsMSY>~uMq1LY8^OQC2$a3!n3CY z%i7^|;(%t^OI9zwWdWmB5sTy(;noBl&or=C+lQUbeO+vWP2W9TkbA8z_|7I?u;-_Z zQ0Kkm>+R`R2$9y9DE3`$JI z)>^Da!i{&8T7OsfJJDUtIYOYk+^4>`U>ibH>9>H18MsQ(;D^Gz7 z{&M0sJ+9(zpnr&s3)-~vvCN8n-ns64yiD-D))e`)OwY8%dzr1z#xTpIhs2;NW9MGd zbJy0;0XaiPXt_>O(hb7mZxPgB6vn?Bb;~Reidh&P@`q1tx`IdB9@9>iE=_l`T}cc3yL`8;g(c z!`=A%0-UHVDJJlPpX2d-^H6Au5$FW4gCQGTZm^Th;n3B14}5AhvEA@nUqJUB!@~R1 zv>@bnVYu4ANm&Do>9TR_*|WbMR(h6dk24g6{!&oWgQL%RV6Uu<>kh^A;P&4!?4OTG z(QR4)fcWwM7sEQ5xH($!}V{WZY`xc8IZ!2B~85zn`gz39mGtulp;$IDfK} zV)Mb7Ghs!Ic1i)K+>Uj`dohP+b}x^6N>??zo2-Y!I%%z5&qwLel@f^`qKytIv;(c$ zvnlLzf*i^vFon0PW{afyY9+{ztyaB1{&+{(#I&obGZAHl$X1Gtx*9st#CwZ2Ex<}c z)kIBI<<}l&AE#8rFcD>fNjnlmfka0^I|6REUmVxy)~4ZF)CpqlD7>YArlpUFeP_0r~Ih1G>C@ree2Z{(o$veNXXAQo@6XrE)l)6M9}cP1C`T}3Zy zWiZ5z|mr@m5fraWaDU1U-6kH?8KR=P+0JyKqLCejKX^JIjoRzb)-r5s|8qT;|zE+8) z4pAx~z}r3Op4`?70k_uvclD-mOki;(t;0t^Up$ zdU=ajy2K*>3p1IHi-7p5P3g82Mrzz} zV|6Mj950kiQZYT?Th#fUL8y+{mMM76=Nyu;F&mznQ^N(;d*o5292VUEuo@_vs%{A< zcNiG0ZFCulD0jYYAJ9Dg@16+G+E1Aw@o);*uTZ zd>i~dW1Z1k4STLZSY&7i3&yR`f6nMS(vuX)(d2@m{AQJOH{!r5kvQ6U(~A^nvn$|! zi*=JGxx2|q&?cwNxw6l8iEHQiOgD3wOD%qw2J>|#4HxB4$cvcd{;4V?R1#oT0=Pv& zb#V->zD^Y2&M3A+7UFRLII$Gu_|o)N@+O+dqj8Y5B{sqfR#bcr4;IHS%a?KSkd79d zWv*X++EUE`gr4PIs*DUCj&YZQMr6NXE)9Y9Q*9! z2Q6+j+)1AQ!h(B40hy4`O6EI}Tyi?%?0`Drj1zfPfv6c?-0VpQ%^hMYv#}{h^Tr6f z)tvztR#?p|K8i(+f<*-n`Z<8r*vVaTXaIB3KQmWyW^ z3w<1D{*-iN;*}u+E@D*Qt%0!_RPuRs0`fyh$PitmzbdLelo<@0I+`sQepMBLwc_P07c{P z++tA$_Z8N_3Jv=}Lz!qg5#ieK@)ZF!F0E;LjnV30!2?K1x;Ag1t zkcm!U2<#$wUG1!7onh=P{(@it+UF5Z2(w{`314PBz7ZSNaF`f~)jSwwMf;eF-?)F| z-K4&oT%{Ej@37!nv-YgV)zP=GW6!nyc^e)2-C2n_{i7u1ZDdQ@|y@^idjn0mBT|mSPCIET5c=Bj%d<=#s~De#H)t# z>a{CzhmA6+v^vG#1qC`!wd6)`UH^_$seNeah^l<_=-xbwAY0lJZB_cAdRM3C8f5J& znqTU9grUfa04GfF%>&yEaA+iELhLw{;#Km8&bIXZ+o?E$tY25!FDHa9fx*x{$_jK)k>q@1aV*KGYtJRNP-G01;P*? z`x3SaGZrOBptZsikNcM!MlM08v^LZ#8O@KB7m_2ouoTgSWkJ!|%Vi>BN*Nsnq%>`| zUGg)E&AK4z!|9cWRzaPc1#h1#YzIQyUd)#zEHz)MmlXZ)HP-YTZ6#ape2$QE@D)fy z0zv)b{PqoETW77j6Zue3_%I>7g))d!b#lp!kH@jAc;lw~gktOAJbK6ByI+k~EQ}T$isoIBOxU|QOIk-sk!sQ-(Pcvo2#*_{57Ip?*(8;6PG{V`zga+=@z;j)Bwezr$x#@>wNYniVWTD5em&2vGZbmaLe{KCe? zn@ha3I8#>OMs(j6K(413>cYm_gI%ku=V)3Lfm*}eyQqZ3#3NO6@(-}T>NXEdX(c(d z4Mv=GW&(9IS;uC2wyC@(yiizb46H7t<4y@VKD?N`>quTv7^|25kC)TF!M{T2sjjw#yJB`{HH2J)2v@R3jM7W|TJcMBVzHqGL{Hly0;Q-fLbU3owU! zwGiv0kdPQJw}XYP1QrffK1}ho9`UBlPFR>EOfSV@c_k2#>H;FcfdyZucoUQN>|-X! z9PeAF?#XzKBah>uLdTo+%ZVDN)OE121BPPQ)-k$A9dkt5s9};M${a0>2@<{U6zpfPv%6E1mayFD~EIOE+J4*pO-m=5S zsjDYX+kV71W{uouTgcmhyMK2v+ka;-cjH!@-9{iM?t>V=`e2L?y#i51ZgD2jpB9Gh zamX>3&EPVNXu$y-_hh)52YQu&DYXPT508EVF7Fli?G;g7j+;t>XSYtu8kU9H*A(^j zx;TU52hceA6#R@{nD!&toTK0Me~puh7Wu!g!pGPj(}&P|9o@p6D`vcG|E9Zt=vQRT+<*_RpIx@DCN<#8_+C&MtwYF4;J5rU7 zJ%Mo+Uy;-!mo49}qs&B#QY-oZ2-%7UNoN4Y+T`3ogvPho2i(C-(U<~-g}Am?;f2xS z6t}yF87LAQu1iJ3!qT&E81X#fAV8L^>vimS#DDgHR`ILKM{5<#{$cD{Ve~Zn@5?H+usY zu%dAA(}-1o-BHlmTu-`Pfs?1XZkP5;brop|vkShKP<-w@gqT_)IGA>%_U=0U!Z4?| zdbU9$82o=5pI}i(B}6L(>U&1zV1%|$C_El!T`0F_(MmPVh@DbaApnR`#R?Vau}_gC zC-03Jq!?tLfTe-Z69J-9&_&ht8QOVJLTG?7ida`X-YixA6#4h%9t-^lP>e!e_&C(ov)6skTfOY<@~;u7JW`3x)AE5>7F5XTOy=kAfSR>Rr8@&=3w7}>O(#m~0lB-gCmQDGC$or`Z z(o82^E&R7bJXN$=1F~2BUU4m?$tr!}rp$|hEfE|+@vnXy=Qtu7*mwg)H?G2xF_h0+ z+j7hTm{}ELhtIr?!r_FF?RZmuBStg8;77_oJIM*FArW>?hmKqHKS>ie3+_Gn>?PFL zUi+i)EeGI}|GVlH-wB3*7Hyp_o}0HjDolGS1M1NqBFSlfYbmSlvfHj+QQTE*yF_(U zVF(CHc>0_y5))mqfj1L)sm8_na_%W)#VXTnQFP3`(pGsMH2uAn(lDKvz;5)`Jm|20 z`yGwymWkVDZX>2mg%>1exS<(=VojhRE0(E(RUBtRbMFZ7Gc49agj6aQ)tA!%Q*`sA zIF`G%@?673P$4~gCoNixEyc8zouJpUR}9XXBBYT6PghDTfk2n5d7a6b$ukG>aiKA< zfK_kOHwE0f8Q`HG=dCh-z?EqTkB4mkav~FR&!fo7?RwZvhJ*&fz5|nEpJj9wwNU`j z1_mU!YbE#Eh`QIfWqFIkl%V%0l7I|p3Kx_DYj-D-MBfKUSQz15rErkNhLPICL<27E z4D`Lg1Q%qNMNgR+uoIxx?Wd^_=rP$(${au~an5VeDtkcfs-i~$o}~xYP!lsh)q@ac<5#PkU`x&H z$E)I%Ho|+6|3Z_1+SZFy_l^0tHOsqmll_?~;)lS9L`V6zXO^N0w3?Ep{{-3Kq$&wX zxaWV{(>cn!R5|b9I8E-}-$7Vl^o&!X$c5<={M!F=#{r$`^pM)}&SbYm62>4m$Hhr4 z4KEFx9y`hPV0VPshjpFtmB9%H0-&g#EZ zg42kgJREUz@=_gi3FaR0#sAh2mV2Njl>3N*a9F-TLavLgv}NnNz6#AY0XgDrC0)*0 z5fkFZTn)en%?po^$kN5rX#D)3(Rh2OdE8@OH!#o{ywNcz!{CGH7$@>bN=}Y@jzf)F zX44(eiQcEbHa`g*2A;nV!wRjSA4y%vI)T>KjVz0>x~=S@h5FPe-3C_2V!RZcp09uE zRiD!tu&``Wv6c3a!PsjboaS@`&lA#aa&PZ*=Ao!<90AKU0+QCPPnvO#p# zBX!$~%_poahUcHoT$wTlr)1IN&s7p@TIdnzm*@_kOgCmc-p$g^%aLrPgQw1Me>-qw zr87%$<K^BiJ3cj*=$FC^|Lj_t|X zHgK^jefOP}maJVw#c&tG5}+D3de)nDqfld2 zTk(>v*L;C?6BNtM0Zazu*gA^aQF(XMr!cp*1NU`5m(L zuKe_d6A^(w+`lAk0Wag(m)OTFbO~HgTh%Vp-(i&fNZ`5NEV871GW6RS5%}Z?=uSfDUb%&p)(@#QmAxmJkHI;T- zO=Up2Lf;uVp%qc|vY@3nH#sm?i=FGkl{a&6<3DVj)0QAwkZsepompwywry0}wr$(C zZQHhO+wQuL=XU=>JnXS!#9VXP{h?P{o9ylap0L@R0Q^0HG~|+B<2jzqX_8_iAcKB4w@pWlH=?GNOgp<{9`QkMfP6q! z)t6o<&&0w7``mCQe~>)mcsf0vI{VAU8*s6$P4u_|CfRbJ$4K>h=gPLi!{(UrBEJ8} zuIw#w%q=U@y?(gsGRdsA(lUMYi*;=H!uJ3CSeHqs&Ms85|R;!yb z{+weW((XI9rEasXm&t=BerXfmY(nqi{L`a>kBHTJ7;6gALiTV6sQ1k-ur=LLUVKkO z>Tj#FbF@n)N`AFfX9{?MB9SnU5){jXx2%(PbU-!4E}9a}m3~{hp+|BpJ!RSw+s6sU zylQQ)oX!Fm1Ln4iRRKCW&V`8$pyC-7Z*!1{)1E*2+HuyfSo+EgqO3t2~%o8xz6; z`(PQ=oP8=ivcUQJ4T9TYkuPpBo@PY7B;5qYJaa^0I8+))XHu#y&;Y^?B90RVZ%`q7u=&WVQ88%wb zzN2QcYKas%y*8Y_*1Ym;J$Kx&F38|b`Wwgd{)O(k;PBP%TTekAgHduOoH%p|5}VE` z6CO}lB@+0?UGi0d>-Q3~J3IoW^E;qe6W&Vfo=$#7x$by@UCOP7Us@7*`E#Qv-daD% z{yc+eSJZY>%$WyWDgb(W+b0GM83QfbgqmltPH)>>kSF+e9`<<-dH*C|jU5tp>W(m! zvO6p?Cb28%oU=Z13MvaCbI{rD~wTe49-013AwV6y9O|0zUVB=DPL52uNn70PbN`3*M=#cC7;-DL> ziA`e+8V(+Cz9lPKY2NH{B8H}+zA0&mH5!zG19e3_5Vv6&{LJqD+oc8hvOWU=xg%Z8 z5l;k^V>NI@tg6F3a3R7r-8dTR7|bLL;fZV4PCeaj^^~h5_-cU)b^sHH;2x)0q298V z3miMAuF$}4KH#_Wj{cXcWYd$m>`*mz05z6T0Du1;Hq`AEs#rr3eGRJGqZ77NoGU_X z@QBJBqwK1vg^$rWK(CQyD&~?W@`9l&(hJse23+_RZHZam*Zlz?ocWB>>ZVfo3!UrM zmI0{putx0@oiL?&clC~2<*G3o!06CwAsens3++&*pW^vh1)hV`_#P0WiVS_P7Hew- z=CA*6LBg8N4>4*~kb8IJ+^|j#1^02s3CE7vy^45&N-SNxYuHE_XrSVdY4HjC13E+= zi4_{-@s`ZRta|OEFl%?B>gGP6L!QCf`{!N&iLQvdc%3xb3u&G8ofmgrvL9&TU|a6J zko}{XcV@{FWP2k^8c?RLZf1^4rB66bqShtz+LUzvbUdQV#=wdSTEC4x#YK5pUcdgJ z8JB42Cn$ci#fPLyZ5*8 z7W2tpKAyl0cpi(Opc5|*bnj2VZ=q-@`klWRavUZ-xsx|hnOf7+fwo4$a3%fBBpk8> z#-6M(p7hgjGTimKPky3GJ+Cgx__ck)_DN*}k_v28{OqNQO6&ov_}1C{^cts6)khs< zVgHly(6z*}WhSoXH+f6J{u7SSt+!_4XNQ?=a|g z;lhD&YmB^OHEksAv0%tvn~rpLwDs)H1{+umP)V!*)wSD_b__edwcpJPX7NeG$0=uo zhm|_6kMKj}vE+8yBCN*6PUsk9si(EJ^E6qBZP3idl1c6@dwO8S`aB4<1$Y2W+^2W9 zuux)%4?MJIuWDaKla{^d7STB>06aft=tuG``c#zi9MvU3(qN@N zyEwe{HdR666UWmOQ5?%=ZXv+_{vBy9Q-0Nq^ngZqr4CFcuqS3xdY;|13YPpVVbxrH zC^`xC$hvwB4Q2(&?c2-?PwR@RmrZpwxw2bxTFlF<;k`ni@XmWWuRsPB#BDuF^)T2( zqwt9m;s-H|*lAs5Uz_g*CO*9raO2wU9-czId1x);tn(9)a!waurlF9t{8-hgY^46se08Z@$0-wo;r>E|qJUi10WKeBaD*fs<}&n9`$K3l zO`fEDc$^pLK6QC5W#>uCg(>9$l{Fr5A)i%7Z z;dD1G+)CI`bM4vMrTK69Uw#I##NKRmgAwiMK|6I|`#t*3Qc?xR#4Gs^7&s0-(m$1j zK+MX#gRn~O3iwoV1JUB_>+V{H1#FD|mH-U^GMBpB_JoG;v0hcI5%!}wNw~w5dYp;w zna~rK3Hw6))>_GLj-(sz^@!)>p^Qxou-+d6Ar1tF>GA?ccxPK^waX^CI6ZXsjvdac zr*O~Af7^Jxrw#r1m4uc=@rX&DF`r z)S9Z{37iYPY6>7rc}oyGwI7Rqy4cfnxt0N(i;YClIBcz zz#nHYDc)5MSVqsh+bK5tOvkZI9( zH=Q4LfSQMln?-*x1JQH)I zA}kl9H^OwKqpNM=t z3EV0`&(57HoT;@DwQrMa@69^9M${j)(MJw@J}?AUWYi?8+{be5GFfM@<~^;Ig~LuQSzq63(9tgi$alg@1vU(opIe)YvFIEdt51__;7n6Y%P0Q zZC|Gs)m9M&W1K6`M{%gG{A{07y_{_)%F%GS+$N`-bP2#&k{mavvA%e1#=VcR0kTsP zqGa1^tBD2m=BS7{BR8H6e00QT*!m6_6wfIf+x3n)(~qoLNPws)yIbYmsS~0q0NYoT zVI80at-zh#CBWXLXd~*;u#Lll6>CV5e3;L%lKJ^t^$D!8a-zwOxdqrUcPU_;70Ov$ z1)Mu&`5r>y-e-5v1T4^N0Q*|H=WYk2$eo3|q@2peW*e#Lz!EA}qYMCx25k;78q@M8Eb2X%88{Tj` zEf-*nXE-?|N!wGKP!h?L&xh-$vyx<-K}|T8k=Te-ywCN#8Br!Xc$Y)oZWg(5g=dnB zWncoDv82?9kh365IVF@eaf2NS#QGVa^o$sDrh)FLX^ce+F3`+vnT=px)1ZOmXHS3M z1N4{-%VPtx;5q2C-HghN^uE;VOq| z-HIxBG@CrGa}Ym^8!>Bfo@JRi8O0g`qp`1V;|6p~cynQ?OMQT?Sg)MqnP=s?uXHqi z7kuKjY257lf{H>G%ZxF(;D@+{On8&z%qub;VRk+uf)sEgkG+@D$5Snd^>N{h~o&2^R2D_ z>u-Px30S`UWDq$J@N)UR-ZW)@k>YVA5!($nQ8U$#70he8>h7(3vk%%1>GX9%^VBw)6JY|ire$Qte$Sac4=hz%h#P3 z93dNiXpX;eBdd0=RnBN1I$eC*%Snz$X8?3IM%x|@+Vu~ zU??;lH3BWt8inE-A!~GJTf#@}3sQ=n43OPF0uvLvwfb`5ku6u*flEJteBgbDpG)xT zEO9PPOPi4GCV7pf@k=TJPKVI}9?jZnUUf+auV`8P8mmKz6-=mh^zCx@RMd{*lY+Xs z1dW_LFfLwLf$v@TwGs791@(RfTgn|hxY7vQ>NT$yS?q+FeSFjRX_rD5tOP?N|<4pL&FEMr-3+* z+^!~kQD=)q?(35(V5}zLzlaj1=my(Kf-L*_lKLIQpEwsS+F#V!cIsnAwp1OhtbDU)+z=K`Id(X8BQB% zwiSzUFlUl2Yt$2_gEmfs%tg77VOY+Tm}w0tfYYY&l={H}ig@;m@;_V8hul9j9#Y`h zQS~IN*f6Fbn<1xXjIbbDCl9clg7l3dV+d9IifYqXN2ZL>dX8eRGnJC4(LaStm&{mNJ0x{Ee2X}NvnJ;yuOJ(U1j3NSXA!`3 zb?WKVW;u8XMo7Y|_g@uUsT~Wh7`9b73nJl7ORFJZey82Po^0q=CQCc{X}E6|Ex-6r z0hiL+JWlOmTDTXdYofA*MlCCfNq`?0n6RCed)+TZ zeKO(u*w88@4R%6C0fP5tJsqVbiAm~+jAH8QkuzQ2C!B!VxipJ*-ndy%e*2<+Z@z0? z3v43hqc|bC#^;9{9+(|5koyM>*EU=qniEern6a$<6=au6wwXFafM%-~mLaw==Hs!G zKdI;eQt3ikT1LE423E1g95-jD0E@%PPeWPE56J$_h!|3$$6D>`DO{7H#3F@bxn$_e zz1yI_);jb|J&Eor&d`(p)lW~jLA#F5t&WV=iBD@f$)coVVV-pszg17oI=4K$PJ`Aa z^SWMf`OXvwiu7lapW{Ee26=b&0+__DF+fR&U4b{zo}HNBxsEg?F}mv2*t+|(nBeSM z7@3mvieC*488$lA&Luq?)9~2JdZHJrgg`+GNX?avTqM2%P}zo*_Cr=IEuc1n*LnR^ z42%JC(O>jvpB?8Kh`#FFPOrk@JPLNj(V|Xn?;yfP(0tHJa~EHyq{blZWK-BX8k>={fxhwr)Q=v zuH0fC-TTYKV%jI;5SpNO&(K)o1MkCOsDtk0VL?Y;8X?$I=d`k*<0I9m&ogzP;4hm) zoR$EFo)rtT-Hh0%xXT=@(>Q*D+IwYcikRX@Bczt_O38`0{gi!rtR03pQ1TFEp)RePixt9xI)mnXPI$uGf_F6fuigExMxc>(#vo%10b6M z%d^ttMYD^cGQ;t4%Y2(f)}-E12)z&w9gPIehD7Ov5bqZq%0@z{xiJ~h5roG zJexiW4lQ|UYoh=XC}K4m{lrBI^y5fJi*mnWY?Y#uW4VVet%n-{L5Pa%uJ(kk2N;;o zo=oU3NvPJStlOs$#J-BJQ+W$pnF# ziqhf=vdv;%(16O<>>R-yoWxp^PaI4~OqjyqKwi**t|-K9zAH$hs}>6VRgaR59ux*`ErKA+9Y+>(x#)7MuA_t{e|3TXYNE1m4WObJLVOA#}&{Y z{Z@e_GHbf>QM4~5AeavZ;1i0ThA=tTV2?NX>j2(DmI$qF6v;q20_}kFJqR-H(XtHA z3GjKt3iSci^b%R#XunHc3;&Y4?~yv?7+E;q5CuR@wf>8JHif(f>PK8uSV-TtJpKt! z7yl?@Nw0fk9ryU?5^tC#GAwFRkRx`*F*F+Haovp(?OpE`ZrC;VE@~?21N8U=MIS-z zU&#Lg;ZU*IL|RY)05n7Z02u%EayZ%AS{WHT85=tNGjnWfoZDb?ApO*q5**-f3l@dY zjEcdy`9<-J7_HhzHJdW{sUnowNE&PrdXA^SgSh8;N4qzaQ#Qa$J|wUAQ>*$_-5Au5 zalWabb`RIk%K2XBPAZdAec&_YOL8O+;MBu|%AFSQiMMcRT?wPZi_V;oU|Ze7d<0(i zvv%e{zeuQ8tCQM@)I@?xn-uRw>J8Zb`f~(oXEl!URwy3Pn?YH-Q8ZsTm59=Q&-(E(OaQPL|$TfwG-@c~M0LU%#yNrgoqh+L+KQA2ke# zT@Is(&cf)fNnXjl7Sl(ZrpD}?J25hV2Br|wj5aFoW~BYZ40p2|v@l<#i3o>#Sp89H zw%}>Wyc&QwvmYYWJmu#+Y)938sfByY{ei#Yd>84j+IM#7rgmWHnu9{=?=8fu3?rxy zH4rN#%FxOPEz}gBH&p6Y#-yHGBg9+Dysj_Xea(y%-QIth*Aq@0_NI(T7&c`@NAKVk z`oo7=s9!CmkG60CL+F&b+_F}VrYb@ro!VlgSU(BB%Ex4#_GA=KE5$o5!ZQjHMm~(S zY*w`4bk>wMrhO2nq)Ke#P{Gt66T8kDWT*-*b3hiY)J@)oXv0YUHE2Jy)6%`L08mt* zbm97?*G6&|P1FEHbokusW7uV++bc4zoC!)tb?>Y`O#6}8*)Dx5ZC0XA|%^P^I|_S(N0g;5Y>oXe2d~ZF!zF{24FDzqbB9Hvm%1SN!dI#}i-tjn~>I;lB0 zIB4H|ykr3&F27j*(SlGjcGn@DD2c@F$w=b#CMabXxdc66TO0)8Rscy6mmYu)7C{s6 zPnRvTI5OSxyjE+_=tz)7A-g0Y|NT5AVf#65ElyI#4M5h?fk)IVI~J572$6tCwuOj1 zRjH1#V3-X|x@NUzvKrNcx5eMLIjb(k&b-k23a8E6kzhyE;Y>L#D)U%V!RbknAG3#- zLw$;Kvw2NC+v1Dl#dC*NCiz76v++$35L-&p3vP@Ry6GASdZ9Y2=#QiYb8Lgh5C4i8 zStW=tdr;({q!-Y#qo}%)-(3E?7prB<8~f>k8nQD^DrJqeOj8y%KG5MFh&2N>H=T&A zRCN*cmOc2e)K(-(lwS5D{ZQFNk|#Y%Uq618Zxe)Jrl+!M9Gol5>C)LN&Irou99J6* z^JmC2FoB0O1y4GSd~_=|b|=XSI&K~7K9__+qq=rwIHql92RIhf&Ce2rP$MF08i1~m zw`$1=lShvg>q>I~-?_Jtig4#BH`SxpGWqN{&E&iW^otc5XrLyUJryiJ=`!_$vxCFo zU0&gurYn~UAQAls?3G9Hd{HP0)~GYkl8(?HBZ@~DT^e2LLWRmyzY;7}o%4Fbx@^!W zmE-$njffKdfZ{sMK@G^|{(H&qL<>+%qxB~sfm1;$n=2jh0yb{uut70RjE1$>CWae= z-k#+3GNoqU51GF7hA?bw>wVUfuDUC@hO@tPk5Tt9Jy&pkfs)eVwG^`q-2(O@&OGrY z@?O+`ifQs*%_Sn|4{RjVau~Bs{iS~7>3ViT)gYQT4EDh-P0`Ci=}yOkwET55fBa@YxvFLfAiN{lJ*+@0o;K`%itK!ub5KM}kIX5? z4BGytHg1IZe7Ed`6d?G*cwnpL%MBGAMW#^Vv3_58rxKpw1-5#dh+e0l^5NYF1Rkft z5Y+eg$;cq_BAvLaS29#x@bPBCd?<esuSnr{yr*Q+G#|2^aTfLCvPRe z1P(?Hx?Sw+%a8RXwILI@4rs>$+sD@4+cbzd=ckL8olOh1p4vbX6JQkSq}>e9S6ia) zLv~Jqj){Rd(ll6NXt6b__Sa`y281Xv#QznzB(6#gIklUy1~itEf*bi;9>Bkp}#b}M*MQ+N}yc^CEPSQ+N}+%yL%2 zD+AlKxD|vhA7&Kf5|_VmI$lUz4_aIx(_UbOY#TDdX1i18SZ%un=eK@L$_f|4Kh)V$C1Qj-2fs?T@Hb%(a2 zW4IW^ZcfZBqCTdf3J`aQi$YBF#vnh)0nepn+NVU?)ay{gfOw>derNUMz#3XyNep~x zjKs;DD)BXqe#EfG2x(DcpEdGJK!*2c2ng%603JfBUm3FKA~H$mH3^a1v(K4SMnToi zQoxZw5%MyU&#s;7{1z0-hnP^mQsG*&W6WaWhm^J(ri-@rmk*6CYA_`%-u8F^dV#E# z7n?@c=UqY#u`Rb5dv1AP-k#T^9=n2#_~v=T2FRuNTp6uW8mkPvk*C|cIw*gyQpvn@ zj_57YqzXaLuatsVr{MYSd-eXb*OhID8$RB2Nfhu-4;!fL@D+6%n%{5jGv*f)gWVZ4 zXjro`>(h6u1_(X`e`h@?z}uDhTjgc}1Hy?sqAuo7Xwl6G#?YsFL85&B*+=OiiWccVAHFZV(2)l#kYqYf*VgaYchsw{^;gRj-|$mg-*3+T zAIsC)I_~<{XaK`fBe~Drm%+k+g;C!Yw_oyI&56gV;%IYHZWGt!tq&k@qlRxPi zE^7U~x1=Ma6z6zoFVmT?COdF?t=e7SRLKMyFas##<$;2Z;7l}$FoEZ8gkbch-mDi~ zj`Z1ETY^b{y7G(zP~_4YX}$2-lY;M#$d%9%{%ZO%ag>h*JmTsuRDi&VNoE-&v^$s* z45295!JLQ_oWn%mU|G-Y>O@9^Z>sO9RDjKl3J%pzJ+g;*z9H<*+L>%;QK%FTR%BVT zf6xR)OJZwN$Ipq6;wDXy8&NE(`RrJ)XemW63+^VVXz$?1F|m=DE;=p3(kC=QR53{$Dq~Qk_1xDUuQqFS-Hb1rF!K1M0~%*^@>=c!SzV|stisZ|kHr7)HgJ<&g>;1t01y!g0D$|yhi`84 zFCS{>@NXw@_&5J+9?Qf{)`Zr!g;Tuoo?@U-PqrpDtFa~(OSbC zm2uMjVNg$(uobSKH}kurD@4zD{1}mjZI!F@#7AF!HLe+-BjcRuPO1CDy zzzMa^BBM)Y%KcsL$^v344Nw|Yh4iZRl9?5i1XG0!Ww8`{yvH;Z4yubNk@a{Ijp0b4 z{(W7)WORA66do}0B?7s?Mw$3q4Gf!$3R*Xe1|#3GNGMGscT|0{*ZdTpO z!$0FK)RgPVe$6wBNyr|>KxmIL%B3nR5De=N1JoX>DD(5wZjg$FK9HRL#%lb>-bKe67yc=q1~)j{qvDwoM{q z`9lcx?8Jqdg2B@L{S-oYOvXu-n_BG-8ixcNk+Myppbv0=D}md)u+c0`LwLKNbE0Cj zO0sY6V3WqJPLYB&V=#ODeM-PmZ)>Cv<<+hl{kl${pVzeSJEDnE`J~^;K5D0M1wK5E z$$}G-j*N-vey!|&t-Ko;a!fGE{XdQ8UO=)6gJEnhlND zlCRPiQznxiYv%q&9f%34yE}s9%O~-%lss73uYGV`E|!;eL#MWKeeov2WTbbJVrPkk z-HWXzexz~Payf>mM(sgSp8kY>I72SQG3a*CdE`L+i`)u zf6=tEiqS5;6=vAX65W{vns_sN_Bq_39eQ#nebEjCXP7-S`%1cEG69Tvm_EdAgBg6~ z-qw|EP3Pm>FA1L=LYtL$7draa^vIo{P{zk8vYrsO#!pE$YmyUh@r$SHRHpT*WUdWuzbUaTPlX|kV0Mg~Ho}7JW$KSz0;zi?|CapiD z`xh9Jj{D5NeFas1xI*gLtIPQ{l2vPU>U#03!x^DtG~deA*#%I(x~K|mfZl*COGF+H zj^IIsCT#=I{>qW#&ZQ`OAmEeWE6VC<2XUiXyfl%`c*2cNo4|i~{D7O9Zc)(0iiBE7 z$sH>jF){iX0uKPLtruYWX@G!-`nadpLLsA}QCY;{9O9Ed>S^I^QfKtzWH5qYw?Bf$utzxKi*_= z?5pE~E0&2ujhENx`713vbnCkJ&20}06Pw~s$C(Eeis zYiYg#6_J;^WI*}*CgaRGc6--P@x5;Rvqld^e%)k$2vs@lzj&6eY$PqP22pX`?WIi-uqXW8!0 z%OYA7CXoKZO|!E4!j82k3u^4X$E2dOgjJZ&5@#D)a#8D)e5jI=)#fS#fG9Fk;;-86>stP0RVPB7U0@& zof7v%K`qm&GGJ!74U}8Kp%=02vwcLGr?!ev`zDbNk+R;{OJ9JBC`SDhrzLS#ID>^9v#O{P==NeFGeFO0-VNYuy0yz_ zI~edLEk-{~+Lxj(dOSY~c#sUM2QQ#RcZZ*+&G7rA-qXtt!p9&SJ>)H_DzZjaKNV%^ zjxvwbz61gWc_(C{eg+6rB5pb;9Xz|nENgu)usX;m27&2>0or&TmB3b>TpECvJRo2^ zTpoy=159CsTI4nKLa@VrRstnNXElXD!mUU7t1wls=p1I3QT;++%Lm*J!F03-{rwM= zeIl$d!0To^RitVltuY!8?TpQmawc56QZS5j>*5?Owf@Gdu!o=hLc;*Dvy-U(@z=S8 zO?ZLXif^{P7|P?o;tw)ng+yq}3t3ag&IMY!N_m@4xn)$XcmL#JhgFTv@~?WC5=Bf_ zd{V_+!N(JGjMG1|VsR<%mWWOC0NNZC`w^y>+q{%EqRlBck#?hn7%=ILB^0;qY5(3Dm)eLgWreZ0c!fPpCJm8oj%#`W72X7|LFijn5+r0{I~cQvN2q~H zD|zIqBFa%hom(Pp>%I_Sp-reRIrMuYG|A2y$Dg76{N9g#CwTvQIoCcj(@jZK4G;Ux zz4t-uabXH(IPdH5v(r9hP-etGtDg?(-Jtl29(N1vuWt$n10~_pojkgt+)tdMNY*7=SU-_@NU@5c0uSP@ z-Bp7^Q<@{p$dlmMi`I1GK$-75E03N({w%r(_CMh?(c5o9!77^L4Ifp)j>8K=`<`;t zIz4-AnyG<$WF(9z?YO1T%s{Q0YJkprOv5iTr*k+VDP1Klj^QD!lss~v2qU6X3_wejS{QUmE^|yhuGX8GD6DEG7>~zjjdLBsgp-jM$11SX z?}1KYkU$a-jjJ3{x2e>9@vNAQhUWBH%gXZ|~QE?=k;&MV69fi4I( zr_foy&~Tj(oY7`4SobQs6o{=FZzDp0I+rnyi+*5jgUa9^ziNp|7dV{+Hcf%Cz#BM+ zh2HXj)4bngUQ-{GV)1^T!~MR2F{J2rw%1*fQfz5bfm|nR$=`O*BU|onDZoanyJn{u zMOG8Zv(c2R5lu6{GDl1eY}CgItVM9)wr89k54+ArLcvIv7#wq{_W)R^zj;TPWuB1= zbk#x2ymWF93|>}G%8yOxHb>uY_~l*%UNPI{Rvsu%=kUVuufsOCluMZD82gpKr;v2} z>mgt5_P)a(oy8k@KgTRS?~}7~Xc{^4bi^7ZH(H9;SZUn&fO*->8Hp@INT%qu@1suZ zsFGQC7pAJWe^6^ZkH=wYf;QedU2J=cD2vU}C30c?ERbK5LT})zUmTOPkgZW**~VK) z{7xs5%P@12_7wpUOOVj%f&V~p7fg|cWxb&tVqCSn4y9Sp?$$Cr7u!dfD+Z`~5Z@<8M;DqGG;_xFOUdMdA=BzFF#I*ktl@LXQw^ipGF!@ZhsW!9M0~q zr!K%Gd6=|xcQJG~fXt4d!-JCP{`;OE7bH%ot=NK}POje!E%r`l@Or1IC) zB<0n#_gh$`pDtcDwQV(TP;3|7N8huyF!vGa4tMNATo-8Z>btRUe_=}JnLL<5w3mAW?bhg+Q zxuUFoD4%33<-Q6s!EQ7Y>q|%a-E6pmbarQd&gVeQWuXGrvQxgeEp~bMVU9~Y$uma}i?o??Cj>Js^jjJ{n9qKWq%oQm z-jJoQOmt3hseTcnz%(=}$QILI-Z9H?ErBUBb(-}98M;z(a~*68f%vc7(!bzuSv2IP zo1)N1<{{bj355Ip0Y(`%~DC>)SY^C9p|*ymv*dva7n)J-Lou zJ5x%XORfnAIs?x9`djc~;~cfE0e5Scqs8+Xj=S01cjYeu2 z!lG<$sIc*}8Q5W`o-}xxdm%`MXg*j@ga;;76Q-%BABDzq=(%$#fpg(q4Lxnyx)t^E z3GY1*!jtZ6!?n33ye=!(mk;jWSw24!vNLx8$@GlN>gT91vZ;Dl>^?hc?}8(=ZIMZi zc7~dY3)49Uyqawt4#?yTopdJ7Ll}x6;w*qi1>FIyDmtvSab3)a`ldI}SGhxyBC`w{ z{pMTzi4{&Z@UN21f-jsq#V})t0jJkopB9VUM!i32m2rc&?`o0BI?!vt32Vf(K*>Uv zv4(qfT0-rwA0RE;3i*NLg;$y`&yhPa*~5DACYD?2w_=Fg66?VqFx$RAIRpxs=|sR} zDiQ~;aXPGA=jCR6j@1f(`MIz&0emmh6tS&sDJ)!o zMeum9Fwv+iU?XgX<||H~^fb7c#fwwwR6Z+eT&m3wM7w{Ftl4)=66{j>IF zF`^$rKi;#Pw8@`Ca=xs)q(y#I&3Rndy$W&VvM#obQ7se>M0N~W7e%cjt`eTO|29zS6_#jHa?p92NkV6Dd3?MKIWIImSuun@_b@oKkNMZ4TsO^-e+59{J z=KFNL&4GoN!fM=jH_a%y5hg$ipKCh}Remb85AH`)s&a!pr|4-0hm}*2C8g1tOu|P< zg=rp=kl{MDN)mq{t_ZTrh;ZeuNd0g2!mu2i1X`ZmCjb zcG;s)p5V}0PJ2#ukVk!of{G0q*Va+yVr+ajA#y+-eOm+!GA*R=%~c-t>z-sl7NBPQ zlLX02PDNS+AwFJIG@K4Rh|;tNIPep;z*WgSZFLT-t<^x;(GS9B08gQ0BjQIM!expS z_iz`XaM+AG@kGs8w4cvgoF9$@?K+f=TB;pC1|1!aP25I8v-{vceX^uC+GPTs_oavy z5q*rbjKfV?_V;*7JwnfrUnF2KYOw&Q@RNQLpwUVX3zkGI6o;8er_ewu(~a1ivR^%K zJOl~!*LTwAL?K+F=+;VJ~PK!j*7i5OfDadSmU zX>=o?YlL<7(*UESr9+!h3d6`0@nuu}fdp^;-k_X{O9)}Trgv67J^);~IqB=p-A3pZ z_T0wO)e)hFTu-2UoML8`szT#v64!%p4> zsX0QwpDxE)HaQpXPv$(JWlsclOr2+ujH$8_N@Ab*a(m~nm2rPsrdRql)-uB}!oiug z0JF3Jf^I1fZ!0Ni9Ru^6Mw^`x`kX|av)(br@2tw~cpRyDVF;#w5z`T=;nL>5296E{}+m=i415!HroXr(B^Iyx% zh;0oeHlBna(tm2LEzR<4(J-^}A{kQ|3B z2Nm!=9KU@&cB)7JR7o`gWyxC$^uwEj#F6%Xhe)jUrn~*E#v}ZGmO?zQg^T7~k=XpX z_9*P@`ksh(U(LinIS8o{--~T?!EObnDX$?%$LwL$3abvAP!I6e$z+JpR1N_=tpzcYQa{RZxXA6m0Rvq8><{+H6&cp*KbsTbKDW0XUpUt= z!1k)$Fk4-`>PR`QUGOBOqE=rje(TeLodHU`dU7G0!obdF*yAj8p!iW=xYGu}mgbe- zlT(&-E_inEKEo)tPP}c?^h`|OUbf;IZ3MY2-PK%W2NlHL)K#>k)|%(r=46IRXMP_X zA6c$x6lnGkQx64pwJF~^1)Var<9B~$HHbm@O14}2y&aC2H8rgMd467VZWQg&TIc3- zC2WZ)*W<{S(H9!7V(J9>*`mR99iO&mi1&qq|Jit*BvVaA8D8XF&x^8?6MLfGT~cSQ zJ+8QMxW#n=jwb!OP&Bq+!Yg)8q!|^px8Gq=K<(OD=cLCLP*UlQ0d$4QVW|nd#`^Qb zXdVnuG(az{MZ?-mH(Wn;j$St*UyvRJ(wX$ItBRDGn7+tmLIs1ok)txq9A2t?A!`Sp zF3e+UW6gKEVwzhTvk z4F9XEnDH{k8^6Jgzw9bye}El0LN(J*_#6jem4Gh8l6l`g&ygh+V ziuoSJKWD6%VXnI-njYR3#;Bx#X#A<|0xcvy#STATe_xYJyq)XPdCh@tIxf4dY ziBuP= z`WXYF(emjEWs9jM^jAmM)^^A zzNZY7!TY&<9(Wh}hwy87XhJOjo6ISDPxm2i5B(ys=ShXW^&My;+LJmV+FyObnNN#C(B?4 zE>Y)TB^`KegYb>+CLb&ncjJ!HRm(q_OQnU3KMrX_wFa)Q;1~42XF{tP9L@s-001FT z008{|^GxVq>uC2695lDJ`G4#nj^+Q*^-V#V1>Kfq+f`k*ZQHhOSC?(u)n(hZZS+^R zZFBm+F%NTR?&OI$Zzm(;MC8uBSMIe|{Kn|r$5)iyXCN9is?je4l1`Q=2Kh0WdT!{Jhs#HCdaAM40fr%9gw``XSbK)XJ@u!bfrI*0P& z3gT9i;&n9e>&74G^P!J7%>R3mzEVDgan<%B%w0?`2lx`uX{n`tkMUho6^E%d#ZBlp zv_WiA)jNrllrH9On2OXfuBFjbT8CAKPz{tc(~5k{Fkku0Lo$yKf*PfOer{G>uE)r# z^SrAU*=jNh{&oRa{GZlm&a=b6^-&> zs*QZ@$$j(5^BUqRWQX^{Y53>2c;X8lKb0t|k4z2~w~pi3aRW3Ccn5^ziz)6KBsy63v5PK=LD_`L*~18K8u+{RafP< z#?D`YvtfB`ryRz#3StkT6v!J#k=!3T3m$>FEht76$A=7~Yh(z5v?xD{j>t{ZH zZaRn-h$rABTKCJZR!-Qr>k>zk@Uz+qRS5o#!p@zEH>VJf-L(rnX*#`~Qlq;AJ%{67 z)>aIBgNP?P2c5<(Rrl*-#`FEL>Y;2$xBGqUGG;)*(hM)^5O%z;E=y=7B|vZTuCR9( zU^nLg4ldA`nKXds0Ciex8C_di`6|!Hm7I0+)U?8)?qX~3Lf9W`h+a)>&$xD%JfvEc+p2kb5pG^syT6p>La@w$4GQEQ|N(M$7 zA?T&U#)88J!wiSp0}+gPt)>R`uZ@$T&t+cPz^@Dqp<^l1W0a+ z-khWd*z2AQu2^z%MnxjdeBqwcFYtQ8EXQ_|HL>6PKJ2)tWv2VryoV?ULa#teZCh{;W;^6szu9o%M8 zKm`KeU#gi8aXOGu;*fcHs^JL_m!?PrKI;v%#D`7J$xPxVWSQMgTxRaxEW)iJ*lCH_Gj_L}2`4dhf02v!z)5-i3XmnzLC$-! z&AMrsCRi`!3kOOBS5Xt1g9yq6rPRpxtyMunP?07eFX2DMJVOmJivm!e-JjQnUPFpO zc~!P{YL%?cD~22g^@a4-nYV#G5tuMQtMOCU%u$dr$qy*Y(bem&j9X|IPb81x4sgOs zOQxvCnUo{xvdNp21g&)Ajs5buO?e{Tm8GDq$r?c7B2OckV#$(kEWt4{)*B5`+NHsa zGD92|l83uY!vV*pv>}D_n^lp?pO)0HRE^ma0NA4?gk9~@_Jn*1)usKV5}wwf-*&Yx z@*qrvakt3TBx!Vfoa5-Ems}0D=}t1kbzXeXr>4(MD8b6l%Mpr@Cfq_vj^~r%LItVN z0`GZA?m6YkDQedxBNk0ZgxH6Fx~Gfu;TDD?=qUg!)NEKZK!;EegjusCRC+*2mWy3J?5!Zeq z(u9neFD!3JD)My)B?@`SNisYH>+PCKS0|H@t`KzlT7(!WO>|hq)0U$coilJDSV@`! z;BI;ziRf%{FW!}fhlc~LK$8Q+vJj+nc@szE4@+H4zP@w0JBP6#vv3(&Tj*FyZij2RJnh@gBY@{4Y}L^rkX5DZ4+tk7l$96<;Ejr z$=2~)d9P8dq)`~+CJs>n7)o z*@{fp5aEK&k zHCu4H&`MFA*vhFX2Mf$j_HEr$XT0Nl z5!^3kuk>O5LMpi|ebD|FE1o<&>75w#Wj+DYEP$N=LPuRn+hzfK0BtI$D9FQXf zk4eO#l#GzG$K<84D%fuq5-P&@0G7DrQ66hvk4;7}xzr zD6UZcORr2=_f%6w)Um`wcycOu2GkX8F|N#A zQ)~AhUS=thrVeUw$qGQ{nIXmbxDN%w!yYTb*kUzpW!FSGMEYyv@*+(#zz}b@C!D1l zoGC28E`G4$O$Y=_arC64h>}0mhtu3*5te~E&RG{vH*PqM(I$QswVvG5FQ7sUb`PW* zj5;$I!zg+4o;*CWaHI(0@)oT!Zvg^lD@j*}MgRJ(z-+`09H;r@T-&GLoJK!o*Kp%7 zqLmO#{j0qxAly-qmNufxG`|Qg1K-6?S+qpY2UoHDmu|TEX&t_nl)?o%_Yq}2`@>dA8w4$qb{<*Uh9V>W2``RD* z{QlODZ-LnHvgKRMR_5|!l!%i1anB#co^QQ2k$peU% zAv?;@e#er~TTi0tc`C*-YJ}Hl&a*IG4XduZe169!OZ%FJi~FFlA9Y_<_9#(~KvSgs z9R=C0wreEtT0m^$iCH(R4d0*7th4c;9+)VB{`4H)F6Sic%B`%mUrRrkGw}DGZLan( zfR_MN$^n!@fx!38@ICZ7M(lvyDAW5&&Ldcb_Gym_yU0Q@!0hJ85l)w)07Uo+7-_4E zS9s#m+<+KfHe|q{ud`C7OD`lC9jPI2&q&o2Zk^clk*CtGN64iVU?ZXP?};2fZR=Q0 z_k;a8LD#8=vWxN3JN!_?)y|(T$D-Qp9BGd=AO32y{6b>d4U_al7ItdR0?-vh4RvUF zm!B)rQgO#-#LIdZHThf7$z%%&j$Ii)NFKx_rAI8AO61Fgkd;a9Jv92y`$_VR8Kzxd7t}C29d*ZglQc|ot^c{VYHjRv@k^K8-7N}_{ z&35|Mt*qJRE8dqH41%%RCsvQYKS8qgmVHj^FFc)!)U&rd9c7AUZKu$N)OxdMe6hqov~Iha&!8%IQ=Op=HBy zuIdibRf;U@H1>FRm#(BG>5hq3{-YxgA}}vhJguA3aY}cqrDXcuMEHw4ks^qZ+Q+K; z-n!c0Wc-<^k`i6sj<|~iivO+?SHvl09BkVCmLMr8Tur1&CutBL1+h2Sw)y1Ql2(w| zW-t8~;0~=KS<#S(_u)T9&a<^u_|mE&sA1`lKIQJz+4-Y;bOP6l;V2uJBguKxs5}T= zuP;n6xpIoezwQtg?ekC{ro#agU->T`Tx6B!=D`H}kob(5Dj44R#W5fx^}Ou&=BilE zQND}o$KSzLmQ)3{OL?1noj0w%E6Qr8620V>{H$dLx{OKs(^f&d!cGBZ>9RUCXNF;S6!_ZIXm>D?i`U{6l3No>F<6EF^{Qvkkb(wAOb-l zMZc68@(Vpj52P&WTECS_oaF$iv%0Zg{wXsZMxWsr ziao2RQ!ibxrX~|`(IyK%M!hF9H(Cj(GLLKy;$7$It?>d;s+z=+DzlcR4B3`rp#Rg$czAby$iFoD2Ub0lb zxr&HSW_xRTztQ+)Z{$}USBX151iM$uL`)a6|DG>xKp5!RjZ%&8YdkACzf|ZqWKCdB zzobRJAto`Nni|*iEWL;8*OhcL)YeDeBAQty?viN;Jn6#-s{3BoFzy~Gtvj6|)Y>%D zJKv_j)qLFkh1(umc*@oL6WGFn-(@MhZ6;P?c|soiDe$jT8K(Z|BBvXsapw7g_+Joj zWgGga24{%Q3;A+@fD*G!l4R`uSYpnT*JElxRpf-LCR2s`Nswg*ohEzTzXScO)Vk^j zmr@wUZ%|tZXqEPqsAfwS9JN97D-wDJ&jIcKSWC(|{6ec^H%ehldO+k%T-_jv+^rFs zdD+U%9dA$H7?VJYCq+(M5$>Unt21HcG@9ji>eA1PaqNlX?Yp@~Q$hyvHloyh=qR(G zhUCQFD9b;rzI0AJ$D~pQkBI}36>;xAii0skswwSqB3mjF;_Ws`A1JCCT!~OirOJu-KBo&zGZw{8L zN@0KNGfcL5*)}_L?Lb7l2``Z64z168(+}`}hewns`ub5ofq+sG{>LtAM+aw@f1c+i zX3qbyJfBgwv)N!o`o1=BN?08b+!H$&uRqjUcT3w?fM9nK3=cA+^w_glntjfLavHn4ITw)iZG?#)n<9*2?Z*J}N;O%wk@c8#3 z@E44&e_&>@?l0pj^bXWhQEnk;>U2sa=koK;7V@NH&#g_s3_+>tacJLeG41nS|1proHb(Jmqx(BFvmkub;TFw8Z2WYMu9 z)3FFvXIJ`Zyz0g0A@VK9&TU2{Sx447h45NjAwtQx9~6$NC1X!Tcb-Uw*05YzgJJa5 zqwlg{t*MX3cd<^r;yfxwG#7yToE1Pg|)u}`y_ zI3ujbH&)f3?>$p*?%PWq2)y9k=0yXF;BsXUm!^ArxE$~QI1 zg&R*2KI&ICiYSg&c4F{Zqm+qnG+YT7V7!hh7wi05KYKpOuxwsS1to$eT2(emT#pVL zCf$W+J|}yA(}jmwVW2Zszg>38KMcF-_lfmU?byhbHMb6dQA@p|kos2%9k#~t;FPyN zAhPXMV)jC;u*CE1~Aj2Uj+>0sUEciT~^AuX=sbmiTOz-e`134ie^2uA4t<; zv@MOzv|)sP>pc4d{rAn(-7{O21q%dJA_@eA{r_T(j=%qll<=R8glprl!FliP2cEbs z^gMdUwq*f&iN9zM`&cg*ZS(9HfC?2QJF-4m7@v}K9Q65;Mf5~SrkrM5;!STTbJ)#= z`%eHkFHwQO|Lf(>!AVj@D1L{|Dsx0h_Kk{b18gq}zb`{Tz(ZWWX@)P}K^@!k?(>kW zLsRKK7bY!i_#kZ|8t&PQOfDO+WS;?8Tx0|JU_ z3gnOo0d3kx|G9<(7*kM-ZD*8tHb88_lf2QtA`RO!i$dy4KS`@-QOZZpSdyfB(qY>N z`V4{#9~X@;J56Eji(KA8l5l(kIP-)SImSnRO)ttWJcfaaf|l4;q$BAa3BcbSw?sy4 zzlwJh{;*izz-&JL+bRW!i}7BmlC6xQ>HJRY>(%b-RqyN7_v=;U>(%7zRpslo(T~^D zuf7;La1YApaxvi@ntOoMOvXza$Kx9&>$zi{fl>j~kAX`L9q}`u>X4U=qA`%1y_GB!QJ1*Q(crP4PbS^% z(7~Iq&-@iF7l zMK{tgC8NTc z@`xXqEQIfv(;idwO=awO^?Gi_L}U`{nQ_-#WJ6SHLa1_r4!C0+zKoR^l|UEJ;0xIr z9B!eQ;2{D@S<|wvr&Zs5Rp{u$6@dBOC z1lF3hmJ|=?q&qj>DqQ7DLA7AXUq#`9l-rO(pkln)f zvHU*8%S{@Rxw%EoAmWPY=p`s~I{rWvO16Yh?|*tn8=^@F_8_?ZB~aonm8~o=&4M9j zMlt;E(*(zS4oUn#CO9crZR5y$>i3IOn82)9AY5nyRrHy+N#rgR;mOdg)eNZLttb+0 zl%2hBIB*s=SEY$3F>}{Y_~ikjC)>HNpLf8}QVE|NIOdg0#>#FN9y9>nf(Tt0M~mJ7 z>Yx$6%sJ6Oq1~M-j$S1u=3WPMag<@z*0PgU91#pgegWFN*yODFmK`nKkJjLEb*DZL zyTTPbuK)7(<`;7X^gtH-v`W=}K={2oT!u?U>G?Ogrf_dtIJoo?440wx`AzgeGEIK! zo^=b*$X~~QrmiG9g^&D=mP&9*A>71CP|{`aCIzMhkU}3pV7_==e`}u&BwrK>l7mO) z0vDv{3S@14?bN7fw;7$cZj_4{!_os&^i$O~A*AF1pLfK#CzIl2jrZh8v}RamvRc?H zA6d#(W^>f_=Z)hq4H?43o0MH2=LOX_&%*L3WV6>Pv|MUv&q#lrOY zG!}U&pnf_NAVAYc`zeB#DU!~>wppJ> zz&yva{v%emYj}Sqx9tk`NOm)Rt4;K%)mE+$uOOAG>tVR@5xS#15Dtf^)^NIARy}i< zuu{K}tA|#`PNAMY)Ti^u)BEzbn_NI@=+Y%+QEp7OPb>0{zWk;EmB7#WQ=Mg>-l@@Z zpJIg8LTL1!>GdZZH%`(tJ2RC-y5AtON%>(npm>PypD|b)Inx!hI;;O1f zWRbGf?D?=Qz_HF9wJyJo&g0dZL!TgODbtun^L$JpF2X8XvBh;ThYK#$HJG0*-{%n+ zv)m;CqMN(Hjc9y3>{p9~a!!mYuDSHKfpuUjPa(I6iO-L0Q(v_*mx`ttd_JcV`Hz;v zsBa3nt?MqNx6Y<0-GR=hR#V9fr(K7TQ?`YI`x#bnhy^1`TM+$6Ojez^TmlMfJJ!F=FkBfYl{rtxVeCHf3*$|4q&} z-v*$~bAxB`YMN!p74Eob#whaMpp zkM25ip5TkeESM{Ov=P9;IvQMxSESN~Zw{!2e@1WNS=Z}ngL}5$J9kAn9PClB6XM&G zMxoND3$?AU$C>>xbm9gsvSc4v)o)fs?)AW|A;JB%r6Q3secEXg^;ae+&@EO*BmNJ# zf!tA+j7+mxzDq#jDAav2<+rgq#PkSD+-9VW)nX8ghs`EGEc4p@FpC#1Yy+>Lb)MSZ zTRdxf4cbbgfyxH3_1L)jaW&TSFC)3H(cR@Ejf;6}z*Qe~}8BB4p@TRwJ)Y*WfN6e{e`X!lxP@WOOJ$u_^OuZ=DhK2!8Hncq{Q z;<`vz2uNT5zB?Q0crf1Rhtl2hO~&-4KejmI+xGMJU=3utQEr=L)ulVMxj2Md*(tyb z*KGW&!uz$I*%{8ND1ES>Flm|1S?%xM6;G>f5aGQs`P3v z;En6uN0-wVwyiV_#JhHwl58jYkM^ExRxu_~CS3x;FTH3id7<4p#!P;X-Fr`LDM!`q znnrekHK%^@9Bp1%&*l-GVWr#UN?vGJKg`KZj`IZ^L#N0DD2v* zI7QOZW5qj^`_PY@FHz#EmL;f+ATkJxX#V(uSYoWSHHcEu^>&2s?#@>n*q=g5eCf!U zCu?>B9w2*9yVX4jOt=H^>!h?S` zaIlSbGu`^<&w6lx;jrMuKUQJKGSoto(kPM@`JtjAD_mgY7Lp7Vi#JY5d_(^C zjQ)X@fj0vj2DI@7_*9kWN8V;bNFXR9gz^fbdyKt~49cpLe}9!} zh2mU!rvfALXMQ+;1P?$4{kfGw%>}3nv ziwd69pjg_RG-`1W4W=-no;H0lKQJL|9n0&VT+bi5*DEUIfBcNt^T zzFG>;_3JEgMeM0JS7-L|qGMSi#b1ZHbj>=P+>L4A?Or8bjDI{fg>OS?Hx&%)W?st{Bt7PTkTRfycl( zfne&6+FRaO;pWIkoiK%sHFP@52H5MZhI=k`V?gtEBK})&wT|re7i@!rL7@(C~t^v zYugN6IW@MY-+t6F5qX5_U1%h(v&YIu1AfF?`{bRUjBgnspK5CZ-I#TEoTf&FpP{UK4 z2gm_Ub#A&sByC;LPYAj|h!q?Oj5rn7@(ZuPKIqp3tsekSK3OWph-e%t26{Ba@)yR%AQibXN1+>yg5S) zy=F0{NB!P57z4Sy-j{Y!8_ap=!!6dki&w_8t2RaL6>I<0s-R5K7GV_d{77oDlc+13 zmd%vlqd(2^0c0}PAYYQXgTy(^%TkW1)Od&RWv0{Gk6RDpTjg6Chv6%?pFE* zS!!Yn9B;lRbz-WybcKgs6X3(n+{cdb%Q5C68Fc*E1>*(0+Cnl z2l2m$^M9BO&_At?{~GxJ-gair4)(^bR<@=L#zrPKX7;B4r)UT0{{`=4v4oX>>H+}` z!~g^Rf4=_Tv-}rW+H>{$pD{V*`;J0jq664CJNQ~|&L6xP>sCPPMiExqmCXbnUzK{j z5K4++Fwid`G8-3Mr`%)SRo|p6f+sz2q?9d-^aZ;_K{a(X_5Tb%-Wd5E{vWF!HU7Ct z@(lqkQ?o3Fhid+qxRtX{>J9%)UcXyLFZCLSi_iPY*j#?Udl!Q5Hxn1PR51ZlIW_U< zOKzIVCm3o8yR=$-Ud?3yb*6lJmYa&jl2uCGvf7rom6p2Q`mx$t1oJ~BWg{0~V(9kY z=;~RFxd+cFGYqS&+302~W;JoXOi>E6?eC0bU6&536FW8ZN<$@wQfFMKzPXL+*6q2v z#qLA*i{>8c`#(Mp7=HW-C5Er}-s<-1_aBg0J)in)_Z!@K{5*k*)TgV>LC~I|VJxop>6u6laQXOrH&gB?Q{ znV-D`aYA#S?oFJYgXzfR*4)`m_ADSC$4J5 zdgte=p_UW|+wvTOd~Hjm>wh2MBF>m?%6?lenW;r{=t3JT&v>ot1GJpg(4(cm0RCI1 zDwd7DjA=zR%j|qhbA1+Vi1@tY=?hxFpXb^bO6R_x_t$n5^!s>8=L?Tj=L5?<8@2D+ z^?^UzTmkC!y3_YozL9cM_j96i@fTC0w58-zdF)zdC_O=u8^!5=w3wElQqbYDGszxM z)R#LUh|A3;nyMS3&^+IeKM21kjmyT7j_Xbfv^Gnyi_-`y!4shTyjAjA+43i=_jbR; z5{(#^-qS30$C_7xq|R|-F0Gy`z>h7KeL`)C>Btw>t}?L~NWJu0ZW;|ZxRCIJGw}Po z*!X-OzPFk%%T%%#Poa)6EY3e^JqnEnF!7}Vx1v6$wMnL7l7qF*ImUC0= z^w?~U!{!19VpSgwMCjx4gr}E`NV5`II1=#$;yI4S8at^>EG3q8?znkaC4O%=x6l(s z9w^2Qd3DJLM(%#H@4XnqhZ^WlE+_<#;P+#YNGyn6slnh<&=skDQ*};kRGn(60v4Ji z;(^lptty!zzB{y*bQeI(aXA+3mO+ZO*cCYBARHUZJHTOpD78Wq48=Ck@5zP#Nf>d& zuTy)u-JUKCWUWDdW&stOtU9YV?Xzox=;K_XUK#-91?=*71kl+br((OHKoNX=o&(|q zL@93CM}sxS>I`z_^YHrkvwHn~e?KeaCn|MEP$OE zUnP_`qx0lvb9+4FhQBiKv+?>uZxl{HrvCkYi`xsTFRzzezt3D6KbiSJ!`jNw)8VAF zEi@d08Cb(s_!`6WW6t#-8?-FFNJR8IprymYg#{%vi@bX`1fPD&00Kk4tj-W{0BPgg zxv%;v;kwI~-Y$JBWSVjP9Pn=8+0rB5E_zE%mRs8E&~~qZILqTlCf~?KLPbJ%>1tPV|D)AC{*B=i#PZ$KQGg*(JMh zhN-@u6L;F;x}i~ty`lFL^wIlys?`Sj%5){Ol>!U3(7=<#-#h0o&KNV*gj>^n$10c9 zI!DDsNL~Z`Sb%BXtM4|WXxjg@0-9&l0c;atj=bD?TOef}_4&$9TXH?dZ%;6q+}Uzg zYQ8`SSS2HJUK_hGGO1AbYE6js>a^{e$XRNjF=l6)aLz2j$)}LoCNNTkjPdxTK}d7c z^gYe}dmaTq^o(iQOTVoRQ7gTci3Rkp;0s&d#Yl^9;b%()@=YW@^bZs2@aK2v3F|E;%Z6c^dkI2S=h6SeWUPa|M#XP&~C`CD1# zerz74olrOqb8zO6%E-`nds`C+%po$%w&%82aB24A9buNv@`UjS#z>u)gZPrxjfp|@WVHt zNBHWNHpf4tK~8E;=%d+#_!TOr^>Rdha^U9Hpyk+!v6S!$ZzzJHeTk77IQ1`#%OL9` zOf_6;rK}fCR9Bh#gWf%ke?*%2UmE=%7gmmqE_?1@UH1RUciM~CF3ghb*Q4s-N>^r7 zr$5u&8opO7KP2ASY^y!C06WJ^z3h3~cKmpo$2T7vpS}iJeQoQXU%Tu-^E<}`@9Uqz zfMWuPwzslx_Mg8i$9dK4KdkLD0xxZEC%x=Hwk>Zb1$O*bWd&uvtdD;S3(A76PR|Jb zO=Mz_<=?#id62*^z$LBKCFQlTQ20jwc82|lwWtqW-I#SXFhyTmW4{8^gL`y+) z><7K!sS;pGy!IK9YkBrq)!+{P(ndkpeNS7)N!{IB$+6a6hT4ZN=ISz-8TRi;rGk}e z&(<)@IxZFr8IoQk-CNySpM22L7$RYxIV)L!sI+U* zE4fB$aPQYAw|P+b>(~iqj2D`1lM8pFe_^(fj`CI1fHIl#7eF9Oe7y>6_kDl-le6;p zT3JQ2ttL?x;KG&&4qre#8-wG44N^)DHjE4gAq7^mKV}TEY|yH)Cvo=!liw5IyresI zqvc>AlCq1=knCWP*73E8()y$>$2FpwY!_vhpJz{8wSb54B(=r!%4ZU0K9Sc(hxlWc z8)(~>fupVIc^`Z(w;VSbSgMpGUUvn7nsjFh+*Yby=dK1I8?5;kiz-eOb#k!Js|D|T zn$dN4W7b~Q*qPlepKy67%FHxh;2aH#+>b3s^j3yWO`#tjE+7yn1^ZS!aYi0oV%a5v z5{FTR3_Lt#7%=WLc?MZ@nrDmgQ>aLB%qGkVVU`B2vkmlOo@O3t56D!C>2l#6k4*Cx z0i8(UU*YXQD*&%x@Y~Fykk%+%Osh3>@a)KiZ5S+R@wWMrUczuC)~seh`{r>PVA<^C zEX$O|-(syC3c&p{YU;uYw^2;nI~qKyyvM&1!VCRq*=s#NsL0h2^hJT^FK|0ZK#;*5 zn4QiKtFSwE2D#U&5k(0SnF!}Z(?rtsWV)FH&((Xn6<`JIMHZm?!0;U8v5JEbmucdnz^@gMO>u^F!8_0Vkj zSmo;JSUKOv)G}f}uO3e;4%vjT^PlcVVB!kc8n%e_@kHg~df8yXkD!Erph9Kr!>TZ8 z3d#nVeCd5*)2+RFA*3llH>XENFYkys2^eUO-b8XH7^Zn{HEaHBFc=tx2+@IEd=q1R zdi%T^VUXf&HI&Xih;8GermT@pa_oQ)rZ^)0ILvpVd^N8c6k?O=>dIgtO!_`XlR8s^ zt(fSPAq=xtBxY6$p|5&bx?s&=OEM2N=N4?|S95zVb|{P3?5!lazj11>a|~G3^`e+@tpqTMJdWr_eUd`EOcmgN(8*i7&jd`f8pfGX*jXOnPd0~K*F;>C z#{Srhi|6uU?H%v-(x-A?g;}XZGZLOABjg-L+d*YxrFk~6uEtmu0X=GrK(zAr@-VrJ z1-g|Ov%v+hv%ywCY`+%zm|}yj_0x%BXmuti*W#-oYW+c%HPS%0*08Z1Z3m~T@)BDt zVPk``Bo1SIZqF4(i=7y32oOLXZ=evDyYj#2ek{_R$yBJQ{6KY>uqF%r_i~v?v7dvFOt9GF{7ukgs`gg`$kr<5eWz@y2YYD5(JN=mjUlExQor z*JfUHa6+t%-*&tuf4+wr= zmV0k33N>_FlEoW-i1oH0Bxp_NeA;yxZ$Qi z_k-y)VYyW5%HK&^dFlGAf02*-iYeG|r{m{()~wkI)`eAPj8tP#bRziE{l)-a{5fU7 zfQipT7JfE{chbKKcS5}CQ6>3@hKD#uSWz@=VEdr`FNeSlyV)()Pr?)HMW?pyF}9mt zb`3@KL1N}ktM(1%X^F(U#RpQ-iZTTr<9KWFE*I|p!agXUUBGx?(Vk=7LLG$rapJuT z&WM;7EFLhvSmPk|n3N+a#Fk^<>E2xTg4zD;$7+gN5E(IsH7NY+er*QOLydx6r=AQ1 zYCMIyodPR*$zV8j0`CP}tNE&^Afx#?b|H&hixvy&B!)d!quadzzySnM_R1M&VD8aH zm_a6=CJJh|O$JN%$!-7mC1N{YIclWHxqXEt5rxd>{`XrWMDI-k16u8T(e*5H!AFyx z-DRIB%p|*yu3O-*ZH{9utOHmAOyXoshLHWq*{<-Keg>3-SOFQ;{Dl||m`u&FILs7l8def|ojtK$?|()9uX(6F#V zM4hhp(S?ea<vW++}W@wM9rJsFD9O2Sm)H= zO_>GP)C`{SiWGXyh3xLpEX*)-PGZ$n7$Ty@;F*}T(LUQrBd;O6&d%b}k(fE)zl^XH z7w<7{{LJes!~~x#zpZ%=_K63&3RBPtg+CgqD}AZcrdMow6sdcu3`UoMqh+@5#`!7S zdAH|s*(Y(Vg^x2$yDFJ_TqmjBXEWG`hZFm*+`tPn%#x{~0r>zC6$5^o(q5LjD-bn{ znbP@MTXxDW%F3gB&qpZuF;OH?c4Mf7?w#G)e6Kpp0uQii0Ya$yuK0Cm6TMZ=pLa}< zPOP`9*fno%?X6k|lPk>lWWi&WMIrs^5~({c`%?P5JTeQy=j`qVt|XiSE*yWWNn|IJ zK)1_ah&(&XCrs#_1a}hpbNjEdJx1bmGr_HFuT&J5lM~H z;LC`W{e0F&SWgKy-jXTmHH!QP^TS|xO6PopO#1vG-SVI&qCMfHBIpDjOyg2SGu!~d za*oqT<=HCm@p%cR?yVnps{Oqaqes5XxPbBEeQsGa8syD|1oRAvCm-zi`MQ zHrR~8ns-*9qmy5_6jQ0A48=hYnl!X?@p^qqW2!vB|Yw792Sa#_e^GLA>1&cV2QQ`17 z^)-TUzK8rY-FGRs%!xtLnx#FA#RR9cPiS;F%dwj&Wd#l6d~5SxcQz<`gP?b({Sh~; zNp|raPO(ytCKVc-l>T#U7VRgn_iTgf|Fha&(Na#*J8VT?i>pv#tER#_woQbmEI+Lmb<|3-v%d zFo48+$r=tCg+v}hi4V^Sl1y}CO|h^+i-+ZpGR?4s4=-8VB1y^aJ66~Ofwdr$`sW>K zGJGXdM2tL!KCKThhXmuQ&!tQ9L(`qcmbclmP!co_T$UkY78VWB2)pR1?gc*sUOlm zXd@YARDw-~7lz`$(PS3J{|5m}-Z`0}q}TYb!(xQEUO0w98B4lh4)biz)MjADq*yRT zfs$43{U%J@${#DC)cBxK$w-`nl)x(~0L zMQTMnv4efTSVkNxux3&!2Ai1S^e$;5-}s*2mNis^aZ&f9sC6*!(=BN&#x$?c<{`cpeKZh@P zx-oG?Lg0v~rRRE8_kHzwwYR43hy3+VSBjL)u?+AD;($XfUy1cMpfE8zl7j~K zG_yFcr??0HRyB`#31GfeOh(`)4!y!ev5D&jmiZAoNb9zqH~B*@QSBFPMzog9)o%6S zs^d)}SvdpCz?nHk0>|X^=<`yeBBz75&*ysx_@vF${QX}Oqb=REf^xCK-Q(~^@H$+5 zrz~R4S)6_IMXd+Q12U#TIZy!%bWpIdoGFoGB#?AzUnxt1(te!?9%y3IhU)ZT!+e<< zH`I3Tl?&DE>E-u)^fQ7w;?v-!a88esjYSV*nC12q+y2S-Y4z3YN5qla7}#E*!2$8A zLF^z-kIrLv?4vq#>*J@rV32am7(D0?Nuy47!y1k?% z;VXNq4h5Cr+CW=4c%wp$Zwbo<&iMnA2Z;5EMMppUX+851Po5&}&>lEVHz0+6rk!l7 zRg)e>>8T%|rBvNynrsRZMEVwSz|W7BT{jrHEuh4H!&b1lQw|=R+Zee6NJsvHWk^m6 z;OI;-zqBAqJVG_mDoMlrlgF?&gR+z1>zZb)L*f>>w6FM#!ihQ^&~+VS+QQQ9JE58+ z+Hb2%ZHJBS5ru=tL6TTC&QL9?P{M;bqqJIz$WK?~07(u2sBZ$5{{?73m%s1ei`BnC zW65T{Ku3Gx;&f#V?8mve2Ih!{+|5y(UzSy!xjrb1{1QWxA4!l`*(ZMFbRFbWWOowB zOE%*sT-q~xt<;=XxP{5!PX#FP&=`jcBrhjI~9y! zLaGK4PEwrNC(g;-xMqT#g=bp~1W_uqRTL-Cx*xIxn{F+QD*$f0H!|hg@Ws@98{XFP zPHLkL^nbA)$;ZboiY4zeT+`%Ntx(7mdc1%2s(O56e7V{xfQaFGEbkN4S9RY*+G*WHa(FkyuXDwN;n_4qzT35|dOklLIz(L!F zhq&?P1iK4ttBNXEBXz!5WF-rbu&{1$ZWnngQg?7DteEm4ac|7XayiB5L6#)w0%^g} zEQz&=)Nn+!U_Ozj6laD_rIR)DN8S_YGIHUOpe36G<#xA?>SQc2*4W0@>6Y}scxk>LAObe7NFd+xkQB3Q=(L$8hln2h@SOQVeN8o$3qyfpqUd!vz z-RE)GCe(l?2eORsK7KyByZ#(@Qa+ElqmNWC9+}(&r0Iz~p#&!b8Bm&luvoX^sQPUz z4lQ5Ch%nMvRYgTrUOLzhkXBGFBIjR`qc`UU9_%qYhSB{xR7Dg4vXs?Pad{r^?~6jQ z+VVUw;a-|ButdyTrE%^s#xnA%_nftrA{8bcp;IbA5Xf-eQR#rB!L8G4CKUr&URwcz zF<;wr>D|wGce}kp+t=0Y%Jdw@5mjaEz)Jx)_|lG74BNmjw*`0F0>Ii`pAm1T956x# zq3)Br&tK^J2DdTc>H}K<2&Pt)x4G#_g${M-jL!N2;Z=sGSbcugf}N7(aNQx1dI3_% zO|_xqu{mdwBDEjxTPt$iL-5pFsqck_m(OWaGr-iD4r$m3|9=5Gg_rCfHoJ`|HoBEo zP@G#0STKjTjSBdpch_y293c_HS;pq*^bGZ|S0e^7c0fvf4dwV5VNyMlRR+8c1_2P0 zaKHLu;_g=&C%V7p5baWjW(g(eJ4x!FwUP!LQNT7vvFF*<0w* zVaaNz5mF-(VMAR2dhh>qm7iE~?9X zzGt;0Lo1loC#Dcv;Ida#Vh3HBlZ~Ljs83goAHLLv)@8K0HQ)f8v#K(mGsjY)7~;^h;; z7)O7N{$O_tj&G3kywHdBS2g?sV(2!+VR$S>fhZ;;+j(mt8^Wlkg^+--NY`TBXtUPt}D`*$qeVQ z1k-bE;FED6qY-DacMceXSefWy&=5~>WdArBm4{-gsb568H7u5Q_14JH;5BD{s(nNc1(J;ju9*zMbO= zR&zi%+lLokRb9<>WE5`(28=ObcExscTT*9LIWh;;$4uP&B872g2KNBGiX6g=zeHCc zZeetlTbSv66cy$m>b98*Jwfb&;8;A$EEfZmQMfEUd>Ip^ z@t|2l7L5*A16H+O&tWyq6A6CT01*RDH)iySkdL5&`yobuebTMiT-ntfph!z2?Z>O! z;0=ENy%65dj!*x7^7^IPWhZpKm2$R*D!ih*Uh;eAxgg;s3g}DRR zfsFCQjS&vpv_VKth(lEI7i~2l6v_C4j5IBapis$h~cq18p2vUl4yL;WPY;2%s+~*sfU>wSmQ$YN1@=AqX z=9>fibSQ7jQ7T&Dbr?ky5E-RNTgf`i1@g6=C0+*tMcJh8LaWfk0{I85`=5F0evaK3 zuK4NoptHz31}d|n6iJ#1pI|g!;J9(bGfj{t#VYZ!`zR9%T&1c}4xNB+mW+?E?GP67 ziIfIEE&Kw3H|$3m-@{8yYn{}n{ncmg8r%ovm}oGQA2N8PB9I{Mx&hcUpGWI=S@MWH z5hY;Y#O!D0G805o@eQHqC*>K?B-~gz1ZZMl?NG0K z$#i>Ax(+HcV$+F|j@_~1(9Z4qkg#5j$gk# zojyB$eKvjn`sD1N;guut@#u(}>sZ?*ki;hQUMj2i8rsc9WDt)~P$Dt#xepR$bZ}ri z>QG2*53^^_z;34-V?3SFwDK@xa5e`=$wZMEWK^-x8a9}t@H?ZQ_ z^*qRI&NvL*PPl8Jz^AWv8RFNJ7l4NxN*9Fwy*+5+`+MMMB_U8qNu+=Th;kC{-!MQc3d&R z?u{0c9JX2dBvCX+gMq88L!4Sb<*PBEAeFK9n!c^qY?31a?84c2jmXA#BH)y^d^LAw z80l2rhxn-FKe4&Crlt-)crD();wHLHQ+Go-j2pDK!`!KLhHS?UM-7`Ipo?*ZhAJqj znA%DM7)n&^P`F5(8{ZX1To4nk(JWAYQ&#|#hGPx6)A7jAySb<_(g>I_N1ZUI5<1$x zU>MVB_3?;vV5{o51#>7y9c(e$yYtlIn)1e<_hPUAB8saTju*pKTOycMx}ul{Y*?iC zljyLa4eX7@C|jFYUG-R-i(kEZ-80Y-69qebPg~yxCGWFjp2Ar^#?rB`e)iRP(7b80 zl##+J8vQ-Hr9?E7=(vUB>}=C=hS~6Kni1qD9H}U4=IJ^UzRR>Lcw1uk?)gw9LvISa z+9Za|ivp=sPs%Ll{^-dox|qE&mQ|0HOYG5592RGKv-_z%-DLEZ?FU&yg!JM; zGO=U??mut`?!UKsq;AX#Rt~HqpKFnHh<#7bxYf^NfD@Yp_l&tMx-(&-5#>Y?abPY| zW*||Z&$bmHha#66fY93k^OESezwAGQ>91vF3c*b1XSbpp z1sr6FQxf12TQsP&&~{>i&K4q8K6j~vg71DlpWtMC~872X?7|r2@f2RJAO14_Z_VA$=b#Nm(FEocX<(ltXvER zpe+w5^baj9B+hJ=w=MeG!6G0pr|P2tP57{&E7g+pz;$HfbnNSf`fy5!a?N}42JE?J1$%pN=CM|0=GXZft7#=L$t+2F=3UyZbzc^;o z_6tk1cyIOwvmnQ^wX|P@#v<$UXv`#g^ySfp-x2DWvw*AcSHEr3*D#;K0+4rxGU!ER3`{^h80>_nhPQm!dTLS~e7|{6k z_a8EUE{)6BV3qb;N&&o;h=ji80US^uL$?_n3@`ZZY>JoU^UU`8=6W@eF|p|^q)S4B z6`V*q{~!F#r6njh-%VI~WvsHCX-jvey zlqZc%aOMSUK%(pH01QPkI9~#Bj-LPd@zXyi> z3!@R0wO^oR20Z?g{kUVJN_Z69fVDD7x}p7MfBE+08Q*T2DT{Oa#^_!NnLF9mI`>Wu zXt-!~#x#e3&KQ%A8K1Jonp0sN(G|9Gu>DFtzyAofWDmAl4dlUfI^w2H@9s!8K<*GR zvd{!IFDc<7t$vJ9354X#R9Q(|qC@9!*Iq7Pu+%1+^;vzGRfM5Z-e z9C7W1DKkRrAl4~RVa)S_$F~;ckLWs2qhFrUqr+eNRZ|^n<6-n8+S8-tL|Ze4 zW2ffO$#%6_MVFZF9@jMp-L`UAFMP4yiI34j?_7Us=^@ztr^(}vm3Ob@il48!WQ~pp z1WfDf*QVR-&i#BYUtx~9iFLu#D0u+fWMwU zJ-kRz!?GTY!}dJxX9i^WF<5dt%Q`7N%+mrfurmz1IDo0Fab(s{lDg^0FN{ugFs6={WiZ{^^GhIdw)iHVha;^wNt8$*5-vWuyFgq=IwM5$Q9Em#Ml-gq5;n&MBmd8 z6nz0B9M-rKQo0g4mp)sWK)xvv>F?ggGPEs=9ml_}BWWA0_OO!_l8rkZ61>@3|J|lU z?E)j+Dh*Ymk=JoixBR@_Fb^j4X$*03AQQw~4~dqX}) zH>U;a&+s|`n+1Faz!^RiqCc{6rUKO`GRm0U(g55{01RqblRd#goKQKQ+YRR55J%67 z3|QG57IBf)$Vo+a0{{h;kPeXULnIa#GIpHSct~Ul4-OX9yh+OIe37SkiFh#IEK>SsUlP&&0{9O6!S)Ywj7OAQwX5Qx zuP~Ay#PNWm8&h(KR&i@!k3MqDc4^$Ze3vhzeXwti2FSUwVzA#kaS=yljNYI+BU_wi zirMKWu0C6Y5}yI`a(yq18L>isYwNlK%4+kl=Nh32tJ=YR{FGkQPdxkB_T`+1D~7(r zW4D`aRTZ=ux?OE^Y~?3ZzF1)e$4~>d2@T=oduw#`g|s(PYSx zri-HBJmFG$Ftc7-=9-oXiY)Ee;82{P{a4;GQ5GkkCjN>CKrIlWLD^fg8x|$up1Vfr zLAuboxEFY_gS~qv7qVJQK-jE`>kNZMIMU%d9XPo7)%`x zO{~+Jd|iubHj2MV0LSjW`;fh?RFG3B(uA781BQfW2dpD}kU9G}G)k^wETX?GqBU*Tsd_YXY<{cajO(qGJO@sx;5 zz)*oAvRMZ@!*fkuCrRQ}=bbdtTH9+8D}1CHJ&L&y9lY4cgSL>PIB+J1{&VTBa2tdq z+CaHnm)bvcdm(F!-DXM7l_QSuv`W{w1QKUs;JX5)xrgOU-0K#ez%mgRbVsvvu}{97 zd1-UR{3{*6?M*!2zJCXXi=*?GeLn7TMhWKT4(0o?8ny*b8M$m|9CR;$It6*Rg>5@} zze+sNkvFBmZ1wE4&S)gCjcA&oXiQPZ`HG%b^sv#74Xu zGrQX}(x(quZ=sIQBwy_AHgMq5xGc7YQxE}I6Kge#5^{DqD5#HAz^&bSe@MePfLnH7ty{Flz=kK$$L#i~NLRB( z8nq4Vi2F~XZ}3~PuJa1U?-~$rmRXe$ZPdq_hUKl*P(!(EJD?6r1{rP5U)z=D5OMc~ zJWGXf!I;})FMxYT%2~??!y9E_m`vb6!D-`<>_b>G@g%xTpo zY_}3f`WGmjh8A7d8Z)KQF6dv7<95il*PZ1SKLfHv<3}LKKHrJkYjFbWz+&gLcTTtf zL!!Txh73Rdvl!l%k+`EtLs8~Bfcp7L2Eg|tp>=kBTiR)fjUC0MbU={b4&|AXg?bpW z@ZO}u7WQ87MxkAKP+oAWO~ETT3Lr=hZM~T*5fU-P>lqqsRoae0{p;LLhjl2mrRH6t z9tIOG$KRz388s^B6a~tHJs!Iv9J)xndOm%1^4+`RcmJGXf<0W&PN{Tk*%6Y(8KCTz zEYgKmOd1YeV*-FCU3xJ~;3F^NFF_*R%;+ATh@R$@zaFeNMRD*1K7V%V&txYW!~Fx`~dL_tl2v{L;hcy`0Z5MPv4q}8zG!X$>MzOOP;|a@F2ADC2;O`;{gGv`^-9e=t zjX(eA@aFAxhJuWz7#Z=*u>BeGRq0yEL3q$}HgC}v4-=6}!F^C5GArw{M-F&+v<3G; zK_e;X^d(gCn`I*9;uCkuRFi*;eza z;P0$O8U&|9C9-vky%%uL>thg<^G`Y=G%mSM20PrA6`DWY9-`84df1G5*=_NY*0q#k zT0^{6hFNt`Jvvw~IaqyarnzF#rc(_{4Rz>FyX7I#NofgiT;A$)<)kzJcK2nQzGn#7 zo>EjR)8r{DIf4~kpP?jUDwf3U7^%3V@gztBcvI&&P&@Y%0jgvJ10GK}?3ⅇ|F>l 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�ws_vM(7$Xg;9m03B@wd-k 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%0D2yw0uJgKpvKbRFOqpB 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 F`#=3a-*o^0 diff --git a/python/wheels/meson-1.12.0-py3-none-any.whl b/python/wheels/meson-1.12.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..0b764d238f9419b7d061aa1bfcf38123e08c8746 GIT binary patch literal 1106208 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%0D*d{jrsi*4aHK!;$B=1v9pfCJ&4Q+BKIx5pJ}I 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�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%0AkOD&>h{rQ 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%0D=gjIvD zsoE1sw=lq_YHU@^7*b8M=2~dKnLyL5s!`wF!}`G%m+J@5o&_%yG|>VV1+a#W4jzd2 z5(Jl%pt!qS8pkJY%D8TlW>NRxAwKbRR%-cvO@nb#gbnTp!S7`q{d(~F^x)0m?%VxW zJ=U2=E$II5#6*yPS81L!=|ljVE(&3b1A=f0!sj?afW+tt6@ecwj@DoWRiU#*ahXn{ z;Ghw}xF}vc7wKg}iUZb@!w4ZnS@$}rgO6FBGtfj>#ROHt()d+U2!Moda_vLq_v<8U zdi~#{U^lPJL2xidK&YSuaCA;J+Iq~hJfVE4<96}bj=Jt!1!8~8oOinJ!`&1++t{CXx2VEVF zMPW-D23z8_dSmbpS(I`Zi4UM-(*+}#iF?t_hpuhDuR2de$vr+%M02+uyDybo<%;6?8^NAVP`l9c(E zWewJsmko6d<^K(>`y$`~Xm!Yy_kaVIdHNniryjlC$CYI>bUmt75+#tcENWgds0YS_54?p(6%{@>Jlj9n-8(z@7hZI4FM|M#=DNyI z5TsM)Gd^Kbh10WFNAJ%7zzcsTkwR?O<@WJ-|L_%G9f#s8PwJERhlk?1_{z_Ze!)ja zzwocKgLnJfbSS=tZNE<5AJZH4gWsV!6D=e7%THeK9=ydT_?MsT|8~5;ceejZzR`bk ziT8){+41fv8b*ZX69ETJkq7{O5xBiMJUZEbMVRqdvHt!IS6ns*iTE548Fy=eb)|Fbo9$W8@os+!o2}~luRB0 z9^n`bh#@qdsln?$I%uU$5}4TI2$*Pt?47{|ycX`nqD=h7d^K7Tb5&~xWR95ktu;y1 zTbCl*2!ohcR@r~1)C6#@R%k}E*=V<@vsWOBgP^1DE4Y(E`ACdl-`sH~vI5Lhf>H_L z4L@lvD%%+2sxr~#Io>&wR<(Ky0#bSHHXP{#xC+Q+1tOUSqfS>;80Cx99w1c+1$9Mw zwB1F^aY1@H5<4`==AOf_kOH`6Ap?NTwcf#hVEx|ThjR0Q2Se&3NwI@~3-BY!5Bk3O z6RC;Nw$qOkit??6{^}QW^Kq|JBaB#OveuO7>^4~##TUOyHx9GdIRT8mXlEikV*s+Ii6@Z2us>7 zG-hx_NG?-aJ9;&oxJytUq0xbkHy!o~h&kvx+7fsG?sBAJ9LzZG7#?kirr{lp5aWh| z9{nQeID$&qyw}(J#}*(DB#LIsyjE2;s8FFOnP3_?VSC*LN|@kl)#7)%2ZtoH(68Os zz!XWhPhto?`#-zy-m={;{XE%^e*%8P;(}q*hw}mz)?a<7zeY1ap{T$buMST3rFdl2 z>HTvDN`KhID(9#5#rZEEFU}9Li}U08#fQ_c|Lgp$xi~*6FV0_0=x_hSNI>uZQ-go} zcK6T*y^Z#Wz4PZ=-(NiKqtd`YB$_7;TI9DdM6XTs06*Na`u{9H_OaoA?nsF6tN+j5 z`G0I)e7z3zf9;=~9vnGH!Xj7B5(?M07ScXGJ=;BTG5b(I?Qd;uMPJ*+VLP=8Ls>S@ z1f-=U(zILvuR`WPOarRWl?A;Uk=b~Rw;=jsTw=!RLT-fT5LBc+X{V(!GE^K%J;~9e zP_)NS(8e{jAKoUjJeG4@YY=S%_4cS79Cy&c3H5h;-~ss$PdhZXpJ?+Q=lP44XOpTm zW-T~vI^{>^hyz5N7RjLHLW6*>hq6zp!(j$X`44fK4+e`li{7L~O1t2Br-z2?gaHk) z{u=+i(AXy*Y3aIHawZRFgd*B6SrX+Jy%1?U6@~Ew1ytXq4PC1{Rm@ct8Mfb}1sYpu z=-BW8i==95)HwI}EMW;Dq5_PKS8~10(tN_3Hf=C4as#2YcEl;ImwhiV=KRJh5|p&A z;SmW=>Y>FYi9)rWtOW-bjRi-CVR9xxhOATy8LRuNd#?8x;CLFQix_WrpR7@k z`eQRxdeaV}pB=7)eKr-ycX1p-M{GGymEJ{uHUpAeMtM2@$R0{18ZjkfR4S#DAejON zq#mvtn>`U^v5yS-mnIu|85AEh#76TYVDpWiVWBpZ0UG;zMDCUr>8&Paeu#<`a^qw0 z2zz;XZI_j`_}3cM)TTRwQ(?K7_qP3L74}>la>7?~junUt1 zbVf{8eLJ&>)zNqdKo7re=QAw`d9ML;xkt^ymy(&AIIL&`eBTe<0a|MW2;Pu;R~hFX z`GJ!M-n95e$swaqQxj0ZoeU9R)3^T%5*g2pb%d+3a|QWVj+`mDC9$oK{1u^4OpoYV z5+7T_@=8%ecmpg7*z#aI6~-2V3 z6`ra;V^ys?Fl@GUm9Wb&jXlkN5BdF~Eq?T)raoi0J!B$Mu?h@NO>Iqi{PgsyT>;&j zuu)8&eAYVPSWsG&e$?-kyFM;SrDRW+G_81#^57E2bsI(r4>?TFC(e+-i+gOr0TU@ZU4Z`hYGeUU%3bws;$s~v@yc7 zfz@Wmd|W2WwrZwT9LPQ|{Lpz^SlNL#+C&0~qsuP9dJyZ>nvnWq(Z*0mvQzh9ow^pR z(hlI%-6S`jGbaJn72inifj*#`_R7I}lZ^GyEilVdd%mrIQ1~mvYcDqKLR(L+^~*pl zL;GsDo)9GAv^9VD4C!eao|R=VO|ON;CE8#1lyH0J0en9QE`f@7CKBFb$XZiV$AcUQ z{sKgnjfWxO%0XCz{zknYR#xli^{d4^&&D{fH8Hk!dTw`GE3C@s2;G0~XuQknS{m_x zQLHqZm$ziOv!m2Z(|l21wfA?XUWjdkWKmkTLK$_HR7G0XJ3)v*f97A|dLZ;$0zaGq z^-4TESrn@Q=jCNwFGdfCEDaOrLR-HL^~*UcuO?O?xdJ(PDZ5_BTZJzh9em!{jPp|H zNjr;b^XN4&VxCLAc3Sn@c@@WiQX{U02eiLvw?Ay2O+WCeNf~Fm4fFY3)P}P1t6KnG zmh-ge$r6JgyhclKwE2ZqH4GQcbn9hn8_s|FYZ5?mAcXEwoRWta1L*tT%A2+)rj=b6 z4R=rX4i4heBdbuI&0s!gL)1wo#J=^%Oc=6ry=fMWO`1$R@;l6nK93a!f zle3cp@$B25{sASsW{>iPX>GtgvqY6*oe6(8iwHL?ae%K6lM|wej z6Ky{Su^bKvV~S9TQtr4)NhZr?vviWd*Zg)M?cOywSrc4mc`k~RN&B_9n90j>ZsM|- zPsm6{_G{m`(qVK-%#PD45my}TeX}Y<4n^c9>FX{@kk)m0`+A-gMOu-j_{M#m!5}oZ zc=)=lBeookFcx5QYmYX0Dhz{{&mA_vFib|^7+V`~20@G*suq?{?0Xp3Xsu*v`-RnY z@92~SgF&#{G*vcQG;D+I(Ri5M;#pw!gk2wFBAjs5K(`WnCD*JtG|);NX#L*`Ui7`d z*w06R3d8m5!$vKSzQ_W+gC`3J2B*rn7VUQTq%V**x^fRdCAs7Gvxbk+3NnT-e;_Z> zu(R7MNw-#Ird#-5mUowrY{vG{^3|o%o;vc`tJ5Te@RRbEWap_c^dawG^9nWgDwAx| zxbt*f%vR$ekHPa{7z(UDR2p8(7IHVfA8xis=fAY%cg6c9bqlSx6-N052FJ{@YeY1D z8r8HJDFEp#bEvhp;HQqo`fesKDtyunO&fDi?c<$@A?9wgq`|i|N|LWjvp|EP-#@#v zc7Xe36qm5VyZfy>sN0&XdiIK~P9&cO+v}<}UAO~#&(ic4xNjqR=XduP!QFkJ(4&F_ zWBH!D``3ldJgv>G=XnZ!=?8ynyDHvlNO4eXBw9TO$-BM}?k0YvF)6Wt3jj@w#k7v#CmpcQfwfSsVQpr@Ec!le9@P5 zr?f)PttKsi0hYmpqlP3o2G$Soes6pg1px(0f_G2?P8-#&2NDNG9-w5W9BVOHmoO4Q z9Hd8vPpgPyBYD%0Lw#J97`K?)rgdJ^Kjtv&Z9Vmv7T|}rbmb@J$L!NiMqN zS+=P9?p$ad_5$Cep_uDOw9M?sOBo-MYU-K?YA=R~A$cm2Z*3IBJ8-EnW zYG|WS;RQMTJHkNQc=TVtgDz6h99BD8DR9)9B^R+~wPZ5!jGSkPsgNoD3AX0bJPFCo zCsJzciq7cv>DM@c%dMe(=shYcTNOU?%37BG;%V^B^S&WE>L*xfEF>!zDTrCZ_0zt- z+8r~3c=5e)o+MkN(X;XRA~-qm0n7HNVVuHBa|3`4)8 zQ8q1VOb)_1LVC_-V((L5MmL^ukdjCQcH(dc_+UJnxCgpU5uZ<3mQcWA06C;dSwIes zEdY8ypDz;xLZTT;Ue!92b)ePn`#NS+xBSg;ly! zrE6er&`t{Rz~&AV2HnSN@xu#Og{A4_KcWP3m$h6~)`hEBnl;a*>PoFnK}<=ir4aaUBlUI`PPc*C04K*VnYS1ba%T>@0OO9a^Xr>@#)4L>$6&I z*<#ecKS`4sXT+Tb{(hss2DVS!k?r0LzYOQ{Y}HkYn|05#a$5$0e0m!#P8+R`h1GQmFCOET=7=;_fm8`LU z#W1?0WRut$BbK-^ zla0B6TmnnA7E*}l-0{pdub~($HID+q70R7n0ixHWbyx+fg?HV3WLVv(msI8~_e5Ip z!(B(l|6Hpi-Jrp+rCzQUb?*Ss(8B1GrVuqs84N;BB9WRC4p1VG1@Ge@94f8c{fQbIw*Ex1VkAV z)upr}esozWil)TDaK~v%N-y0FpcG?5mti1Tz6o_cDp?+UqyEaP~rSlkIFEIGG2 z=9jOg_uOn?zk)W>E=L5ce{}PPx^ypFPJqrW=&#&_Y$Q6iBUU!9 zTuQ#pNS2i+ir0%gC*6m*io|%5cM1>(r)u}Ge}|1^-97BfFzP>)z9M>+jT?>|dKT># zw`e7LXHYOibi*B;o0@X9T$?-kDz=L7o3;pwhaB$BEQew4Fc;a5PmXk&73@@RSv<0e zN3>#@%%1Kcz`CwZF_+MM(ek}$f2I^dLjEh!5h)+5vDP~iL zKF;QKPk?AAwwiVromro7YO)d7jg1ZQlGftCx3QcVU>$Keevxrf?7Ge8e~5s;`tlb@hG!p)$6j2D^l-E?A|$59&Pb2_hvW->y(#h( zo)RLK16KgD784lgUKl-lrYPid#@~ds40~|Oq2;eJO)LiL$Gb0_A0R7SqN3~;vz%X& zVNn!Cu53VTftk`dZ*>=J@)^j2SXG||lm`YPtdfB%u z(W}!z3R9RWYRIM!zCHgpUYi$PK?^2n&I2XU6#MbTqZ_0=m`yU9uivJs@)^zIN?X50 zEd3dc;bCR{#>gApZA`I(h*Qn=sKwo{Ig#`Jsxaz2Oh5Pp6gY1rwVS^rV-mnT<8wGEQBWXU^z0~lt8T?cN3t-U* zB~uh&`4^@pWr2GV1@C318CnKhz};y?9t0AC#l|KX1?F3QlQnOXQ9!XW>Ok^Hl;JD9 ze*(GDJNb!!(E>YNjN}?4LiN9flzieo_+n2S?p=l$^<+tSF{>Xt*4Eu3tca4!BX`D!u zjk;P;e4o)RrA~Pi;(}5Ccc4AV*d&j2nere$E{kb)xxmO3;^N-Z53LuvvCaee#ckcB zvn|ws^(AH=s86hh>AkD(#t%n(^7Bl+HD5)Efe3sM!%Rfg6=n&FZ)SNs205zksm4{P zNWU4XtB@j6RMjf{+H|Z|#fRaSdhl~?2qd;r72pbx9-Xj9Ce(qf5)1L8i-x>|xranJ zxo?|i`p#)B&-nu-%FvGvIbt2dij|#QaU7-&(0Lf!&*U)M@5$-Jl4Ksd`L`$P)#4+5 zTJgXl`a0y&jxlQq43F5eO-jjf-LzCC1U1dk?MAp$ zq)X711s;g4U*LI!uwh~&dBzfi+aeD{d6m%gc!BA$!qR_V-Jt&bx>s zfeH!0NnUvBmkh@3fhOMYrE={xtzDsn-3(4eKwZ*?Qa)^U9nQ;Z5po(3+K@tDyX_j?#PU)?lFNj?wS1|=Qi1X0sf>S&dG0NM^W0el{6-VYnkr2VsrC#Wv=Ccr@U`Du zTCMA0&qgq)==f~MCrXw1nJ+FHPOM1^5*rI+(&ST5n7I(gE)0PkAHIL5f-4=L9GxBQ z9leduj^e$yxEaYCFRXW5l}$OuTtH{h+3h^lf@Rq^U~yce*Kyn%qx&ddc467mw91kk zqcov4K=3stZ{J~C2>A8&$7}6@OlVSQVO^xZ(t^WC%T@#$k%PVxzzJ{N_ib? z#3BQ1d-X>Nj$F}M3ymj(QrMZA2ACZZHT`*><}$UCbW-A>nChfY_Z7bir)&&*X*vE^3Pd-fO?i zV$uYDD3^`}rCl$PHBfJ%d%al3Y+tI zMq%9~&RUvk7k8cU8HkBCwaSr}a9UGeNk~gPcRa8-?er2Yn5PbB%kJvD(f%6gdL1Wd zXL%Se3@2nW1*>4a9mzcx{l6@U(qXLr!p5>S?_ zx*RawK-@oQqGG#6vhRYbp>3X4K3*AZYUO0GPOL(n=yJ7p0jSN}SA)tpw(#C%pwD1k ze8WVZdD#)PNQOGtCGTGBZCHkQpH%F zBG5#$t>$`AnG%7*l*ZOftZgM@_oUADW9sH@?3g`AzbsAX=%7xbmcifX1P^CPkuwHO zYkdJ5vEEY=q|pO3b%3U80ZkpCh6HJD;4(O#+TT0(L-x>UXRzhA?u0Z@QloE88L||~ zh-gbHoSZP~q!b~QR}&%HEcJI1upJ*M13n&zO@F#D5Ro71tN71F39IzR-V2}`Mv{46 z%`xhzmxj??OKNJ_50rXy_&&z%BR<(bdw+7ccl2uCE^Wty%b+>O&Nnk zh?PcOcNzJ2pvM|9U%8B1olR)AxAl10skPx>6S%kgjx6>xtIacvgyYriVd$+dD2{o&C{;d`brpzW-IJ~-{^J1m>m7>CgldVP}}WY8x6if#sEs87;M zPAN<-nopx=ccq4aZy(B8YQd@~vJ3K;k8E*SA>~AR=g}p>%xZK}V7>>NAxJw>pr(Wg zjuInW0jJFwnz%R^2uFuYPEC(y;UIyGKcZt#8ZF@rOc7|1)SN^Oa^tZ{BGLH*2+&TJ ziX=qui$wT_(P#yC$`=xY;e1u!>j70hW6`}qb&$5=Xl2>U?QHj0W6jv&=WRw5PvQ|A zUhz0!^v}(+K-C#SV;xqf$_Z_-AzX#NIRD~MF@-Igq-hRsnas%1E1mEv=96(iDBoFq zxbKHc#}A+Xl{+<4#5i?0`qWm-ucfxLl>Kdj!0i|9jBMqA4CMd?2s+8>WvPIOgy$Hj zX=mkZ&{meI{5(!3TAD(c+t1SYECDMLOnQ?vubejck?t05Y_u$z!HeWFC0FA?z}e;3 z#td8T^3j$~EaH+j^V)l7nntf9yo|S>#-6@TH)#We;hu)lB>ygp*g5q+94I{Sn`Y>o12OyG(Cx>l}$J-R| z*n8po!(R@Memx8=g9sTsR|d|-P{5f?DykNwY|ReIs=^|5$3rr%UL?Jz@_ZQFU5mzc z?g*88+^|G9?&-B4lAWgyXdqYdkKWXw-iAXlFUS>GSl)45OY#E4z~@1BS(N15ag4b{ zQxdLVAD*TOMgx{fKwz)+ongJ75QDDMRT%E|Gm3l8q59}IbN>WWHj#vMOHL*f#~ZNZ zB%)DhPf@Q?s;|##DnO@tAx$L_vU4ZsBnO#V;7)^~k70w-veicG_nRa@_&@A+BM?w- z$tCQ+nXlEvCeqow zxwYq_d!FpDqx2uqd^&(fDzr%hu%@qT-W#f&ygxmQ=|cQue`(HdeC5)SJ1Z&9r8q-&?aAFSDaXQshnjtLv}d;5>9i** z`b9Sx^Jzz@?C}~_m?5?*djUb=hEQ)jIlQ~`W!YcgT1SC{4vl>fde!HPGEs?gdH@(72Jyz|FjNTk>?3H z4`&s}zajuo1`q>jlAYf~zM~~3$7PjWa^lLSYWF;KrL-BGZ|`hvUr<01viV^5ZVX0@ zXO`c?-*u#k$&N}^SX7L5DpJ*K%HT4%<_nHRFK|QgH_nsUXp-Q0gTG{Xo?a%1XSGB9 z>S<4y|MdEOMo$2vo#g%DKB}pAe|ozg|Mu=}y!Z3TDY8ab!9BM<6u4Uoz+ONmIw>cd zq*zKQS-dZRn&-H32f^qT7{P@}Cc6Eiz)OyKm1!Db=xE!R`%p6yjSA~s<|bw;%U7u< zm8Bm@R+n2ZUw-@j*0!eIWsw0lJUts$GKobk{GL{AqSsS`c|uRS_FXveEKEboP*(qc z@YT6>m3gY~%$XoJaaZILXe_hJVG}>Uu)>iA^-QSCBR4}+ydu2N zn1ECuf{A3It2l+Y^ijPtc!3&Mu}lm#5#PZmXtyARN^ zD0@>gU{`yvlQwW9!nLL~QF=qyOG4w`%W42tOv-DNB~hnT$K%^ec%*)o^$YTYAq79~ zm=q8nqrdga(I1+M**4j~5T-O8Zx!bzBg0mshd}XAY3NIw#zHe9s1IEN__(4mQ~%-kEQhC0SsWP>&p=EAaRyfcZVtc-fM;f( zqy~)Fp}v>Wa)~pLgnEDO1grKz>DA&WEx2#Iiy@cMW=WII6d(Q*ZBw+P)1MKBK947` zQq3spRLg7jJpv~FQ9ZfM(tJXt^-igqB+hu&N(Y?Y-qNsaY;63B$W7aOTU5ge$?p=V z2P}aq4p^CrlpQlGqY19u&5Vted(0Id!VK9&#O+LsXD$Xu420+pg7LZ8xlU2V>(nE~ zL{ccR`-pUHSer^1+|s60-9;*i+`&}hqsRRlh-Hx!icDu*N^JO)W2vsjjRe7LPU=BpYLEMl=7aK3|x5 ziecgWH#P*+A&5sm8n##yT063?(qgD)>A}hAS-k(- z-v05~!O>wmu;xUc80sd<5}kNL#J8S!ilSRO(Rld1YshpHJ*9ZBV^qGYrDwTK&fATl zR;8n3{_CNOyySD7B8BOt^TGu&FY5+}Bc77y-X8EyTJq-?tdLX8*EYlz*rCqQe8Wfy z+e_PVkrCsU@Wrjk2}*Rt)tZABq&?_x=R=5(udUGmyVU+Ni(w98jYE=DY;i}A^QC*f zUoO^M7#dFYn?qV^X0a;-AG2wVTTp|pbBHE&wbe}H?AfBAFqJ%4y^EAD1=1x-sL&x1IG^;rg2qn$48P@sNtHS4X_LGAMxWzd?0as|;w#%3_I z45nUcpv{Vb(L&$07P2~@{@>C0bZO^Vr0eMRrawJ#z`v9-E91EDxU^6~F%G@R6%*&9>9XRwDgpNqTV?AVKN_UbzUAropy4- z((IjwNGrq|^`OsQ)4yl*@A1K_kRnj@=FvQx^e@)21KJEuQ|vIXoobeeG@CUXFfk@f zDWm@rVd##9c}JZ#bvE%_)NTf2;81w5+ro3CNWzfdrBE?utK+ny;Yfyq#|0T&Lu$GAReG zy`nyfNseOLEsQ%1BWxXiEGX7o)>v@Jasle0aMiFj1UY0j{>W_BW{o^BavXeQGsx*& z?ubFMj;QXIW4sqyCpR0ebyn>JlUiV`eV#hQS_4Zi_Xx=D&f0mZl~RdcxRFHEY?Yk7 znaOP^iS0%-oezrb;)mk^!9iiHejf;pT*o91&mK;Bulm>`+ z4Nc1#&R|mg)oA#<*Hrn|Ui6puKm~zZZ%*qfApdmKO7wJJIc{BZ4mTJXx@SrS*ePY* z5mU6l*fd=_FrLlMogLmB`=W+vMyKwUE%I%^5wyA_%eLqcO2bYucJx_IS1>OD1HB3P zoB5g}3h^+ZCKi6{B$717V(Ki@aA2sWN@8@fvsB*D&-3tj_v~j15-D65>vV2=F=_yU zr@?v1AtSZg)|OVJjO)4ig04^WI07DT4z4R%!`LfHNnguRQj=pG6f;b15lB})8bbQl zgTsB*Z6qbui0dmjeIQ_e7;6o^Zk57$`2X&pL&%&uJ6D~x$#}u^qbtD{9XKR}eNNQb z3;%c6nV4IfNYca9ThbpJo^KJgV-kos?{?q5J=%+p_fO8=pZpX{$pDTKq6oHgv-3E=y9-fT2blpGFLQvM0{ z3QW^8DOn0w6qs3FurW+wMiy?Di#!n-*)$-dbev!UJ4PQzAe~{_Gk7*#&LCcu!LGa?+Z~KNS>NEkSnEfZ(0|JGyLEx1M+H&GZ zk6=+y9I1ls(nPYnOyniRE6Gv=#;)@TGcvp@0ZL=_tyiPC77bCyP>{|!2N}k;U6A{a z&}#vi^n@Ts(_AXDA}XQrZtY(jD+7gh(@7{zGs}w5@^1CmE;(ag}3A3_6|{8f57R? zMIP1Rc4*>7Jzt5KS;~u^3TiR-(+232i}{42>Xp#*B0;Cz6Z zD`Z+#Iz`={mQ@p#Q0Vx}uD+vNxps`%6aH)W?VFQ>!&iuNcfZY2R@_^!;o^0L8)X#> z^Lx$DhVE*`>z*!M^v|EW`3w-pPol>mIRR>bmu#dK#yAjLTSS~K89GCs0#uJ>+=F70 z-gx9%{IC^>hMSJR5h79sz|m!U{l?gR`NJ@H-gWD0oXy$@8?s?hFcw-%R84rTbXtH; z^ACgm09iHN0Nh_D9GyQ@O`4mwfqe}QnBy5gM?H3HIU zM;8ukRI}LcQ@ZOxXxj#`3J6`*tuYnI%2Q_q_G~Q5xJoJIuXUDy)?@T2hgVH2pa_9H zt1(tZPqpba`@>;q&HSd}nG_Xe9ECeo|Euc0y)*!Z0__KIC?-?!MImz8iaRetR%A(@ zMW$z|0;n6d{*hFUog|OOdH6^2DWSCUSO{fxi*)8XRlae`FUY7gfs7^YF8YV-x6ugF+)AKr(ZdljT@CUeHCj zr@j={8*+l8Gl-~=${oqo=y&NUJBj4OTxfYkE^>MNVY2lyG=9Xe`@x(qvg&b_%^T10 zj2wK5Hp?#A>a<$Kn{-Qb!?y#Q(?}zEG(}}{R|JPyeThty){#C=QkE4mHIDF-k^mvSe?P3xc*( zTdztzb@}}E&V`TB$SU5=NTZgy2R(fIiEYJ|+QuAfcKOE37>yM!-H_Ljc+uEU_O)Zn z)^`4NLOhGDT90zx0r*o^XXwF4dMX9k7ZX?q+|u2JD5MqdAfV;lQovFUwN(6galOoG zpW8{b1QcS>l*ZA!E2w)4JQy5`jX^T`F>mCOzgznRWpB>X+RAccxcH*VFIHZ@qKh6& z2qjqQp-Ptpbkrs+Eh&o$V5$rGP)X4^!SF?A^Bj+!qNjdNk91`{$`!bd1PqFE?+?bz zkQ@sR1kltDmagF||P0WDF0F`g&FVQ9gzxCSd z`h&wWJG~B>N#GtkL;n~}U=q=60JJ!CJT4!1jeBhmLCFtNgpX4(QUfAp>5o_v75p?4kZl^MMxu;HLgs!ZqHx6 ze!HFx&aYCUqg3(Ix&~z{901AE@H>gs*dd>A$Tlw&AQiL7SFC@Q6Htj9SLJokjG>kJ zW#x;uuqhQ#$)_@t*Y0E_B_an3AzC%)HQ-S;Lgvux7jR!>>~WrHeNyti^xaShcO=t+rfv|2gW%> zmB+(t0&g9{e~+lya*<*CRf>8(Pf~UrWoHpHM29Bswd}k%A6RsK7@4%GKGco!m2;QN~PaAMkuLGi+)G8AvvLt=$8QG)iE!@k=8*WvrOZ~YDW z983<5_x(6@+S*zX>II=3%^%>9HA8Fl{7$aG}xAcH!ERg)VRHQ8X{PjnkyeT_z)< zn1NSK3RBQqp~TlTG>H{EcXdQ!8`!F_#Aai5cmvVnHq_tN76Feru)^?WmharD<~V$^ zmnFC2swQo+XsudVo54JW5kHRoK91=ktJUYz_SHxOOgkv%Z zLw3C(j_an*8S}{S60-C&3}vb5dfU*lbC?0hv=Y^=)HOr-d1Si}i5?7G%Cs#TW_!lT zODBAbjn4|LeQOMs--u7F3i;Bi(cOq;i%*2`oN#-lJD}KvI(-2jV7s)+M2USLMCuyD zbxmjwd_HTl6vdFma1V{ub0hS<#1{Wz=tX!h45f;py1T5rk!i0-h+7 zrqBgq`Fv@cZgCYXXk%w%5NyO7ZqH=>4jWN}vKWX)pz47G}fNg0W7|%1dK6D z1YUg#8#@&LY8zHIPKC+i@0WnaD67#R33hq;&a+6j9v*9JkBc@WHC5OaG=?E0b5_zKF~eA40+ zo54?f_m4EpQev82%B*n8<^XpnB;^R*%VZ*ti5MQC z=_@TzB14KWOAr$+o}?Ikb)Zy*!dX#VrdH&Bgo`~WrxrZ6a=^`rgGT}+*j`f*s?(aS zCueXLa}J8mPS&*!X#}thzNfL=8MRf3mfu?x-Ho8|(-5`q$sC1xc`BqxYmpU_LBnhm ziftVx8cuQS#H5UrS)4)!`#cKkWVYCmem-2*DeAu&mp!_zmA|jO^&`bO)7ov_g))9% z<*%fTMHTJH$+_W6`<$fF1mN3QPW*i$WW07Xd&&h%PG*^Uq+LK?RYv?|A`+Gma}-t# z^pg95YpSQMR_9*Y)xh|L0k@143))s${H2$%FrbV(wI3_Yp;eo_aE98xPEUF)YsIQM zw;KT->j&mv0lV#v1=i~w)3Q6kCvE=9u=%h?l8+h0Z$-#F0tG}S+mB&zj2;d`-h@5p z6L7S!4@^@5wzpVW7f%{w-?f%m*DG?VEUR1JBy2e>Zh(TrCL9q?aPf((uUnIlKcK>g zQe}nJ$eaEOqr#y#z8QfKUH70SP420iE|WvaN!rJ8iqgM0C$og5D|Nj$?MC$*?UbF~ zjN|5ZPUn-|;+7wf9lLr$hR7JyK|JY7O*ziXnxr!%gOOd=degBVt1NxSA<-aT&W$)( z&Fv$i89PQH1%kwuc|ax$`5R{H`u7emHhI)s(Ab^CZvv^vX<+AgBCu&%xPlJadYJXYpd zchhPUT_TJ|Htkk8EwTiQzcz!{2fw}BAK<GpC%U&p4X>2%&Z*_!me=`lzpXm2YfD5y0RpWn!V#;d}0cYL+Ky zIwvd*ZB(az!Ltp>)Y+(8_ArA|hORU*aQQ96afsI*T#;;Ch;2|cl4E-9CmNt=F`p!& z*Rk;u9izI;wf&abfvsbZ$V65l=bjh+I?1&N6|d}d^w(~>9wbVbLuZQHhO+qz@hwr$(y z9ox2TdnPxjN~)5)^h2rFowG*$G2Y~%?yZ;LlJq|F}6XyXqny2TxiuOu4o{QX* z10MAVZU)ar8^ada+gWUMEqnBr`)}?PO8XVySqFm`;O$cw^2h!4X$g48Yt@8x4?~lp zf{F!1ELL=L>xh_Q$y^5F>tJ0~c4s?lP5=b1a;0dxl? z2v%kfq!;B4`n-5F9U#klf4zQv6K?ThoJBlJvy1xEdTNlH#&J~P_BJm8Mb3Q}yx?hY zuT8k-dsMVPxKsG;)*%JeNI2^+Eg?%EqB)zPdrx<}2#P%NhtO_#-|qlHKJF+c-NQ=(e!?hq94#1a-LU*k$hGD~61 zvtti9u*QMp9$!T3M@FV{9(lt1>hVx{_HIqj4jLb zU~zmm>+S*EIEd0knl1DJu{*50ZAPk&z*xnmnmv|P#ls#Xo4`YmX`M|hzKYR*%L362 z&M~_DY4X#bB@P3^74^Y*yBH~Rrqv+rafFRcsn-o!mbgqy+(AGy4i^Gwr;KDNfq(9+ zj6)y^%INyNf4GUjGFu@^ze3n|tQ!kmFM=2lud>YGSDza<|JS!(jfyZzf85qDKZ@Hc zK9nllBMW2{3RpEYSZ1T7BPAx&c&apQY;$c=evdkLm zVfP3_BU7X ztQ{a%)e=8jh#;_ZV}EA7G?IRlxxq;=-Zw;D>!K!6EtYiMLQN7O^??XVH~F2RTUWmz z-cvRT{*q-D`nr~jg-HJo?m>vgEdyLjrx5Por#Mo^_d0vmlB>xLTI}uFOtqB-^(CW2 zBRsygDA%o^D&b%U$=#g`txye%vSTAVRHe2^xtC6T<%r#vC_CU6dwP!ZvPLNg`{!b0 z@?gqHQIsu|Hv7b6XY6FV@w*~d7$L0;sWTAT`tq)EtO~Y}76s;@(!0#4Od;ZB9El{l zLk?@TJ8te$!&^VMX?&5-vC%nb02lRx9X$>%LO%EJHqhkV13hF!t7cj$ifS|{FEovc zC8O0(xy58V8)N!OS0qzXQVm)~X-6Sb@V3^XR;`&vf?@atnxY;?O1i~dc+0r0;cEkD9#b}}%VJI7bXr{0 z_kInRbnMna{{ecHhpBjTPZr$6RMj~gi`UQFPh2pZNj?&81R5e3w-tCZX7`eV@e&+3 zP>m8p=b;QCAIcjCk{TQngstv{S)g1!MfSdnyohR z7tFuJLkHbbZKH0Gf~z6c12rZXl9PqDVRi^B`Lr6%(&+imKpXPH<>RSEjL2?l+BV%J z*V+d`yk*yyNWQ}q6q)e$WjF1?>%VHEic{hy37QHBW1A~`upi=5kN^pVpOrSCT$dQ> zT|-5H>SF@k)Q&Y0wpKA_kXh^pJocN#S8(&s=BQYugko5+Ic0b1H(a->-TlcrB`p=k z*oVe;luruhKTB!o=i=lt4DdXLbc>~BMN7Fqp>FNMe_G;$SJDXG3eQ(Oc(S<5-UK<}2Mta&gF-{yO~au`#_m&T{BYFCI99oxRSn2KLOalYy6S z40Zz4PQDAu4rYatZ?v5IVoTjN3@-;3qk{`UnzGy-_eC`!ontLQAb zkBM(oqaZosN9Rwa+(<+J{KcOg+~^OQQ{ryzA~%v*5#2x#%2!nIl8EVNs34W}vrV#) zne#E_;d+Cz^?4^4pM%#@O8fD)4qlySAMDR%d*-b$Z;w5?4SAH4DyheL*nGCuIY{pPPEj_VZ{Y zY{hctKtFU!U?Hkl95YQvCzp{TVYerxe}!VLAxca_&2FtGIG=^y;>s4NSA{(h$@OO) zyaL3>1z|YmMPW2X$xj9V5#o_ydrxv+!QJ|RkxK-u1b-V*B`O{PJ5kJ@6K*>Ac2jRv z2|dNKz_DJ^Km$c>v-Bg>?d~LfwS>wFb!jvq2Yl%1zTU&l4kDUi7AHvoO4p?37}*sZ zIg<4$)xRTnqXx0WIwLyC>OcibxbfxN^Yn7gcTgvDcfqae@5}@eORi2}uU1TR7|2KX=lMdA20>3}#0)utifBna*+HC*@Ku*b?Vd20>P(X0L z!jv=@0k;j!?4FUV6fLNV^0WE=sjl6Bg*uY3luK2y*A8Q_S+GDsrU=FjVbb1Ns;s)7 zK_tT+Bb~g|Ot-`pj>R*YC2ZItL|komo#$jFlor4iyJG?ubL({43E6AjLxSYER(ew3=b(9voZYapiKYn0tT)XWpHY`E zU%-Auq|ac^_a_({Hio(-;C8QQQC>x1lO&Nj_+(%GRpFqbpQ&C_lQBReTY@7V0Oy_%zpSNRL^7A|`^O=-~#u?UhgXng?#B9s0i6ZlT?Nty#9- zddsQe1J&+-nThqcS?D~ht;X{P9sVnU*idi*LZ2Qh*Y~_zn=|h+llT!~2C(KBisO14M+X1#(T@Vfh32 z$2L>JzSa|C1^Ue~gT+!SF3AIn>QK6FMho7#f#xV?5D@4*h4{rXMt4DD6(n^qS?Eqb%70?c>jEI}&ShvuSxW209lTadnMC+m&0f z&X(`;Qk~bR^Ihj10u!~NOt<)84%89Mc~#{Y(<@aRG3+cvK1CDpvg-+m_UZ%gt(Vp- z>f9g{&yF5Aq~*49(h?ru<)(l5q@u}yd|+sOzN!d!<~F6FqKYM?ih= z6ft+Lr;M0%!Bt!dlKof_>X@ftFzJP=>mvc^4VGUX%%NhW!j*9*lb>@;^9j1i!|!BY z=XGPp4^wwHK0#KYHDl8ERtcNrP@DKAY~%W5MoI&8ke*SI^Xf*A2Nw{_wAQHgf+}nI z>q{G8@MJHJEjBVC8G5s_b9*v&UZ~AjPm9P$!*$9y*{n=(E|i`>VkUQ@{9$RT&+KDep72vUo+I_B5+UYu~v!e z%Mg1i0r9G{;P?^{aOmk40a^bd&@7W^d6?>uEc%%e7^St*c~dcg z@5?mFQN+_smIzSn@1Fa( zj<ue z5{nLJ!;6wGYr;ERbF3JW4DYYhNM|$z4r37`w_Su56O@vOO-N2=5y&JhWWScyMT9esff3LWdzfrM@tl4KfOjPO zR8eAY+IcD96N2qtCJa7PloBvl>IPaUuYkf+bKJewDA?dT>gX%f-N>|^wKgq@y&eQk z_+x51>Uh~>q^sAK_}0cgh^c7X$!x7Sed=xI+gkEhI_ib1P8bzayh&AcuZb*;t_>yQ zsLb|~g5R#KpVquJ22+1t6td{2BiB{o3^tGC#uUz!LQg2MB20k({R!k3S%Sa!a^hxG z<+V|htU_S5oxjMs?qOjXoh4|77v;o~`J+UG^`VnoM$Te?ueygB3M2}< zkT)vIICtyPhMruF2fW(7`9~se6(j9u_GAKfVyx1ASIq8 z{ZRv(BlX-*Z$zhQPp#-k-3lK{juw2LD}S<>F^?J%PR54sQoY{XgF(XQnnxA=4G&Nm zx>G?~D#A$2k+e!f@xq+`I3&;swFVhsfy2Mn))Pmo|J6}n@$Vq7UgVVO$z94<13U|P zflA$;(zBV^cg`n={99DBL(f8Xm^&~(#H4X`LySt?Ad~cb3_{FUJ)a$wz1Z9;aep>< zo^6m#-OY@9Bnd@cV6$3HDBhjifJ}5m;%vIIveEEIa4ng0ZzgP@kV<-o$%G_QhY0K7 zvM8zN`>kxdM}J1n_4UQ)o_7syQqJU7Igr8Cx2V*n1$%@8$lCFw_?gvBc!P?Xjr`Qc zNgX2wXE6)UG0kvI>p4pAP*N`=&0de*f#nae=Yz5w(F&0<&R}y+*YDB)6|%oB@7wTz z0RZ?S0Ra4Ktp~6%b+WTHawsSN!F?2TkXJ>EGu(8`@L-@JT z7i9Z$$Yy$l9P80tFR z(N8|T`mudEeG8H(m}BUj$Y(I36d1me9baUP))z+)I<=;n3__}EF|4E4`<^=aW3ZZU z+RwBmNHk*+ z(?&vw4lVB%0~G;O`X}Oo3rkZ=Lf-KY{_ddRo?f~zWh5%$Ecj2(lH&OE27hV^QivtS zUeh|Y9?^5+bkV!Mn_bemon6^&o$byraA+F4M2%D}3(VD|7PecmAS7rf6KcM8S;bZ= z5qL?Q8=m!r-js-y7LE;pH$yzuEaNY6hM)&))o>Z-YG#jORU}ctpoeo=aYDsZn1ig~ zY9W$GDkMxTTcyY3Baaz0F_J z_)zOFXeuoM+_+3GE8*aN_h>Uv;t}OUCdlS~66xql0DZIkX_9hC1+F?r<_?i6gC&mR zC!v-}N&CK3FEeG-qzqLordE#nW~Imnzy3woP->{qpvTB}jQlg8-3!UPKhjYI17TWd z%ju+M5-|a37Xp7*bTwOOlgJ_lPUvn(79#Rel^U|qs}LWbQ1XnGpn$b;;SNW@Tj>V; z8~l6fv){W3}}-9{fS)ca>0L5D~pYbu5^99F0lY$|k91 zlW;Gh3}d+WFUHzMm`=t!JzEezOnG4Wn_9y6Z_(%T+Xh-HMM{O6xd!KW3;<)xq4-}w zD)zK78gOU-g-=Z7MMB4HOs7xJCxv0ozi09g$?L$s9LBx<3l)0PSE}?2EBj};}RwsvVFY8LB z#Yd7R5_B8&OPYe8VGq_Ef3<`BKwb*q=bs+L*+JA&V|xDTIaA>oUeWG8|B715(bI3XeGFEK*8&gk{gh% zPhWT6FcX7_=l1;Vc57Y7JWxuId1wptrBHXkN&4dDKclO^HJCQZT?*oyAf3em) zBUBm{9bA9ewg4q-h{(v7HDoSsz+RCFpmxPE@^6y05bUK?g1`-^N!bqvJxaPR-~o|s zv94DcBZ*N)Y^+DjB~h`EJg6#5kxO^MHhMoeCZ8d(?tPOIKE)gQ3%f(){*(5@@OFHceW}(nJX|VS7fN zE)REv3m5FDICFZQg*G2wC&#?fV@dwwvpscN*jtb|JmeWhq!It zW&ysJf6%%}S?fZfaf|#N!_ck?a9I1hK;dy`H21E_{1iWq+)5o@+>$g}EI$0V{r&wu z>WvNkT2nf&m$izyqVvdnS#+&%Wqz~5isVgtFT8VI7?(i@1>0%-*%c4W$1JjyW(5k@ z<&kDUY^%6V&_nV}PT`e6J2LdW%EJMSx*>Ux*HT*$Ux6LCj?fm@oNR>|`kB*Q!nby= z<_D4`d9v#JWD@Eeit23eU1%3clV(-U`L0UUutgtQ{56lEv3QqSb+v1Y<=JIp&tMJT z!!Jt&h{sUybDv7#!gCa^jje|G%&l!kFUHsZsRGe1!`z{Q0RW(+0|3DJ-;>AA-r3UD z+0@bA(e&T*Kc|k?rPF3R;_po#P}&sic<8~JTSt}}^Tkp_&Qj9QxK6TM9af5PRQz-# zkxG1X&EuKhEgc?+fD(LJ1OFHaUeq@JO9-fbB7NTMFXvnQw1whAzo}FdRhD@&{P;Ol z#`Z$L{QUjAwBv}{pWN*&wWG4bq&)Du$INIu%6AEAwfN+n`Rtlhh71)JO+4IbPVGdF z+*Q?SOPnO@4x?@&NyU1q3MRE=aq-F+50u6&Mrk+O-04t0~Fu7q{ItEJIlZYo%w%a%sgcbHfgHN&@o=w zLsaU+;N9d89|!u~84X2JO~H4JO!_EJ=y9*Bfzg{rM7dbNpLHNaMHroiz=NlF6H%Q7 zs$S^_8d<6lz$s2l@xxty{ULL|J`OKGk7rwVkv+RI5u-2N0pWKNkCswP@8>uA=V$Yo zA7S$pOcHk5Qg~F0cvybN%v|#(DiVAq4UTczi5~4|P?7?1BNcDo`}ek}rp5bV5ATo7 zE_xG?10Pz0xueVm9um_K9dQXiqTGG+NLu_xrDmD3#D&eybjgP@0-S|;@Aurz(~u)Y znSOqFx4+ntE;7balbEwZ(Q><7MIKN!f&7a+U8V*)q|VXA9cqd4)@(Hm^?9sx6SauO zRmK^pbbxCLUI$DbYwLMzo=}4uYncvN0!D0;NsT1>RB+r;V{fo#{q>kM>8J#2Njv^e zER-+PLh)CY=GGq5aGFx=lp0|#v6~?Df`@h#yW&XpR+#`taG|Bl9%rsE{=-Sny{x#r z@mw{{>lDLJ27)Q%8*SxG{So3(M_k~%5Q5Z=jUI9rkshCFyou6MFZ6h3Dm-r+vLZxS zEZ30{s4@W+2KSia6NS`sqcWd&qdKGoD9 zP(qNhq?RC<^I(GiZuQnpSk9Sgy`)CYOh6`wqa*X0iKp#bB$0(;^=Hi*lO+!8=P2m5 z5>VLmAz+2tNIKzd8ljzYxE{1ND)6dx-^S(^>7K>z=lE%oUW>%be}30MYKn);EiUo- z(y(gD%U5UCWN*m|p#aoYHWiD6>Y4KoONs>VaafevGx4s=-#pLmT=P`h7!uHWS-DA? z(;HBVu{>N@@xL%pU>!3%xK%YUr4u?lhAb051Q+E)AQA6iIS#T9Zb46@iE%F$_9ejp zeWD;goNkR1XEF5`R3IhdMIS8gKY@4SJ%HdTD=-l254c)%d?fJBN1$7cv+U_HWQmJK;~f&KrwksGjKq8l*sa@nf!TJC ztXtay!~W{Ru3CC=9cz$;V%nGY$It{19Z`gt)ENi>qp8sQdQAx~q_b&6PFcYTRuO7- z^0={q{}!LGWD9%Zp(`ElwfNx-y8}iD!Pu*!Fni*Uv|{XbIWjEnmm-ZDeqVCg3r&83#1ILe|q z`Z3g;3%=5wZH7HD(DeCEMRs0o&ougVi0N*bc9jEy&Z&>N{H=6KRk3;A3|L90rMOzd zAt0m&qi0AbxDQ4V%FrgrSP&-hi2f5^q9B2;=H5h^J$&^mv(xbdY}fD){FTu z_HP*%n!rmt8O$&^J>~k)gdV9Xextd>D^f8Phe5WIGRuj=UDo_Y|fQnC?dzSzyn8>(TMWc_2x;h=oHT=hdsQLgptUKpdiLY zWJ*SLa5|wY8LcUbsOsEdZ~G>QF0zAHQB7%cyPI%1M4t1ujA{Zhu!iQdNC15y8D@V*lej*NC?#qm&Yjv#A;0~(Y~Kdx4C^vp93T=5F( zLH?SYjF;S;E&?=p%3vhT!6Ld^>l^%~$O^`ijN0aN0=oOC5u#Qn=o!vRBUeFuzm;WTyy)&)(#~vH!vTrnom?G3DkoOw2M*x8vkHvKfqaR@a z#=(jp$f?yj8)HY4Uy~ix)Vr9pB^AwdNQf6iVu@p$#bNSDN#u9ijQ{z3`s&iPl`W&# z^&i+@MfDaTk~~ zb(9=0e124QA`FsG&&O(&o⁡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

Ht-!i~xw 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 Yt+_8!yJD%W5zQg3qOOUk-l6 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%0AA!nz&y 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≫cw+>t7~YJ6*-%To?O?lI1O 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'yxSz#Yo)M!OJja+ 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�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

ykmDn5+PwaJ=~Gcqb0}>0%Q4{5MUj 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%0DY;DsrBIAyCplSMzMn@A`XhCTztuaLzjQGf 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

mX9_KSXI}{|fNB>y;0+aenZ%fD8h3!w zqh#)!wtP{Hrc3W4om?PL65R@GFAnSbjzNoRqQ!J4Wz|xa-u6&^bI__1+M}POV*iv2 zw+3>=9g$a=Mb{{_pcmK4#_vaq8^G*0AJ=y(oZ`TXvMIyH-l>^PIbe2-A zms$J|#xK@8q`NB2E=cAXcOQXk{TfP_?p-p_bf7nqyeUH;+OGw<>4 zZl679`BHn4#FvyiK`I-c_p-tQ*te?~sPdX`(gU}=AY(#F$>`Z9MCu|9r$AYlR00TK zc#$SooJ1GtzG6X*ib@4?%V+N=`a*bSMke;D09?(f~zn=35R?iz6TVf0AXIws)6YeYq*#3VHc zy+@w&(XCNoGsvzsx5b-hcl*!hkEs5S%Q;k;_O+*y4K_HX^^AnJH>hf^(I{tDlA;ahL>pEpot z=3Hc#S$>@<*uM6<=BN_WbU=>a&X$rkt_82S#4sOv2XgBl?@@$w6)`yTNAt_cwsQpl zJ$`?Ae)N5WL0O~M?_Zt1#9IknkKsMz7gPJt{hFpoi$g~TOm#JIlng0ZpgNIj%D^&XFeN*_ z_ecXUssi89(3dajmhrN*X3yMo#?+zezH;-%9JJ=EYUZ9d(uBXWC=0xW^VJjaA9Qo5 zOw;VrEz}BKT~cxyY!D%OQFalcgala8_brZ}$nvDR1Q###B_9$INa@F9Pm-e#!{5Y} z1P!UuSyJyN_Nm@g3A^0ZO&uqo+0o(tj=#=;c0h`+cGw?x2OU@D@$fR9BqJAvjPraL zPwU;o1GNXE5i7Y3louc})nSX={c!N?pSyDbk_j*&wr@9ncrATUzstSHBb|r)`A<+wy00qzoX*x1S>s#sDU0=NQA5+wM(0cr4Z{0yY z)V;!zl*mGCQ+ZZ*_V9Zr-O|W5&4vg zaVAAd3$n;YiApo5uE{)Qz@hg&M!S$IC{V}?W#AcTYkrK^azON&EKzQ zn_O^!F22za`mm2rcp6}a6hHzl?Vu(zL{yo3?f4qAAjZWA!IJ!}tbSw*N>QIN0uc&> zc}8D7?Uz&&s4c>U4D~?1 z;8h*WiV^r9KA@<*V=V{9!~y?pD@Y|NctunPE73d@I4CLPPLdCBNTw+5>=oz|MyXZz+IrC+t-%H{VOy+^Uw2Y_7e9ai|zU=_k>nqBvCo7kR$-(m!>U*S1NHod3;Cm`a@z{*7cMI~S zrlY;NvrDMw)G3Ew)X&mtS9Dv+Zwm;1iYh9iKv{9iMM{TjoJABq+F6(vlby6I7s=zV_nv&Sx7YiN)7&o$Jkv`lL}xmU3*ZjGDxt|4 zM(F|el906q5VOfS*f!0jq?o<-7`L!9jTaf;07T}H7aTJ^m*(z`MKPSucZS>3IGZd$ zJl}yyL2kW0+?LU9<7h$qoh)XGmTI6oLl#umDF(m+>`fEY=>UF-UdX73@9gb9e!R2$ zWM}Wo9W)^>fgHC9D`iK^+c4VgYuKqK+n^Th@DhoxQ7JD$xuBb(-iPW#_Mwp2LU_X{ zT4WeYD8l6Bu03O1_-D6P{kzR`zbB@O&g@=KcK`g9$?iq{ji84C{NJ6?5MFAfv(YK6 z+U|J-FYN2);_TpW8V@(z1qYy4l_1ewByQSu&1tY}b*+C$!Kz^SwhL1>%tvbHRiCEE zr2}-c1t!zW5$sa)g#7F61|;ITSSUHozycQ^VwYp7&tkEm-`ClL#*;6+J@1hcms}(h zLLaqNLCip{;l0Q~gzG|GBjgOo(}Z(2D?fy`fm)z&$Yk&zp)i5WV34qL4M^aU9XiIe z2Qd;+Jaq39sG$Wd=;)aN+O*W+H^N&3&`=quU=^$K5@O{Jw_yC>N;puljk*wOzhjQz zJWez7)OEJdB#%A)my*0*-gQua^!B=z!y-$FTt>`B`mnLV22{0{M!dC6=gy9q&&~xR z*lLWb4WXRkO@22@(+NLe*yg)x?7Ck2h=mcNoT)q2UXt-cr%uU8;>3)UETQ&;&YI#M zB`PU$*Uq91a;$$kNYLP;jV@%ctJxus(V>8qy>J&vgAlg8$33EkCZkgWUCrqp#_H~$ z%a&Q_U^NDbpJl&Qz7j^vvReNHj%Gn)(m<*9-~&*{|Q;a66|gM9NwF%#7xy zXMCp+(z$A2lt-fCAjt<3^5-->=Hor_*P2r13KY-VCSO@^B2I3;Pbc36XaPP2#Y4Sm zIEyb6{pD%LF$P)5Fp!aU=#b2m&E&kbxI^gX;Xi}w>14s_Q83tt@7`{aiYH0^I!kQ; zw5+)6jd^nM6;Ub18e^%i2f;+eey=t7XqjoC9TK|hpK{*Ci2QOqM9c5UA(L*AK{oi18qSXlu0I1%c+#xE_)4?kPpaf}yl zVJl(I>uKSsR99(zoFo4O{rexcKJqyK1AMW0pL0b({>W{SO^hlcN8E+p z$xm|Y!qZN>p5hkBpTA&!ufWizZ;k20Q`ts7JT+14jEQaPc6bCc8T2@ihtvZleuZ;# z<6PEMJA1spy?6cyP-Zn(-x9aH(`1GrFB3z+>?0y`H*$(ABk+OSrm9-AjKbqctP$=m z?wXS|NjIn-3iZ8+oXEKdVMeO9+KeraG^*_SqP2GpzO@Tebzpegxl^L37p6M`-QvZp zMCoSi|D>>9E(T?lR*OpCPnO&rVv<(&XpD)0k^C?-DkbX*yCozEx638T6RhkIxC}Nh zt`7Wa7VDO$)L2f7l>MBAb__|`omW{zV1&LESEl(H`zAgi=bfXYk67ZQ(1A0Wkr6lm zZbw5a({7-leQXW37lOjqPJSxl5Tnr+DT)MBg{yt8&KjBNlLv3Dt=8?s>|nAD zvr6`w|8utu&FWj7TYQUuoc({=tti?FAAQ(9SEmK8XHRoCvUo>_c-qRa)?ro;U{q@} zscr_<%A7j*jk~Z@KH}`vsef%|cMqTFSVy0qKm2aqa6eyYj%7`LP~!!f5Yc*@VEzSb z1-FrcGz zm)<4(pVD)Z)H^_3UiP4R(wm+;j22+s|Jd$h;Y0#bCd?*mLEn^b%>?6ujbKwOTb z6dms)@jmkQ8s%Dj1MtJt?KbpX*J(d~6s21&?_1wxJe&VaK0cc@`c+s+DB;x6#z@0fNSMT9kaO zh`#R>6{(^lbatTg=6Slpg!mvtu~D?0xik>6LR`mB%9?(p!Krm=!&nJHa(7NZGXBo30>m8`4!)kmx#a) z&mR2L@x>P%Y-RV>;)mOh&p$zrXxlMse6!VY7e8jptO*BgqygP)$LYG8Xj|Q;vv;G! z8f3q{*G;!;5dHR--PQj|B>zd|{s1E2kw0|DUt_nox4qhaFT3x7eWI#-P*RmRPi0DS z>20M3O80h>b#0fHuGykDw(F=So1f!&d9oNB^JB;FlH_HA6Bmjaos>AZ+kv?-ChG;17ro#6W+3^^2-F{LjAGyy+2CBI`S3IxmwZCI_4z8 zhmP=bb)Tl#nIl2_Wq;vqq5s<$y5W7X^C82&2ng+ZXzO!z6;t~wjQuScwRU%eZ+E^L z6dpr=$oyJG9>6MdzAERM)2%UBfgKv!XG51o4ZPLxseAv&(nW$Q*W77zO@+W_#g-1a z%5bxF?~fyfqh_-2U9EqF;ELiINPSZ>mFZOp&Umuv9KWoUJ`S6`wH`_SsOxQ_Yg z6P6}cqn<4^uV*zVGeo?6g%buIH4>BI%PfIHlYVEwSM%00-UA|Xm-pwhhb8z;OG&x^ek3=Ylb{HB*oMM1EeDOw< zI5SF;t`~f7{!MbN>zYR)?t-vcFUlmaDV9u9`J!ss5AZl@H~iC+@G*Qdz5Ew!3HOt6 z3$xmND6?E^!=Wv+vFero$IuWwT|+Jxj4N z%h(UQV(=+v{hmHf7kj%cbtxy=w`AL)E5t#({cGPl-2U&rx4Zr4KBjQo?x8zcO>8bD zf&}A9P2oC+`CHy0n#Z^~I&9=C&2n_>KlR0S`{AiAH>@`5<0ts*{s;K<9tD3r`0(Mc zPkY!F9T|L$pZ~p)dKMnqR{H;R4 zcW2w?oZ|8K&UERIGKthW`{7hF28x}Ulwu6;fOYAM4L5ND;}B9*FDCWHrZKynn&CmD=3f`4POR%-W>hC z)8#rL6Am}r{fK4mMwj{x*i9~^nd7H&q4hj#{)tSfd#`L&68NFo#Z>2whFRYcbnSM| zW)t}TV{B_OHd?nJTt}7}UvoK!{o##JyD;4e6(fiJ{A`yG=ePWpcW5+uAP*Hay$NT% z>NNb{VPsLC4r7aTZDo*D*9j2F$E}Yv@{blleni@TO!?;8S@>G)2S1J7!uAt4+l1Eo z*WNE&$v_!8|7BamZEd;VJ#f3Q(a>S?P@n%BHVjHQZ0!|g^@%50pXoM7g7KaZN9r#3 zq8e|1;}HA9wwqRE$FV??0!$ILNTE>>`Apq$;7q~JWSRckFcEL zmh~VKSoc14V+`2FI1R|E5FRW6j3`NQA7m-qCVwdJlvo}-VCH*F?Y4S*um03r_&_32 zHN)&U@C_}A|KqR1sT7Ao9)atW*o*vaUHu3G3tD3U82_skha z7GsR@h?D_=SVxqOqft5@Cm5*!$J{8!w-we|p3mOCc@aH}j^7=~jupnT%5C%Q9aSXaLP7i3;P1K_g2Hm-EHW z#>Va4#s=DGxa~KGC$HV+|FVA5e_6X_Zjo{hj25$bG>kZWRgiPqcUZ&8P4)6^`<*Z5 zO%2x6T9{|KMVdrrl*Q$&<6_w?9u|4TPSZ8l@LCE41|8v z+V@^Ka2pv1jJeOk42p&EY%q#F#?u&&L2mK;9iM?1n+)ZRg^Ahd=#x#NE$#ntt@eSe zeLf2Li#e(*hkP0*j9j0U5I~|#=176`$Oy)l9KQ&2+6F^Qa<&9X=Ui1EcU?LHGWE@w z54%-sIMmsmQ+K5+ft0ywiXTn`{w?G2P7%;0P}7I3CPlUTv9$x@gRUl=7H5Nik}RUf zMsEcUTDpj?8x8P{Grd*=-+S>epnaSoJIh@MqnXkE0Gu7RI3k(L-m2A1QhVDfwg=&F zfh3oXsmCIc5fjAC+2(^*h?@uTymh!9{QU>YW?j)i*XMt_t0Efc-+;3?C31M3{yJ}M+D2jmygpd1mNm9SsYjC&mV-mvy3ivhNlOHWU99DmfswG0@3mDv+ zydt;Dn$v+D0#?JYR(PpHf9dYRm$uUeD7wffz^j%Nc?PE`g%S^tIQKnCiaMU+;diFf z;}H#7(E&JVDnnPNZ7Q)%Odus9`E*J*`MqQ|NJb+*O_KuZ(g;pHU7euEJbx5;T?KUF zV2i~Sg>?kF<|0pZAD>AOb*xS&OO~ih)kdeH(O$Rw21oswkhUGaeX4`P!66u302SPH^$pTTqf7b)i(xOnerwRCGap1 zhbO!E8c``bG`CqiMMjyZFqOCT=dLbJNM}%Msoi%s9kpD}S}j-&EUy~16}6*nyscuA z-IpuvltYn7*)yBwf+PO*{hpQgwmFkEYPCSq-xkKxf#6NS=%xu3Y3>vfO>(>_9gR*< zFHsk*o~b@a=WKdcubARhwxzg?uw;NC03xP!T+wt%H#+Tm(R$8@X?9GAq zqM%Oj6njPCASed{Mn%O2DWeV5AdKW=V)Q)O@ZP;BtX)x($*m??zf9SZg0^_cXvpROob>W0mv)^rt@*ca#{IzG~Ne*_;AJAXbSs_{kBNWMer!ER9(vm#!nkaeOKX2av1$cwT zc^Bm7D5P#V%nQ?6Sx|}jLvcDoAP?V(PNz;Bp)M~N z313(1(EG;CJrni{(?e};$J0OS@=NP*P;7H*o85o44H-WaMuZNd0{@6+v=MMs&+tAF zfM*TO=lnK6TQ%be1J!G&J)VZnMJvCZG07^yY|4~W2(3}0maU2Rm~$dbB07fvp-Ant zgkDv7q4>7_Tj+6fbMrl3hD9Y{M9Diy4^%xNGYO}J| ze%bf_)c3ybdw&)-tuicC@Uq&2HmiiVC!xh*NkPTe5^!l%kJWm@p$AnDT6f;>(S|SY zWQr(PON3EXgT?~x^C?8bxFRQ6ja{~^MyZvyj>;G_Iehy*%|P|W?|^-BK4@fQX#<)s zs!xU5njwbM!F*PbUwlCx3#BN;4%zzk)HsAhzb}EIjV8p0^PDq6Xpor?T88N%0C7&BcEhhdwQP^!--h1kBCon4I!%- zr(g3-s)V!!fbG^XqJ-JC>Dg$SZFcCK^rx>WXywU=*OF(6n_Xln z=63?!Rt_vnNjchbq)C3t(RfsHKFu{UDE+Q+;75=)caka*lAPnxwQZY3cBst39u+593^8_Few?I3ZI@-b_NR?g<9GeQYW3U-lrF^ z%Jqs1nO5VF>}MH=-BG1j%aFrOfu}A^QDoQw=7{B`gey5NP$r;6C#3{mRxAKdnZ0;| zS8xA;;#x|xjcZ|d@`3ICzQyckioJ_N<|}U>?8~V%2OHM9Fjl@{Zy=#hjBe~-qrzq z+`990Mvu(#j7sH;(;U17M4vs;$^&2Q`hL$!?ooUo$EJIZ9o@zr01lH%+&5l;*U;z9 zD?N^yx(7Wv40EbyxaFa-nwC>dv_lZg|`U%uCcB13=Zj(lc+2Bs!0pT?I!s+7G3npjNZ0&NWi zX2;6uD*jX5vS{#R9?!*bo-K`9RH2+HY!Jk%+_6yGwmFRz-9l6u#7kZ?995UCzc}IQ zrIlY?8{%`7RW_Bodo+4uX2%|}@iTMZ$ZXXOo@rMgN^SA7AF7x`*3B5cU6Q6vm*4gP zLoLyZ9aW~exngnL-EITtLLN^Cp9W?zb37o+oEtjY zB=j+-+tcauo0YR5bEK)gMd#I1MkDKFQ&#EjWOgYT@#!HEu{q61B z#Gi6@?hL021uv<`T!>1f>S5pd)8aGDuayDP+)eK77&$LM^9Ad_(l+NlzyS zXzlm%@Pp(fVX&<4vPxy&^k~rbP$7rbqVqyg;4%0+o9%n(9QY{UuHRM| ztLt6Jafs(@YYY z7Q;U@EweL=SUwqbELeZl+dI{U2rp)VNCF7C2X#y9ye-n0QtK~(S1UIup1jv+Tq=NM zEN2AKUBGelS8l}-uTZ=S47Af5GL0ErYW%p!z=Wre1xDkxqmub7k9hrR9Z?&#u{*lE zfRk5a!>fg_qJ&G50&4ga}lS8VfR#SuBU^ ziD0Lq%$4zmGgzAKgrQms3DyZ}|IbFMy ziVF3%d@2=PHez4w+wr-h^YUvk_a!pGKLnPlL>qE_TaBc%X=iJ9Lr~LuNx#ytgBF`3 z$LS&^ZC0*Paq?e>iHwIkj5fX4RWyaPl@?n{wQRdZARs$Zc5S0VA4?CQ%Wseq+^mgS z4AKGEc%#Tj6K{O*e@_0d$*y1M({PEi5*EG@s3--@E`BMeVo z!FNKQ%m9J4={mQNumjBJ;surqO6tLOZDZ`eP`gqRH})1e@f??ub;-*|ws3{Q=+twX zSlh%)iry)nw9l(uk|rN-&aJAv@3?O~`0oLQ>&3lS^d3unr>Gsx_tJ;SbluC~IQP~K z#*mzBMFqTxXuP9mk?Xo-Uh%hqG$?9n=pX^Bj7AtdMViGa>r7#?ArGpiuP%*18r?n+ zoq57Nj3iIY=GgK4m&~NrgTYabiQ@ND$)Y5-$7X!kVTc8qSuIoGN~0y0SG{PK7gTNx z^_Qkzt{>jxsfLu{Qrn!YlgeObW)u4C++uZCdrAGPDaMEx$7k{I-cRpyo`Nvw{cfVg5q?x5tl%U;BoodpRSdu9ig=ZRV0EhvBRyV{Qqss2BB;ks3v(sS-_)3` zq6=ik|IQj(_W#LwKH4yOMGqztYNUm`c4Gx8&Hipu*9(FvFZbTmc*xGvS@_DWV@Xq1 zc(t|`pgo=L_e`~lc_F_Mm3bv17r-c*3g3%3HAo1U7YyvvBrnXFV@_03MVA2=17Pd5 zvEta8{D@koX_deB#m#HMF$yQn#M>|x_=5Fsxw~Y4HH6>Iit)?;J?qnKx6dg4vl&%E zQ-aG#d>=M3fr#-pl*!jViPN|cMlm59SXz-goW_x*NKNPP5>|#j_nc418=Xu@(N9=# zp#CSvl2I^Ssil|JByfmU(tEKpw<>13FB)GCN4}M3c1C@XlS23fL1pL1<@6Gtdg)#| zZCaUkbI>~UG;T@QLmR%oTNBos?TM<)yvKwa%Zi5Y_g^~rEc%jN8T~e>fcn)9VuZpUrW4eyz z?zcQ>HoCDrN!0iSxo{gjG%4gf6U1y?fEs^@(PfA1Ii~o(vcuR*AflWnW^iLgvkq@@ zaReT|2i&e&qnR81Y<#Vr9Xve#8!lCLbtsIoC2d~Zc$$B?xERjA z@=Fs=5ksA9A)X!w<=@|nvCce7#m{0fWDSx65OZf;?<=HxPlJXJN3h0}m;&Qq7J|r^ zE*J8Ts%P(H5-em2=^Nsl_+hLDOaE=AasAVZjI)A3M}i`?Q@mtU*mv?_Psvv__Oiu) z=s&TuB+DQ$eWkY&GQ* zOz{_^V{jXoaoO^R&=nRTmPfE2@^!~&c#_lm=X&2TYx#(! zV!~}s`LOu0wl~xfj zVSG&|eFV8UJ~s74okq2~N5Z=mnx89Me83;A322&yGCI{@tL0wR}=xX zdXcTD2W)F&+Tww@vNYz`?qWj1MR0X_NZzP+%`D=ARhqk>^;;eq8c~u|;-RNSvcP zRl#%pl=t$m=m(`+#r`}&H>M8U=g2+??KVmQy=VUf*^T5VkIQCwi}d2Az(K^+-|^z> z4=0#Hj{j9oNWk$x(E%ojN4Dz79ni`1nKzHxXZ0sd?Z}H6T@;E)wo{6}!H26Pt>TZ7 zCF88fN}cUM3?}4=9JnCP{-|;^*Ll%VtaK54nx1pbAlJqSuzgiU#hAJnR?4&GQyZK= zt_z!)QJr%#YpFsK^w?Pk+Wi(wQX|BnAdI{_70mdRn5>lU5DV+wTEn++XSCoSamVz` zHkNRnKfbPMWcb+pJBK-tvInc`eA@GUf_P7U%XyQ=RZr*=p8>tk)qh56_LkJDJV}5wA1+0;Vw7QJ+P)&QBwmx>YVTMH9kWM)hjk}#Lg)7R zt!k+#&Nb_pO>G&Tg^Ut1#8s7_qhT&b7~J3;%RlO>ifR%UZQb|-UHiu7C#@Nl95+{tO!m~?r)3>!Nt97?byR<0OY&gRYvgLBXRjXWSe`{ z9se)Wsa@*|3CwjwHPOP>O4`M#hqlJ0Z9(Vr;oLpm-%-Ipu-$N&?oNGEvJw5{>AF>Y zUDi+#XUTw_bIraW8!#2!%;dMD(!U~0P@39G)&N@f;)er>C}l(};!{G06&M3tWFL8( z+?8d&)0{|Hv2k_PRN}OJXB6kN!`7k^v8A$VYl!320pma%jWf0WlW5a7;Q_Q^BOS$2 z^GoLL0TVIlozemfY8b5bDH#UI0n*3d4}#&p^79*RKLdpH?s+9qI+gGs4|p2;BK@v( zV@yQ1_rzI+mgdm_GyWkK2;_^?sshHc2AjAK8(1jzOpo8d?y&LCi!J-3Y(?IY_Vn7! zA<|{^qLCm^(g4X+V0@S$hK6&<@8?4xjKgsfF1mcn{zNe| z-(&P>X*8>Vv9Xwto9JxNXxF!sv%Rwk3w(37k(`m6XnowS21JTirf1Y@;Og!KJS<2c>1AC&aZs%`FMhM6xi7#DYg+^6K$VS41i$9=}0+<=)J`UcaZO2f#e$n$!9UFZS!^FdP{-O1W&oivSlTh7axm3rx3>+CM#s}O|hLqfL=ry(^iQY zOTw-(tNxgrO_a_#H&Do3>u7otq@5 z3foMca0}FVM2$!042P+DsWmBOtrqivY?#Qf5MaqP=GX?YM-vpZsYE6Qee*BsI3O=M%-xd27ZeC<6pkjB4f=4ws(UmMM%k5p>Od)i zhYpV9Hb({u0fSK-gmo8tX*O+OAZ(YZ`IEujdUK*VzUGLEn-#UqY$|qQInq~c3zu$mwxd4^IG?NbXptg z8sv6}q5R%qE=9jKei1!L+Q;~seuJ>r4ltZyKvv}1CGg%s{Pj)7S3mehH|YpusYk3_ zGX@n=9Ws{HifDRD4VXT-`vQ*ky~^-l)}@`dtvz*AEmFCexW!54ih{M3s4Ws4rMu^n zkg4wC4FaB>UQjj~C}oGsBe($PbhoClTzl@W&EJ1qSuI%yIb&@>;nvWK31a3n>+2?y z8U;YSdcC9-y(_Mjik6{TDT;PKl}FB3G=l9}5=gq=jC~~)L(w)hW%S0$WLsj6T(SBC z{Q4aDEofKbU#Bv^n66gaRcQcvSJ*Rpn%JPNpe%~}C*n=sOZ zyVHv-4Z2~q19uoeKGz{ZDs3na7mN`uWEaS#{Ab11cs>#zSwobfl{Y( z)}R^m27z{jQH(4j1#EZ%nC$ia9T`{mY(H?eIAv&WFo!hhPfoLQ@U~RHe@i)st8<=4yu_&ssrRrQMpdcO5$Q_ zM?uxL8As%RY3SX62?Nz#} zFaZl$?#n~`2t2VBmb3OC(E|Rfw?k4&k+HliqCgm>kj4HIZ-@0eG3h|WCx>&*S{lLUQOu9ZHYeHU z+rw}0jx&H%dNa;q@`2Xv7iyD&`#%mU!FN8!;518*9mGhra!h5KE=hVbODcr7TH%H` z>%P9k&YEs75tSbb`y>}KVf`FK2qzlq^to!tJbgpLl1yZZUs8wWRjgITj)pw-V(`u_ zdsFcEoMOydN;LR(@}qDQkN(;%9sNb2#mEotLD@~?Lc)65y8erL0ahr>hu+5YpC-K# zv8?1U&3-B^L~Q-RRBULIu25D{&?6^2_=A1%)5calfV2*>r-U~mBIwKlVxkAA`WKn zXs+3s(f6w2EY*#(BkFvt*<2~gX4L*rf)Qkgq7NCvcVujC7K}=R^o~46Q@)zOsxN^S zkz)D))^3qUYc8~@a=;6KXTZI`yoD?AxFu5V#oZf9Q~GGr*;Y4=#m)mnTPcl zkpDjM7ck8FI8br9f8_5e&Z7&D3|)`}PguzzZSB0dk`%mr6TQ?6x@) zobkino1o6buogzC^Zi$9iPqqr8>HZ$h%V?c#mI)8VOZK=kX4WcBi}8U`<)!;CMW#- zmJP#jqvFxxL|V`CWgH&0ckwYZ8lb&L0z+-SyZGxBb`8u{>EyZ>XiDWQq!{}_rdk^U z8A7FPm}3tt?j*T5o6s!|7}ifBJfoMf=d~0sxr;H4wp%Q*uAiEgRgOTSMeYho{q%R4 zIB4^kQ&vYY145htm8*wV})FTjx2B6pOq`sL@CsMjPSRbSCK%EC$&w0tO|_FF=~)W677{F(*oYf!v(JzIFTfpX0)yaKA*D&VJu%J|wcG08_ITF@&FW zt#=lyR#9sISxGMa@4QsxM=sDQ(7r2I#YPCFWc-s<2uWj8ldM@+4p!&5K$51rBK`gs6Y(qme z-;z42J*y<@5pOwtc;O(-jNb(+g8M2D8VE|vNWy+N987ITF-s=;KiM|X0;Ln44kSx6 zWPMkR@{;7btaE<`3GKGFY$(X1Gc@0gi>$gxsS@g$Wuhs!8$#Qjto=2_A-94mE-w$&4KaRLr->=uFha)XD*&*wPVsYQZZRi#jciZ>dDKOlPAC5Qi2uI_d z!Afp#>+yx_!sanV$?-T7%&7oWk6Su%dXbB(5b{S;^{c18qhTw){TTYd;8S=!t*IL#>BnzJ#`@bH zeieC^=PV_z7(Q)Nz1UhGZ!%r9>_qJiUiHB%2#Aqf>Yd3IhR)m7F5Rv-fC_@Ch{mSq z{07udrsJGrGAVw-gMNUkUdKr5nq>}Wnpr}iHz!?^_&Ou&Y2_&diJ$*0ug^aryQ{?E zx?F}Da1eBtcg11f1;?@0AH8mVPo%qj} zh%mfAKe3=m_nnM+hPTS<=UqA#Jb%LL!UC-QleI~|6C9I}wRk#y8}eyLBQeSL^ID;y-$;PaeTNNvQVc>-e~=CDubF!x zHmLI7UP;Z@#~_Me{ho?J)u^Y(@DPNr)KeI!GSY8Qf!35&t4`9gy<#c9nDO$OwT%$e zoUmINO%?)OphVxxNTKA~Q}tEFw3I}{fL^TM+Y>zN)?ai>^bY#y)=<{;P@ZEK4=9Dd*W06kyy8AjVn>2*IDAf2*=<~zI%Qz|HU+43qUO^f<1bkUPf+jwwca8z=QS{A_3XhtlLgXWH3c6y%S2)3NXijw@stv9_ZgQYSE1ibt zTI`Pv=qUwtPjZ8Q)}8dN1}6{J62i)ng>lATmO`j1j7?q^AATW~ zWzUIk`Yk&m7%S*RcA~V3*@hItufN)?*h!(8Y${YOR!tV*DZ8h$mN@KsZYCASe2XWf zvLqLJ4gW6EPi2K^HG4>Pa`8J)ItZMEoo8@G?62oAp^T-`vY%YQ%}?3lNvyuz!4KfS zt%t+nOPTZktcMo}KtNdk%fsdBWM=F7PkGp-v0;0_j_CEGftUf1uBs{&>d*tTk63i@ z1zIE3^vFX0ML3IU=0p-lE%oM~|Fccxl9FJP0Wu|H>ByPF!V*$I!rIaC>f$^_g_0gs zO-v3O!=++z%1h!rC0^1uwhJj|+N|N(#D4mC*s(BoHg<+!*=>GGvY?zB`dgE@0hOL) zK$07CP`a2B_F(fcJcwxj7kQG9DCDouJ>}EB+|7h`?K96bDyg*UKi$61R#`|5@~`#i z`X|8@OAG_^w8u~tL0n$`20;WuifaleZPYKNs+H@mO0s_v&6b;#2{Ake63L~=jvVl8 z+d>c35tP~>Nz5_X@_cjIX-UJYGgu(Shx4REKp*>e!qXU=hDE3s5<@LRyCvxbXQV#@ z`UqjA;(~W5;a0x-%K=E{?j2hU%*q&oSD66LL=x%ugkY+jO3Ty6 zNa!nQ+lnoJWwQJxbkeb1?t*Cs)=M_JGw~V-R`hUic!KIVylenMWv8$f&q3TUgDTlH zM`sSSR0dl})Z8$i3+i*7I$IxLg<6d^`k`4Ke?))t5ySZ^FSfX;+IEj47p?prSVEH1 z@4AxrMS*>EsxjW#qH0qn?E-^e*uEa{_{oX^`dS&>ev{vePi2ft#4PJ4BlXf{GP4K# z@LAhI9!-_SYY!Le$c<=_NtGT%1@qFVo7QIitCS+{t~=|*+fTXEo)5VZKaf%@!zBfL zUsAopZ~$xO17e;Mba{8IrM*@7=l6;BI}!P+1`Ls=f|i^C-D6#D`~0B)eo^Klix=(t8gd56 zTYt$?GLM%zXm@jQPRV`l8KP)2kO6X6Nq5~Z=Bm(3b8?6E ziKL}}QpgMyDmW?x??VKZvtdcIZxW=Wk!G@-d!I{k>=y`x45Ql8I#RpFCSxkxE_b~X z?WC@45i9Ie5L7W;>Q&y99PlvzG%B@bO1UIg@vm|>b7-+4&dLuHf=A*=k3qSaX`5Z= z*1UrB(g2+JddulcSlHB!l#vKuE;yVHjVTFHovb`G+t?||v^!!RA~_PCA>#|GUR9ty+?fNQMVees+ujGSOg z6AJ|jY(d>KA!`niseuI&%Z*kQOSaGgG>adW@{7WsdR;)6aCPRuF?9&jq<2{7EfL6e z;;(DZSm#>?7d-C?)Z$cJ1)_&AwK zdPAN)H@}#?zTy5m2tdJek`h6IfY2dv)4*)tdz{IdP!Y+&#&3WC(+?EXbT z*M|mdEnv-;j&N-&0+`{smhUpJt5FO=jA(X#)Li6W5NIKVf4_9+b!Sc$Pmv+LnIBJO zaL8WiiP&@mJ1=k(oB=+&);bFeKs8i(6z;~IIUn_#LWb33i>$HDDgx$`rQT##YNIm# zK)$sdDbtAfll29Y$cI%{Br#d2@#CFEG-wr$KP_{rky%QbQQNMm+e{dB6krh)zheCm z+=b@OX6f8~A2Jh5geAnfRgC}#rnMI}Z7XfOEeFM&i^%u1vT?N+I+e&Z#V_EV@)8C# zV~iKM8%s8^x6U<{vK109iwQ4fR4c*~5u0ENA3}&#WAD~+9iI0(6MEb70rFfI&h?{t zXI>hqLud4&XGdB_&5Nu71v5ki-{lk5`3tr6arp%-GiDO{Aj#&9Lr1&Z3JK~ka*`Vr zM7fDs#vXWaOVDNoGI$0sITU+0Hcr}dzV?&j_fbqP5*r~~G^gAKejuh;WPSk5@%@(r zdbL+=n3F{#D}C;=q4{uL9Cbe`Y9H|UO#2hfj?XK6ubWn!SL+7+BBptRI3E7}iHvg7ec)MrFCG7im|S za=AxyB%ztS!0^<8+DP6EbmF06at)ur4?Z_Of=iJx28lw3*z`FkQ@gsA7oA!RCR-bf z84l`XlZ904+3D%}(Fermv7GVqt;Ub zb_IW$7Knng!pT)VzvY;G7xE=KvvQe%{~Fm^2r`3lzm+5C8rjIlFHM&p_PxG~XBMXE)xE9y7J zmPLw<*$Mh=SR*AvH)_8B`Ta+BwG6NEIkx*IyA*{_USa}Q{*fQAOE(e4E7cbTEz@&z z@~n(9*F?z%G{apYL?LkIKzPyVvXiWBvdYRW@&h;jQgXmvrO7ltB_A`SJ}HQfbeHl? zdE3U8QD?!R_b7wuyF2jvjxIthZ^HJ0;lGF3Z}X(boB;@Ew*d$U<9`hEew%Wr=jUA@#O^+h(u#=}FCu@8qOBA@zrc(=J!~)H@NK%` zv{iRodwk?DEV7r`=T4`n=q)=b;@6+sCw>pMlUbh>vEg2?{BzbZLgf~IEEuweTycyCuO;b zr;2~;l4Q~+fSz9_e$Me8ki*ab0VwnSi{JyF|5B^|8kHfdK2%CI(UyJpw@F$;65i@; z5upbp-p(b(Tuj1@%sy@L0USAE$=Z&>f99eSc~;5grx^hJ$6-8r2j z;Phkxrniy01WooaMvKi5oA-?uS;k6M@aEoFcYBG7R`OpZR7?d5xF$(PsnCVp@8+b! z+V>vkk!|&i2G)tN!%7S4RY1N%_>m%x2(Jg_4_$te$okqC#hjSqoxzR5{DFad^pE%Z z^$BRdsFKx)OexCi|g`R~>TUg#1?X9y^YcVb?Du>mF9c@e8`}+AQN6LTVqJog$ z9$Ej!+dfeavRy_ND=ph#6)9*uEEidDfp(c^tQO&b8&yx-j*c{a_Q^l~50%iyciWy# zl9~U>S1?lBrR?d7si#U)M`F1}T20X^gV1R%VCJ-1%tIjmP142b<>B~z2ZHbYfy+5x z)03&6*~!J%BRM1R{rY}+HFw7IN;S;K(rs?lp?~z?@K4TpH$6R40%C z39Pgy&_MOw(_Qo{hzJpFKd_&+k6qqYEQluYc&IS)+ZFSv8&C9u;bR(`Lrbg^m|*N? zOicYN@TVVJ153#Xdd3J37|Im?%~EJ$Lxn+B{o&1PUA0!P| z{w-dmxsL@cd25D51FCr2Xt+ZS0o)Hnqnr2!@Mw{3IZfD!D2h$|O4%kU9~ZP-vQ+)x zR}vj7Up7#XI?x55z)Qvlj*c99OEh!J8GWvZ=rmFyR}7WenmVTiZO`jX5Kl zC?NzJh#*N&Grn+Fs<&@b#okap*PsRN913P)fiY1H-; zqigP&G?vPq_D!V*LG-C*0AsAeRA3vrGQv8Z?jIf4!z^oe2TIW*jxIC%_HWG&M*#?V zb9s2_5*U+f2o}_;A(ApmSELW#tDz<|c`bcGTDnc{I9~n&_G*))ALO|WwLM^%$*Fol z%GsdWR{&_I1AH138g#Tzc$Ob1^~j2!{F+F-S06B_nfy|V2YpD>O4yXU0*M`pvY9y8 zD4s8jW|qhXqN$M&*(bBbMmr&pM{=RJDS5X{oGU8lEe=p9d-tB`eUX z=xAu1Nhlc9s)aY?_9)ZokH?E9FjI;V7Sl6+@vApojb#%*`ui)SA)?`c#jwV1df|Yh zgyM$Ym(%{-*AQFtt6eIM=EbnLb_>DxMU6G4nLfF5~-4-ZqTG zg$6jrDVS-(kR)P8W;Jw{##Rg@p!P38zjs9OtYRL`TpTMHLK>qaib=Y!g(H{X6yZ2# zF1hlyU#;1+J)&L!ak;Y}Fi~9c#IVn_9T9=}5#sG19K=4YaLxOPp&<{#7BWly{ocuR zFk9C&Q4+mH6;rz(+HbAhhlqHOMOiqs*Zpt$4gz1v>Wk9_dr7!p=>8H?_)7+Y?!#WM!scCrJsZoTV2@^%H0%R6H6H*Nw^a}PA3mLEw z<&TIeZ3-}zcSF^+rT@Z5$5J2!4?{^9t3>Qi-!8$@vPVpCGhqkV2;>B|8BOei7|DnH zzBdeIrJ-OdD34eh#&BK$8VNPRbF-JHrL}O35bC*469s}5rZFUT=jP7bgCKFC30i+E zVS_>90h;CU<2_xht}C36->8=$j+7?^Cmg>!Z)miZ-@q5RE5ez#Y?G8d=QU%tpJQO_ z-g`a^Cy&wuGy-GhkA&Lld zm__N?HdMUF6s&!gDIFF>unV4_SF``f3n_l!vZzjZ@&rkIBl5&wh>qx@7b1sVP3n(~ z*J16tZ)bR9nJIX*3)EC$Zggo|pp2>%K$dZ+>EaWg7rk0}~y+$M9>9CGyX)wU)a)Ihm~=epVUm>BrEW6(U<2SDOuu5a)!T{<@I zQA_bT@rprQxAIaI&rO(LLf^FYzW0k|np(m_2BX_o5qwKZ_c$H#o7E6VIJ2?`=*@X* z6jaUI{{IwPeB}{`F8suQfF3h((Oxv*^K8-y07^wPjYj>34wGY@lf$wAQ4ABRN2IMK zWPF%(g~#4deD47UWgapZA#b!lU2mJS$VMikV*@AlKE_30Trt_bxD1MXGB|TUN zx5RClbSM5AGp%*%S?XEAc}w+b%Aw}^(fKvpd;vHwpCKG`0l}Y;lUlXl>M(VsaYp(D zQ8T?HM>u&{RkKqq#wBo$i)IYl5g$@rnI~{wYL>zi6DJyjJ+?0>7qEJhCX&< z)tBx!2&qY3Ux#A#Jv}d5__kQQRJZ?bUfDmNt$Gdgb+Py@5AOEI+&XiwRj$29w-!7x zi#SEPZU02%IOk?s-jc9NQFDn<*(`e%+>D9`NY1gdrp!Fjh`gY2?Js8#1>@>|E%?)U zv~}V$#iB$;=XGLii9nTs6)d)7^w4DF%mOU*oqWNz-E*RB1)DtS$p6N1tSb(DB^JL@ z%6T-UDxk*H%X1yRp~gvZPt%NLq<<7iB6#{R$jx?5@Jy zxAt6q?B~ppl{8IFcFRY%Do?cx2Sn?^>~<@wzp;j(FM=}Mve%Ryz%sdh5!ur8r>BU# zrTNf2Ev;xvT;l=cXl&{)6=fpzR@0A?-D~XIP@C0AqRQ407 zKZY*)V-tS~(f-69%l#;b=p}<#wghG-rb@zFG}HvN%H}Q{F~>(kUAu!|*Fa4ngP>`_ zPltYftM+niA0i_c1=V-`^yHe~;$1s)!MZU-Qk%Ha^CFrpvjZ34(nd`shhoYuiE<3=x9Yk#%cH=6}gWaY~BlFiulMBqkBu zb*r~K^!=)c@SR9aZ-k~bR3L&LX)N#kEnLB_{xkvPH4K1DCp5co2ad^dS_Zlh1vu>+ zc$u9ei?I#kT`E&R&SFpJ3dn-Txl*U}HB?e(e=)QF6Hf1&*07PRE)MMX)ceQi2;;WL zaVEXA>!Okvj@qH9{!oBaBS~=?%>HN`x3JU`k*l%7Q!agf{NEdIF0QUQZ{-N05!YbKORV?!6tu$+vJ0;iQa(pXFirxg%ZulLiU>V6@6v74pP@k*f zTp$JnCu}9jL$`WFQo@_iZaT<~+Vx_nY?ZN^tL0&0B?rUlQ>{jnpEu&E{d>dLtfsXU zgys1y_6j)#0+y!4Zu({Rg>=4aK6NnK;_5Hx^+K}*DS1@cmbGJk ztI!g{&{L+qf?qtCjKsBFr@r8-=9>MHYTmZvEO5`XmpFdY#$aL+(4QYIpl8}q>TJ>( z3W4xFMaFKX6AD!(^f)ZD?cO@!XX>S6&0DQw5F&)_7mhHnSt%kF8mE&`jto#|iSHxK|EvWo-Yv?(Iw6kbDpfL9`1v7}+nTygA$^ zqc{cy{wS|^m_6RX{I}<=7DdgfO&r5v$C8^<(%P)jOxEB#qjdkFC8H3crx|LMbgR3} z-8S#LbXwSwc{*OI*3JVSN-?TD6*dj}<=FJmC9`CWcy}lG^bKJSSdo*juys%JjnrBs zT7u#JM=k*6)j~CKrYw@=&`ZB-IHk-VwZ?>*q^PrvL=7L8G8K$HEf+eO!mdhn@udM1 z6y#3srty5J(Q)tM7PP$&S|bo<6*Cs~am({e7$T z_+0@mV7Yo2RD#QGO}ce&&?$KDh5wj-mirtsSCk!n3#R*<37EU_J3|EKHDM$M_NNh8+B+7nq!cg30Ay~|1Fg>Y@g8beXspbLA_)>(`0Nt+@CKv$W0JU$?U1QGJ^1%eg($cvVoOLcOSdi4G-&8N~`Tj z);ykq7{f=$7W2IRqbd<#w~g5#RnTwx>#o*I`pqcH;e<%QtHDV8khNZ>8*;=uE{==) zUL-=biLWE?wV&dyiz3HbGiJI$28cw2E1+cUnFCu(}TW+ z)GPvL`QHkk-lHhQ2k`trmt2NJv8!j*2#v2;a}f_O3(<0}s8xk9wR8y1>QtTi-Q=#@ z&?xd^N^W@pS1wdwkwit|e+4irSoM-!Oh#0lf6H5!1kOx9*}z?5bh0?@2dsZFgm2&m z4`1iBP@GuY%)dyC_z1kek@E3#e;<*0dA$R_B9GqgYIUu(oo8nEew;jV25rxoSf>Q{ z6H~^mhVkW6?41U%Az|vcphxz(5yL)vzwHrV!mX}x>IJk!Hm*JzV;VJJ2{STMBYl8< zpc(LBa4#03%hl}I%EC6ne+x&#1i@?DopA@FGLDa2$lQ}odMzo*14o6t zX8$N-JoLw4Z2b05HaqW{bUQJe0?bAUW-ItsO`!=mNlYfJFzs8+;aHk{1ip03XR0ts zy!NFxvFF<1EMyN3;f;!jWVX#5PIONkb6mZEN~lw+a}JhHFpkOJy>&e34T>g=YB> zr4tD=*gqJC_3;rV9oZz$c-FpzwP?Nu2l3bwh)6)%fU|8Jm;h&I3MVovypZxQUpS?R|Tljz8)~zhTWMk4Mx^Yuk#f~odAF% z!dx~{zT529{Xp{{;{cpIljNq}9mnv2tBr-q^{1ljqF&xmt`H&iKVuR%1)6bYzh83mf4T`_)G$sl;kZ5N-c0a2>nDo=MglL-n8n7~xbqxbqtgut%Svh@ z&{VKkGzYZY{5di8705?)H2MA3_M+Pw1n)gvOttlJCBy*P0TV%%ALlB(1J&p=gFb(> z^<=K24*D<8Y)Jd)n`H5v0VysPw+_+Odi*X0noxkBv< zYfAhbIl1&Qp{HPDWT1Ht2a!7fyJb+tQKk^(>;*?XSJg>260-8`6B_3X!>F(EE{9N# zalrH^^kn>^d&Dz#0qPW`9&04Iy(Q+W@8zNvRP4V-)p%i8XU{^4Kk*9`c=PiE=9GZ# zPfNBrr6Ri#sUys(FgvO%0X1&V%D$dAP;bMWRf4$A&0}e74V<3Plsw5AXJ_;lmeloi zu$T@%bQI*xQ0;YkQ-YqGN&R(n^o+@%T8agmNIpW>->hfzCJAhCH2Y@wRy~j$#14=| z;xJ=f*T_2e?Si-J(XGq7>x3cY{umExrg_?>^tl+Y3l_ACQJqVLD9iaA`;{j3ZTyAj z%DU=J##7^YR8+^{c=rU}h@Mu~hDp~0s%?Vd+HC=*B!p7oP$XF;aziRK$m%kxaf!&d z&O8_ZXV7S2AN5kYa4IN~@Nv^4FO;O8kOqY#{u33sUO~$EN326df*_ z#FIk@B}D&jWnbn`Je|M`I(~FfM#yl+X9PR@eEf$x4auCoZSZ^xeE>O$K!u;1Plu7i zKv#ZG5G+uB19(h;fcE`(7@#y9ygbIovl|EXHn5a7&p6ima?NZK6xz5jr}4H~rBdAL zs8KAn+=N+B%2zW4=fv8ph^YgC3&Hy~ zjmS$?xg-;z zdoJPqHjfToU9NIrkMGlGvvs~y@~UwT02oIT8W1oX?Cj|xOK>~QL5%IVAsN{6a?X|f zJ_H5CrD2h&<&xKgUv1dFZe(I~P3;&O3Bc$PgHBwQ_KT0)1C4|}efKh$~b%h+PIBRVpRvivZ0hmn3A`}r? z8+m?DkK!^4Z;TG|9l0AypaF!viQNZUmwuRg;5UXsfW6j(4nzGpkTx04U zg>iB(<%#KZ6BDdaYD9fd$N`3IY&xhq9jLIqD-PT8C-ARjv7i|g<{5y)Q&)0g;J;ho zuq0l+sC6vD->kxYZbad}$pNHn^***a)D@*y#@{r<=lXvDRQgM|I?ty2rAw+_zX}rb zl{sX}>NHxup~?3Yo48z&9a!h&g-#lhrhgdntAt+Nb}S6KG5QZNnG}~{8DuAQjm(SB zGgGHB2KLjGvq{Y{aApVz_kP2)y#2~0;9$E^6~}}2`J;#u_HFb2Vr1=MaZEt;+_Vc) zZq@uX9oUB_QmO>ft)9pwgQNAj(YvxeogGU)=90ufsd2!|vYO=j(v#rCu!nG$mILZ> zfgb}aI&1!TP!za?x>k=QR9q>SzJz5e9#d!zX<=0tQK#Mgor;>53k<6mZi5`p zYMhk)gKw(0uB3C4XKLM*dGM_p1sJ^=or7*?`sT_n+g@+x(*gh#U4}$eix^$>OYO+j zEJQom(yna%InuyoF8!6Zk{Ksd}gecC6lTGqDTTpHEV z?`XEnKKLe`vvZ)F-8K%(iF;uXwB)@aUCtltI8b=j|Bs zFB2{Q*OC!>BC{;iwa;kvxcbZ&)k*Ch&{$^^JP8Vi&J7#3rV#btuSqz1Lpm}$qR~T1 zHv_Z{MI=0WFEU~@`p=`%h�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 literal 0 HcmV?d00001 diff --git a/pythondeps.toml b/pythondeps.toml index bef88d49a6..061f0cff0c 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -19,12 +19,12 @@ [meson] # The install key should match the version in python/wheels/ -meson = { accepted = ">=1.5.0", installed = "1.11.1", canary = "meson" } +meson = { accepted = ">=1.5.0", installed = "1.12.0", canary = "meson" } pycotap = { accepted = ">=1.1.0", installed = "1.3.1" } [meson-rust] # The install key should match the version in python/wheels/ -meson = { accepted = ">=1.11.0", installed = "1.11.1", canary = "meson" } +meson = { accepted = ">=1.12.0", installed = "1.12.0", canary = "meson" } [docs] # Please keep the installed versions in sync with docs/requirements.txt From c5974346d7a7300f5350ccf7af8d61996d9bda6a Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Phi Date: Mon, 3 Aug 2026 01:03:44 +0800 Subject: [PATCH 405/627] rust/bits: Align SubAssign behavior with Sub Update SubAssign to perform a bit-clear operation instead of arithmetic subtraction, matching the behavior of Sub. Signed-off-by: Nguyen Dinh Phi Link: https://lore.kernel.org/r/20260802170346.3493821-2-phind.uet@gmail.com Signed-off-by: Paolo Bonzini --- rust/bits/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rust/bits/src/lib.rs b/rust/bits/src/lib.rs index d1141f7c88..60b63f969d 100644 --- a/rust/bits/src/lib.rs +++ b/rust/bits/src/lib.rs @@ -320,7 +320,7 @@ macro_rules! bits { impl ::std::ops::SubAssign<$struct_name> for $struct_name { fn sub_assign(&mut self, rhs: $struct_name) { - self.0 = self.0 - rhs.0 + self.0 &= !rhs.0 } } @@ -443,4 +443,11 @@ mod test { InterruptMask::OE | InterruptMask::PE | InterruptMask::FE ); } + + #[test] + pub fn test_sub_assign() { + let mut op1 = InterruptMask::E; + op1 -= InterruptMask::RI; + assert_eq!(op1, InterruptMask::E - InterruptMask::RI); + } } From e27a401d2e5a78a303f2c393a289638824e8c0a7 Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Phi Date: Mon, 3 Aug 2026 01:03:45 +0800 Subject: [PATCH 406/627] rust/bits: Use checked_ilog2() in Binary::format to avoid panic ilog2() panics when VALID__ is 0 on empty bits. Switch to checked_ilog2() to handle zero safely. Signed-off-by: Nguyen Dinh Phi Link: https://lore.kernel.org/r/20260802170346.3493821-3-phind.uet@gmail.com Signed-off-by: Paolo Bonzini --- rust/bits/src/lib.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/rust/bits/src/lib.rs b/rust/bits/src/lib.rs index 60b63f969d..5769bc761a 100644 --- a/rust/bits/src/lib.rs +++ b/rust/bits/src/lib.rs @@ -215,7 +215,9 @@ macro_rules! bits { impl ::std::fmt::Binary for $struct_name { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { // If no width, use the highest valid bit - let width = f.width().unwrap_or((Self::VALID__.ilog2() + 1) as usize); + let width = f + .width() + .unwrap_or(Self::VALID__.checked_ilog2().map_or(1, |bit| (bit + 1) as usize)); write!(f, "{:0>width$.precision$b}", self.0, width = width, precision = f.precision().unwrap_or(width)) @@ -412,6 +414,12 @@ mod test { } } + bits! { + pub struct EmptyMask(u32) { + NONE = 0, + } + } + #[test] pub fn test_not() { assert_eq!( @@ -450,4 +458,9 @@ mod test { op1 -= InterruptMask::RI; assert_eq!(op1, InterruptMask::E - InterruptMask::RI); } + + #[test] + pub fn test_bit_display_empty() { + assert_eq!(format!("{:b}", EmptyMask::NONE), "0"); + } } From 015306dec468ee29a5710176d11eaac9a105b117 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Jul 2026 11:58:17 +0200 Subject: [PATCH 407/627] rust: update Cargo.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply change corresponding to bff64138882 ("rust: fix incorrect dependency in Cargo.toml", 2026-06-17). Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- rust/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index cbb3ca15f7..c94c2386d9 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -184,7 +184,6 @@ dependencies = [ "glib-sys", "migration-sys", "qom-sys", - "system-sys", "util-sys", ] @@ -431,6 +430,7 @@ version = "0.1.0" dependencies = [ "common", "glib-sys", + "hwcore-sys", "migration-sys", "qom-sys", "util-sys", From 6d28fc60891fd5643f2fbc8bf4c6ff57f21b5070 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 17 Oct 2025 14:06:03 +0200 Subject: [PATCH 408/627] rust: switch to cargo subprojects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let Meson parse Cargo.lock and Cargo.toml and figure out the set of Rust build dependencies. For now, the only change is that subprojects are retrieved with "cargo_ws.subproject('NAME')" instead of "subproject('NAME-API-rs')". However, just calling "import('rust').workspace()" enables extra functionality that operates by parsing Cargo.toml; it will be introduced a step at a time in subsequent commits. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/static_checks.yml | 4 +-- rust/Cargo.lock => Cargo.lock | 0 rust/Cargo.toml => Cargo.toml | 6 ++-- docs/devel/rust.rst | 8 ++--- meson.build | 3 +- rust/meson.build | 37 +++++++-------------- subprojects/anyhow-1-rs.wrap | 2 +- subprojects/arbitrary-int-1-rs.wrap | 2 +- subprojects/attrs-0.2-rs.wrap | 2 +- subprojects/bilge-0.2-rs.wrap | 2 +- subprojects/bilge-impl-0.2-rs.wrap | 2 +- subprojects/either-1-rs.wrap | 2 +- subprojects/foreign-0.3-rs.wrap | 2 +- subprojects/glib-sys-0.21-rs.wrap | 2 +- subprojects/itertools-0.11-rs.wrap | 2 +- subprojects/libc-0.2-rs.wrap | 2 +- subprojects/probe-0.5-rs.wrap | 2 +- subprojects/proc-macro-error-1-rs.wrap | 2 +- subprojects/proc-macro-error-attr-1-rs.wrap | 2 +- subprojects/proc-macro2-1-rs.wrap | 2 +- subprojects/quote-1-rs.wrap | 2 +- subprojects/syn-2-rs.wrap | 2 +- subprojects/unicode-ident-1-rs.wrap | 2 +- 23 files changed, 40 insertions(+), 52 deletions(-) rename rust/Cargo.lock => Cargo.lock (100%) rename rust/Cargo.toml => Cargo.toml (97%) diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml index 61fe2fa39a..568e56e120 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -55,7 +55,7 @@ check-rust-tools-nightly: - source scripts/ci/gitlab-ci-section - section_start test "Running Rust code checks" - cd build - - pyvenv/bin/meson devenv -w ../rust ${CARGO-cargo} fmt --check + - pyvenv/bin/meson devenv -w ../ ${CARGO-cargo} fmt --check - make clippy - make rustdoc - section_end test @@ -69,7 +69,7 @@ check-rust-tools-nightly: when: on_success expire_in: 2 days paths: - - rust/target/doc + - target/doc check-build-units: extends: .base_job_template diff --git a/rust/Cargo.lock b/Cargo.lock similarity index 100% rename from rust/Cargo.lock rename to Cargo.lock diff --git a/rust/Cargo.toml b/Cargo.toml similarity index 97% rename from rust/Cargo.toml rename to Cargo.toml index 0d24eb84e1..0566850ece 100644 --- a/rust/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [workspace] resolver = "2" members = [ - "hw/char/pl011", - "hw/timer/hpet", - "tests", + "rust/hw/char/pl011", + "rust/hw/timer/hpet", + "rust/tests", ] [workspace.package] diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 67ea84539a..af142c4a69 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -26,14 +26,14 @@ are accustomed to the more "normal" Cargo-based development workflow. In particular: * the set of warnings and lints that are used to build QEMU always - comes from the ``rust/Cargo.toml`` workspace file + comes from the ``Cargo.toml`` workspace file * it is also possible to use ``cargo`` for common Rust-specific coding tasks, in particular to invoke ``clippy``, ``rustfmt`` and ``rustdoc``. To this end, QEMU includes a ``build.rs`` build script that picks up generated sources from QEMU's build directory and puts it in Cargo's -output directory (typically ``rust/target/``). A vanilla invocation +output directory (typically ``target/``). A vanilla invocation of Cargo will complain that it cannot find the generated sources, which can be fixed in different ways: @@ -475,8 +475,8 @@ files, it is still highly experimental and is therefore not used. Therefore, external crates must be added as subprojects for Meson to learn how to build them, as well as to the relevant ``Cargo.toml`` files. -The versions specified in ``rust/Cargo.lock`` must be the same as the -subprojects; note that the ``rust/`` directory forms a Cargo `workspace`__, +The versions specified in ``Cargo.lock`` must be the same as the +subprojects; note that the QEMU source tree forms a Cargo `workspace`__, and therefore there is a single lock file for the whole build. __ https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace diff --git a/meson.build b/meson.build index 40e3f4ec44..2a289960ee 100644 --- a/meson.build +++ b/meson.build @@ -130,7 +130,8 @@ endif if have_rust rustc_args = [find_program('scripts/rust/rustc_args.py'), '--rustc-version', rustc.version(), - '--workspace', meson.project_source_root() / 'rust'] + '--workspace', meson.project_source_root()] + rustfmt = find_program('rustfmt', required: false) rustc_lint_args = run_command(rustc_args, '--lints', diff --git a/rust/meson.build b/rust/meson.build index b6711fe77d..1622a50a97 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -4,31 +4,18 @@ else message('Rust enabled but it is only used by system emulators.') endif -subproject('anyhow-1-rs', required: true) -subproject('bilge-0.2-rs', required: true) -subproject('bilge-impl-0.2-rs', required: true) -subproject('foreign-0.3-rs', required: true) -subproject('glib-sys-0.21-rs', required: true) -subproject('libc-0.2-rs', required: true) -subproject('probe-0.5-rs', required: true) - -anyhow_rs = dependency('anyhow-1-rs') -bilge_rs = dependency('bilge-0.2-rs') -bilge_impl_rs = dependency('bilge-impl-0.2-rs') -foreign_rs = dependency('foreign-0.3-rs') -glib_sys_rs = dependency('glib-sys-0.21-rs') -libc_rs = dependency('libc-0.2-rs') -probe_rs = dependency('probe-0.5-rs') - -subproject('proc-macro2-1-rs', required: true) -subproject('quote-1-rs', required: true) -subproject('syn-2-rs', required: true) -subproject('attrs-0.2-rs', required: true) - -quote_rs_native = dependency('quote-1-rs', native: true) -syn_rs_native = dependency('syn-2-rs', native: true) -proc_macro2_rs_native = dependency('proc-macro2-1-rs', native: true) -attrs_rs_native = dependency('attrs-0.2-rs', native: true) +cargo_ws = import('rust').workspace() +anyhow_rs = cargo_ws.subproject('anyhow').dependency() +bilge_rs = cargo_ws.subproject('bilge').dependency() +bilge_impl_rs = cargo_ws.subproject('bilge-impl').dependency() +foreign_rs = cargo_ws.subproject('foreign').dependency() +glib_sys_rs = cargo_ws.subproject('glib-sys').dependency() +libc_rs = cargo_ws.subproject('libc').dependency() +probe_rs = cargo_ws.subproject('probe').dependency() +quote_rs_native = cargo_ws.subproject('quote').dependency() +syn_rs_native = cargo_ws.subproject('syn').dependency() +proc_macro2_rs_native = cargo_ws.subproject('proc-macro2').dependency() +attrs_rs_native = cargo_ws.subproject('attrs').dependency() genrs = [] diff --git a/subprojects/anyhow-1-rs.wrap b/subprojects/anyhow-1-rs.wrap index a69a3645b4..fb4603e74c 100644 --- a/subprojects/anyhow-1-rs.wrap +++ b/subprojects/anyhow-1-rs.wrap @@ -3,5 +3,5 @@ directory = anyhow-1.0.98 source_url = https://crates.io/api/v1/crates/anyhow/1.0.98/download source_filename = anyhow-1.0.98.tar.gz source_hash = e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487 -#method = cargo +method = cargo patch_directory = anyhow-1-rs diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap index a1838b20b0..f8d7c68da6 100644 --- a/subprojects/arbitrary-int-1-rs.wrap +++ b/subprojects/arbitrary-int-1-rs.wrap @@ -3,7 +3,7 @@ directory = arbitrary-int-1.2.7 source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download source_filename = arbitrary-int-1.2.7.tar.gz source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d -#method = cargo +method = cargo patch_directory = arbitrary-int-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/attrs-0.2-rs.wrap b/subprojects/attrs-0.2-rs.wrap index cd43c91d63..4ff4c424e6 100644 --- a/subprojects/attrs-0.2-rs.wrap +++ b/subprojects/attrs-0.2-rs.wrap @@ -3,5 +3,5 @@ directory = attrs-0.2.9 source_url = https://crates.io/api/v1/crates/attrs/0.2.9/download source_filename = attrs-0.2.9.tar.gz source_hash = 2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f -#method = cargo +method = cargo patch_directory = attrs-0.2-rs diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap index 900bb1497b..cb202cfd9f 100644 --- a/subprojects/bilge-0.2-rs.wrap +++ b/subprojects/bilge-0.2-rs.wrap @@ -3,7 +3,7 @@ directory = bilge-0.2.0 source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download source_filename = bilge-0.2.0.tar.gz source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57 -#method = cargo +method = cargo patch_directory = bilge-0.2-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap index 4f84eca1cc..b3dbfafb26 100644 --- a/subprojects/bilge-impl-0.2-rs.wrap +++ b/subprojects/bilge-impl-0.2-rs.wrap @@ -3,7 +3,7 @@ directory = bilge-impl-0.2.0 source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download source_filename = bilge-impl-0.2.0.tar.gz source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8 -#method = cargo +method = cargo patch_directory = bilge-impl-0.2-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap index 352e11cfee..1c74a95645 100644 --- a/subprojects/either-1-rs.wrap +++ b/subprojects/either-1-rs.wrap @@ -3,7 +3,7 @@ directory = either-1.12.0 source_url = https://crates.io/api/v1/crates/either/1.12.0/download source_filename = either-1.12.0.tar.gz source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b -#method = cargo +method = cargo patch_directory = either-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/foreign-0.3-rs.wrap b/subprojects/foreign-0.3-rs.wrap index 0d218ec2c2..a5fec6c09d 100644 --- a/subprojects/foreign-0.3-rs.wrap +++ b/subprojects/foreign-0.3-rs.wrap @@ -3,5 +3,5 @@ directory = foreign-0.3.1 source_url = https://crates.io/api/v1/crates/foreign/0.3.1/download source_filename = foreign-0.3.1.tar.gz source_hash = 17ca1b5be8c9d320daf386f1809c7acc0cb09accbae795c2001953fa50585846 -#method = cargo +method = cargo patch_directory = foreign-0.3-rs diff --git a/subprojects/glib-sys-0.21-rs.wrap b/subprojects/glib-sys-0.21-rs.wrap index 313ced731a..f4e1514af5 100644 --- a/subprojects/glib-sys-0.21-rs.wrap +++ b/subprojects/glib-sys-0.21-rs.wrap @@ -3,5 +3,5 @@ directory = glib-sys-0.21.2 source_url = https://crates.io/api/v1/crates/glib-sys/0.21.2/download source_filename = glib-sys-0.21.2.tar.gz source_hash = d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1 -#method = cargo +method = cargo patch_directory = glib-sys-0.21-rs diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap index ee12d0053b..6fe89d17ca 100644 --- a/subprojects/itertools-0.11-rs.wrap +++ b/subprojects/itertools-0.11-rs.wrap @@ -3,7 +3,7 @@ directory = itertools-0.11.0 source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download source_filename = itertools-0.11.0.tar.gz source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57 -#method = cargo +method = cargo patch_directory = itertools-0.11-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/libc-0.2-rs.wrap b/subprojects/libc-0.2-rs.wrap index bbe08f8788..488330178e 100644 --- a/subprojects/libc-0.2-rs.wrap +++ b/subprojects/libc-0.2-rs.wrap @@ -3,5 +3,5 @@ directory = libc-0.2.162 source_url = https://crates.io/api/v1/crates/libc/0.2.162/download source_filename = libc-0.2.162.tar.gz source_hash = 18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398 -#method = cargo +method = cargo patch_directory = libc-0.2-rs diff --git a/subprojects/probe-0.5-rs.wrap b/subprojects/probe-0.5-rs.wrap index 73229ee1c2..d3c6b18724 100644 --- a/subprojects/probe-0.5-rs.wrap +++ b/subprojects/probe-0.5-rs.wrap @@ -3,5 +3,5 @@ directory = probe-0.5.2 source_url = https://crates.io/api/v1/crates/probe/0.5.2/download source_filename = probe-0.5.2.tar.gz source_hash = 136558b6e1ebaecc92755d0ffaf9421f519531bed30cc2ad23b22cb00965cc5e -#method = cargo +method = cargo patch_directory = probe-0.5-rs diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap index 59f892f782..4f300c3ac4 100644 --- a/subprojects/proc-macro-error-1-rs.wrap +++ b/subprojects/proc-macro-error-1-rs.wrap @@ -3,7 +3,7 @@ directory = proc-macro-error-1.0.4 source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download source_filename = proc-macro-error-1.0.4.tar.gz source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c -#method = cargo +method = cargo patch_directory = proc-macro-error-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap index 5aeb224a10..739e451c37 100644 --- a/subprojects/proc-macro-error-attr-1-rs.wrap +++ b/subprojects/proc-macro-error-attr-1-rs.wrap @@ -3,7 +3,7 @@ directory = proc-macro-error-attr-1.0.4 source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download source_filename = proc-macro-error-attr-1.0.4.tar.gz source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869 -#method = cargo +method = cargo patch_directory = proc-macro-error-attr-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/proc-macro2-1-rs.wrap b/subprojects/proc-macro2-1-rs.wrap index 0f06cd8e11..3600f4eb19 100644 --- a/subprojects/proc-macro2-1-rs.wrap +++ b/subprojects/proc-macro2-1-rs.wrap @@ -3,7 +3,7 @@ directory = proc-macro2-1.0.95 source_url = https://crates.io/api/v1/crates/proc-macro2/1.0.95/download source_filename = proc-macro2-1.0.95.0.tar.gz source_hash = 02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778 -#method = cargo +method = cargo patch_directory = proc-macro2-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/quote-1-rs.wrap b/subprojects/quote-1-rs.wrap index 8b721dfa00..10626be652 100644 --- a/subprojects/quote-1-rs.wrap +++ b/subprojects/quote-1-rs.wrap @@ -3,7 +3,7 @@ directory = quote-1.0.36 source_url = https://crates.io/api/v1/crates/quote/1.0.36/download source_filename = quote-1.0.36.0.tar.gz source_hash = 0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7 -#method = cargo +method = cargo patch_directory = quote-1-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/syn-2-rs.wrap b/subprojects/syn-2-rs.wrap index 1e5e9d9fb6..db6576f581 100644 --- a/subprojects/syn-2-rs.wrap +++ b/subprojects/syn-2-rs.wrap @@ -3,7 +3,7 @@ directory = syn-2.0.104 source_url = https://crates.io/api/v1/crates/syn/2.0.104/download source_filename = syn-2.0.104.0.tar.gz source_hash = 17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40 -#method = cargo +method = cargo patch_directory = syn-2-rs # bump this version number on every change to meson.build or the patches: diff --git a/subprojects/unicode-ident-1-rs.wrap b/subprojects/unicode-ident-1-rs.wrap index 50988f612e..b420ebfe1f 100644 --- a/subprojects/unicode-ident-1-rs.wrap +++ b/subprojects/unicode-ident-1-rs.wrap @@ -3,7 +3,7 @@ directory = unicode-ident-1.0.12 source_url = https://crates.io/api/v1/crates/unicode-ident/1.0.12/download source_filename = unicode-ident-1.0.12.tar.gz source_hash = 3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b -#method = cargo +method = cargo patch_directory = unicode-ident-1-rs # bump this version number on every change to meson.build or the patches: From 530a9eb2c6aeae6c3b48820b47436389705a8cb1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 May 2026 17:35:29 +0200 Subject: [PATCH 409/627] rust: switch to autogenerated meson rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meson can automatically generate most of the build rules for subprojects, based on the contents of their Cargo.toml. Handwritten snippets can be placed in meson/meson.build to replace build.rs. Disable Meson's use of the nightly-only option "--env-set". It is buggy and anyway it should not be there in future version. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 3 +- scripts/get-wraps-from-cargo-registry.py | 6 --- subprojects/anyhow-1-rs.wrap | 3 ++ subprojects/arbitrary-int-1-rs.wrap | 1 - subprojects/attrs-0.2-rs.wrap | 1 - subprojects/bilge-0.2-rs.wrap | 1 - subprojects/bilge-impl-0.2-rs.wrap | 1 - subprojects/either-1-rs.wrap | 1 - subprojects/foreign-0.3-rs.wrap | 1 - subprojects/glib-sys-0.21-rs.wrap | 1 - subprojects/itertools-0.11-rs.wrap | 1 - subprojects/libc-0.2-rs.wrap | 3 ++ .../packagefiles/anyhow-1-rs/meson.build | 33 -------------- .../anyhow-1-rs/meson/meson.build | 9 ++++ .../arbitrary-int-1-rs/meson.build | 21 --------- .../packagefiles/attrs-0.2-rs/meson.build | 33 -------------- .../packagefiles/bilge-0.2-rs/meson.build | 31 ------------- .../bilge-impl-0.2-rs/meson.build | 44 ------------------- .../packagefiles/either-1-rs/meson.build | 26 ----------- .../packagefiles/foreign-0.3-rs/meson.build | 26 ----------- .../packagefiles/glib-sys-0.21-rs/meson.build | 33 -------------- .../itertools-0.11-rs/meson.build | 32 -------------- .../packagefiles/libc-0.2-rs/meson.build | 37 ---------------- .../libc-0.2-rs/meson/meson.build | 16 +++++++ .../packagefiles/probe-0.5-rs/meson.build | 22 ---------- .../proc-macro-error-1-rs/meson.build | 41 ----------------- .../proc-macro-error-1-rs/meson/meson.build | 3 ++ .../proc-macro-error-attr-1-rs/meson.build | 31 ------------- .../packagefiles/proc-macro2-1-rs/meson.build | 35 --------------- .../proc-macro2-1-rs/meson/meson.build | 6 +++ .../packagefiles/quote-1-rs/meson.build | 31 ------------- subprojects/packagefiles/syn-2-rs/meson.build | 43 ------------------ .../unicode-ident-1-rs/meson.build | 22 ---------- subprojects/probe-0.5-rs.wrap | 1 - subprojects/proc-macro-error-1-rs.wrap | 2 +- subprojects/proc-macro-error-attr-1-rs.wrap | 1 - subprojects/proc-macro2-1-rs.wrap | 2 +- subprojects/quote-1-rs.wrap | 1 - subprojects/syn-2-rs.wrap | 1 - subprojects/unicode-ident-1-rs.wrap | 1 - 40 files changed, 44 insertions(+), 563 deletions(-) delete mode 100644 subprojects/packagefiles/anyhow-1-rs/meson.build create mode 100644 subprojects/packagefiles/anyhow-1-rs/meson/meson.build delete mode 100644 subprojects/packagefiles/arbitrary-int-1-rs/meson.build delete mode 100644 subprojects/packagefiles/attrs-0.2-rs/meson.build delete mode 100644 subprojects/packagefiles/bilge-0.2-rs/meson.build delete mode 100644 subprojects/packagefiles/bilge-impl-0.2-rs/meson.build delete mode 100644 subprojects/packagefiles/either-1-rs/meson.build delete mode 100644 subprojects/packagefiles/foreign-0.3-rs/meson.build delete mode 100644 subprojects/packagefiles/glib-sys-0.21-rs/meson.build delete mode 100644 subprojects/packagefiles/itertools-0.11-rs/meson.build delete mode 100644 subprojects/packagefiles/libc-0.2-rs/meson.build create mode 100644 subprojects/packagefiles/libc-0.2-rs/meson/meson.build delete mode 100644 subprojects/packagefiles/probe-0.5-rs/meson.build delete mode 100644 subprojects/packagefiles/proc-macro-error-1-rs/meson.build create mode 100644 subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build delete mode 100644 subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build delete mode 100644 subprojects/packagefiles/proc-macro2-1-rs/meson.build create mode 100644 subprojects/packagefiles/proc-macro2-1-rs/meson/meson.build delete mode 100644 subprojects/packagefiles/quote-1-rs/meson.build delete mode 100644 subprojects/packagefiles/syn-2-rs/meson.build delete mode 100644 subprojects/packagefiles/unicode-ident-1-rs/meson.build diff --git a/meson.build b/meson.build index 2a289960ee..2139dfc7ce 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,8 @@ project('qemu', ['c'], meson_version: '>=1.5.0', # build.rust_std breaks with older meson, but Rust does not # support old meson anyway - (meson.version().version_compare('>= 1.9') ? ['rust_std=2021', 'build.rust_std=2021'] : []), + (meson.version().version_compare('>= 1.9') ? ['rust_std=2021', 'build.rust_std=2021', + 'rust_nightly=disabled'] : []), version: files('VERSION')) diff --git a/scripts/get-wraps-from-cargo-registry.py b/scripts/get-wraps-from-cargo-registry.py index 31eed5c2dd..78b6f1f7ae 100755 --- a/scripts/get-wraps-from-cargo-registry.py +++ b/scripts/get-wraps-from-cargo-registry.py @@ -116,12 +116,6 @@ class UpdateSubprojects: patch_dir = config["wrap-file"]["patch_directory"] patch_dir = os.path.join("packagefiles", patch_dir) _, ver = registry_namever.rsplit("-", 1) - subprocess.run( - ["meson", "rewrite", "kwargs", "set", "project", "/", "version", ver], - cwd=patch_dir, - env=env, - check=True, - ) subprocess.run( ["meson", "subprojects", "download", wrap_name], diff --git a/subprojects/anyhow-1-rs.wrap b/subprojects/anyhow-1-rs.wrap index fb4603e74c..dbb28f4133 100644 --- a/subprojects/anyhow-1-rs.wrap +++ b/subprojects/anyhow-1-rs.wrap @@ -5,3 +5,6 @@ source_filename = anyhow-1.0.98.tar.gz source_hash = e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487 method = cargo patch_directory = anyhow-1-rs + +# bump this version number on every change to meson.build or the patches: +# v1 diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap index f8d7c68da6..5cf4b11e4a 100644 --- a/subprojects/arbitrary-int-1-rs.wrap +++ b/subprojects/arbitrary-int-1-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download source_filename = arbitrary-int-1.2.7.tar.gz source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d method = cargo -patch_directory = arbitrary-int-1-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/attrs-0.2-rs.wrap b/subprojects/attrs-0.2-rs.wrap index 4ff4c424e6..fef89ea936 100644 --- a/subprojects/attrs-0.2-rs.wrap +++ b/subprojects/attrs-0.2-rs.wrap @@ -4,4 +4,3 @@ source_url = https://crates.io/api/v1/crates/attrs/0.2.9/download source_filename = attrs-0.2.9.tar.gz source_hash = 2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f method = cargo -patch_directory = attrs-0.2-rs diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap index cb202cfd9f..cff10f6710 100644 --- a/subprojects/bilge-0.2-rs.wrap +++ b/subprojects/bilge-0.2-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download source_filename = bilge-0.2.0.tar.gz source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57 method = cargo -patch_directory = bilge-0.2-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap index b3dbfafb26..f8963eba73 100644 --- a/subprojects/bilge-impl-0.2-rs.wrap +++ b/subprojects/bilge-impl-0.2-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download source_filename = bilge-impl-0.2.0.tar.gz source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8 method = cargo -patch_directory = bilge-impl-0.2-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap index 1c74a95645..51c97df153 100644 --- a/subprojects/either-1-rs.wrap +++ b/subprojects/either-1-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/either/1.12.0/download source_filename = either-1.12.0.tar.gz source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b method = cargo -patch_directory = either-1-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/foreign-0.3-rs.wrap b/subprojects/foreign-0.3-rs.wrap index a5fec6c09d..95d450397e 100644 --- a/subprojects/foreign-0.3-rs.wrap +++ b/subprojects/foreign-0.3-rs.wrap @@ -4,4 +4,3 @@ source_url = https://crates.io/api/v1/crates/foreign/0.3.1/download source_filename = foreign-0.3.1.tar.gz source_hash = 17ca1b5be8c9d320daf386f1809c7acc0cb09accbae795c2001953fa50585846 method = cargo -patch_directory = foreign-0.3-rs diff --git a/subprojects/glib-sys-0.21-rs.wrap b/subprojects/glib-sys-0.21-rs.wrap index f4e1514af5..ea4d5f66a5 100644 --- a/subprojects/glib-sys-0.21-rs.wrap +++ b/subprojects/glib-sys-0.21-rs.wrap @@ -4,4 +4,3 @@ source_url = https://crates.io/api/v1/crates/glib-sys/0.21.2/download source_filename = glib-sys-0.21.2.tar.gz source_hash = d09d3d0fddf7239521674e57b0465dfbd844632fec54f059f7f56112e3f927e1 method = cargo -patch_directory = glib-sys-0.21-rs diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap index 6fe89d17ca..e123ab389a 100644 --- a/subprojects/itertools-0.11-rs.wrap +++ b/subprojects/itertools-0.11-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download source_filename = itertools-0.11.0.tar.gz source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57 method = cargo -patch_directory = itertools-0.11-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/libc-0.2-rs.wrap b/subprojects/libc-0.2-rs.wrap index 488330178e..6e22557979 100644 --- a/subprojects/libc-0.2-rs.wrap +++ b/subprojects/libc-0.2-rs.wrap @@ -5,3 +5,6 @@ source_filename = libc-0.2.162.tar.gz source_hash = 18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398 method = cargo patch_directory = libc-0.2-rs + +# bump this version number on every change to meson.build or the patches: +# v1 diff --git a/subprojects/packagefiles/anyhow-1-rs/meson.build b/subprojects/packagefiles/anyhow-1-rs/meson.build deleted file mode 100644 index 348bab98b9..0000000000 --- a/subprojects/packagefiles/anyhow-1-rs/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -project('anyhow-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.0.98', - license: 'MIT OR Apache-2.0', - default_options: []) - -rustc = meson.get_compiler('rust') - -rust_args = ['--cap-lints', 'allow'] -rust_args += ['--cfg', 'feature="std"'] -if rustc.version().version_compare('<1.65.0') - error('rustc version ' + rustc.version() + ' is unsupported. Please upgrade to at least 1.65.0') -endif -rust_args += [ '--cfg', 'std_backtrace' ] # >= 1.65.0 -if rustc.version().version_compare('<1.81.0') - rust_args += [ '--cfg', 'anyhow_no_core_error' ] -endif - -_anyhow_rs = static_library( - 'anyhow', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2018', 'build.rust_std=2018'], - rust_abi: 'rust', - rust_args: rust_args, - dependencies: [], -) - -anyhow_dep = declare_dependency( - link_with: _anyhow_rs, -) - -meson.override_dependency('anyhow-1-rs', anyhow_dep) diff --git a/subprojects/packagefiles/anyhow-1-rs/meson/meson.build b/subprojects/packagefiles/anyhow-1-rs/meson/meson.build new file mode 100644 index 0000000000..91c46539c3 --- /dev/null +++ b/subprojects/packagefiles/anyhow-1-rs/meson/meson.build @@ -0,0 +1,9 @@ +rustc = meson.get_compiler('rust') + +if rustc.version().version_compare('<1.65.0') + error('rustc version ' + rustc.version() + ' is unsupported. Please upgrade to at least 1.65.0') +endif +extra_args += [ '--cfg', 'std_backtrace' ] # >= 1.65.0 +if rustc.version().version_compare('<1.81.0') + extra_args += [ '--cfg', 'anyhow_no_core_error' ] +endif diff --git a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build deleted file mode 100644 index 00733d1faa..0000000000 --- a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -project('arbitrary-int-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.2.7', - license: 'MIT', - default_options: []) - -_arbitrary_int_rs = static_library( - 'arbitrary_int', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_args: ['--cap-lints', 'allow'], - rust_abi: 'rust', - dependencies: [], -) - -arbitrary_int_dep = declare_dependency( - link_with: _arbitrary_int_rs, -) - -meson.override_dependency('arbitrary-int-1-rs', arbitrary_int_dep) diff --git a/subprojects/packagefiles/attrs-0.2-rs/meson.build b/subprojects/packagefiles/attrs-0.2-rs/meson.build deleted file mode 100644 index ee575476cb..0000000000 --- a/subprojects/packagefiles/attrs-0.2-rs/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -project('attrs-0.2-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.2.9', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('proc-macro2-1-rs', required: true) -subproject('syn-2-rs', required: true) - -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) -syn_dep = dependency('syn-2-rs', native: true) - -_attrs_rs = static_library( - 'attrs', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - ], - dependencies: [ - proc_macro2_dep, - syn_dep, - ], - native: true, -) - -attrs_dep = declare_dependency( - link_with: _attrs_rs, -) - -meson.override_dependency('attrs-0.2-rs', attrs_dep, native: true) diff --git a/subprojects/packagefiles/bilge-0.2-rs/meson.build b/subprojects/packagefiles/bilge-0.2-rs/meson.build deleted file mode 100644 index ce13d0fe80..0000000000 --- a/subprojects/packagefiles/bilge-0.2-rs/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -project( - 'bilge-0.2-rs', - 'rust', - meson_version: '>=1.5.0', - version : '0.2.0', - license : 'MIT or Apache-2.0', -) - -subproject('arbitrary-int-1-rs', required: true) -subproject('bilge-impl-0.2-rs', required: true) - -arbitrary_int_dep = dependency('arbitrary-int-1-rs') -bilge_impl_dep = dependency('bilge-impl-0.2-rs') - -lib = static_library( - 'bilge', - 'src/lib.rs', - override_options : ['rust_std=2021', 'build.rust_std=2021'], - rust_abi : 'rust', - rust_args: ['--cap-lints', 'allow'], - dependencies: [ - arbitrary_int_dep, - bilge_impl_dep, - ], -) - -bilge_dep = declare_dependency( - link_with : [lib], -) - -meson.override_dependency('bilge-0.2-rs', bilge_dep) diff --git a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build deleted file mode 100644 index 04617b875c..0000000000 --- a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build +++ /dev/null @@ -1,44 +0,0 @@ -project('bilge-impl-0.2-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.2.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('itertools-0.11-rs', required: true) -subproject('proc-macro-error-attr-1-rs', required: true) -subproject('proc-macro-error-1-rs', required: true) -subproject('quote-1-rs', required: true) -subproject('syn-2-rs', required: true) -subproject('proc-macro2-1-rs', required: true) - -itertools_dep = dependency('itertools-0.11-rs', native: true) -proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true) -proc_macro_error_dep = dependency('proc-macro-error-1-rs', native: true) -quote_dep = dependency('quote-1-rs', native: true) -syn_dep = dependency('syn-2-rs', native: true) -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) - -rust = import('rust') - -_bilge_impl_rs = rust.proc_macro( - 'bilge_impl', - files('src/lib.rs'), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_args: [ - '--cap-lints', 'allow', - ], - dependencies: [ - itertools_dep, - proc_macro_error_attr_dep, - proc_macro_error_dep, - quote_dep, - syn_dep, - proc_macro2_dep, - ], -) - -bilge_impl_dep = declare_dependency( - link_with: _bilge_impl_rs, -) - -meson.override_dependency('bilge-impl-0.2-rs', bilge_impl_dep) diff --git a/subprojects/packagefiles/either-1-rs/meson.build b/subprojects/packagefiles/either-1-rs/meson.build deleted file mode 100644 index 04c96cc5fb..0000000000 --- a/subprojects/packagefiles/either-1-rs/meson.build +++ /dev/null @@ -1,26 +0,0 @@ -project('either-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.12.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -_either_rs = static_library( - 'either', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2018', 'build.rust_std=2018'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="use_std"', - '--cfg', 'feature="use_alloc"', - ], - dependencies: [], - native: true, -) - -either_dep = declare_dependency( - link_with: _either_rs, -) - -meson.override_dependency('either-1-rs', either_dep, native: true) diff --git a/subprojects/packagefiles/foreign-0.3-rs/meson.build b/subprojects/packagefiles/foreign-0.3-rs/meson.build deleted file mode 100644 index 0901c02c52..0000000000 --- a/subprojects/packagefiles/foreign-0.3-rs/meson.build +++ /dev/null @@ -1,26 +0,0 @@ -project('foreign-0.3-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.2.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('libc-0.2-rs', required: true) -libc_rs = dependency('libc-0.2-rs') - -_foreign_rs = static_library( - 'foreign', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - ], - dependencies: [libc_rs], -) - -foreign_dep = declare_dependency( - link_with: _foreign_rs, -) - -meson.override_dependency('foreign-0.3-rs', foreign_dep) diff --git a/subprojects/packagefiles/glib-sys-0.21-rs/meson.build b/subprojects/packagefiles/glib-sys-0.21-rs/meson.build deleted file mode 100644 index 8c5483311e..0000000000 --- a/subprojects/packagefiles/glib-sys-0.21-rs/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -project('glib-sys-0.21-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.21.2', - license: 'MIT', - default_options: []) - -subproject('libc-0.2-rs', required: true) -libc_rs = dependency('libc-0.2-rs') - -_glib_sys_rs = static_library( - 'glib_sys', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="v2_66"', - '--cfg', 'feature="v2_64"', - '--cfg', 'feature="v2_62"', - '--cfg', 'feature="v2_60"', - '--cfg', 'feature="v2_58"', - ], - # should also link with glib; don't bother doing it here since all - # QEMU targets have it - dependencies: [libc_rs], -) - -glib_sys_dep = declare_dependency( - link_with: _glib_sys_rs, -) - -meson.override_dependency('glib-sys-0.21-rs', glib_sys_dep) diff --git a/subprojects/packagefiles/itertools-0.11-rs/meson.build b/subprojects/packagefiles/itertools-0.11-rs/meson.build deleted file mode 100644 index 2a3fbe9ee5..0000000000 --- a/subprojects/packagefiles/itertools-0.11-rs/meson.build +++ /dev/null @@ -1,32 +0,0 @@ -project('itertools-0.11-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.11.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('either-1-rs', required: true) - -either_dep = dependency('either-1-rs', native: true) - -_itertools_rs = static_library( - 'itertools', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2018', 'build.rust_std=2018'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="use_std"', - '--cfg', 'feature="use_alloc"', - ], - dependencies: [ - either_dep, - ], - native: true, -) - -itertools_dep = declare_dependency( - link_with: _itertools_rs, -) - -meson.override_dependency('itertools-0.11-rs', itertools_dep, native: true) diff --git a/subprojects/packagefiles/libc-0.2-rs/meson.build b/subprojects/packagefiles/libc-0.2-rs/meson.build deleted file mode 100644 index ac4f80dba9..0000000000 --- a/subprojects/packagefiles/libc-0.2-rs/meson.build +++ /dev/null @@ -1,37 +0,0 @@ -project('libc-0.2-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.2.162', - license: 'MIT OR Apache-2.0', - default_options: []) - -_libc_rs = static_library( - 'libc', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2015', 'build.rust_std=2015'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'freebsd11', - '--cfg', 'libc_priv_mod_use', - '--cfg', 'libc_union', - '--cfg', 'libc_const_size_of', - '--cfg', 'libc_align', - '--cfg', 'libc_int128', - '--cfg', 'libc_core_cvoid', - '--cfg', 'libc_packedN', - '--cfg', 'libc_cfg_target_vendor', - '--cfg', 'libc_non_exhaustive', - '--cfg', 'libc_long_array', - '--cfg', 'libc_ptr_addr_of', - '--cfg', 'libc_underscore_const_names', - '--cfg', 'libc_const_extern_fn', - ], - dependencies: [], -) - -libc_dep = declare_dependency( - link_with: _libc_rs, -) - -meson.override_dependency('libc-0.2-rs', libc_dep) diff --git a/subprojects/packagefiles/libc-0.2-rs/meson/meson.build b/subprojects/packagefiles/libc-0.2-rs/meson/meson.build new file mode 100644 index 0000000000..db9480ada1 --- /dev/null +++ b/subprojects/packagefiles/libc-0.2-rs/meson/meson.build @@ -0,0 +1,16 @@ +extra_args += [ + '--cfg', 'freebsd11', + '--cfg', 'libc_priv_mod_use', + '--cfg', 'libc_union', + '--cfg', 'libc_const_size_of', + '--cfg', 'libc_align', + '--cfg', 'libc_int128', + '--cfg', 'libc_core_cvoid', + '--cfg', 'libc_packedN', + '--cfg', 'libc_cfg_target_vendor', + '--cfg', 'libc_non_exhaustive', + '--cfg', 'libc_long_array', + '--cfg', 'libc_ptr_addr_of', + '--cfg', 'libc_underscore_const_names', + '--cfg', 'libc_const_extern_fn', +] diff --git a/subprojects/packagefiles/probe-0.5-rs/meson.build b/subprojects/packagefiles/probe-0.5-rs/meson.build deleted file mode 100644 index e6ea69533b..0000000000 --- a/subprojects/packagefiles/probe-0.5-rs/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -project('probe-0.5-rs', 'rust', - meson_version: '>=1.5.0', - version: '0.5.2', - license: 'Apache-2.0 OR MIT', - default_options: []) - -_probe_rs = static_library( - 'probe', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - ], -) - -probe_deps = declare_dependency( - link_with: _probe_rs, -) - -meson.override_dependency('probe-0.5-rs', probe_deps) diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build deleted file mode 100644 index 8ba558e133..0000000000 --- a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build +++ /dev/null @@ -1,41 +0,0 @@ -project('proc-macro-error-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.0.4', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('proc-macro-error-attr-1-rs', required: true) -subproject('quote-1-rs', required: true) -subproject('syn-2-rs', required: true) -subproject('proc-macro2-1-rs', required: true) - -proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true) -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) -quote_dep = dependency('quote-1-rs', native: true) -syn_dep = dependency('syn-2-rs', native: true) - -_proc_macro_error_rs = static_library( - 'proc_macro_error', - files('src/lib.rs'), - override_options: ['rust_std=2018', 'build.rust_std=2018'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'use_fallback', - '--cfg', 'feature="syn-error"', - '-A', 'non_fmt_panics' - ], - dependencies: [ - proc_macro_error_attr_dep, - proc_macro2_dep, - quote_dep, - syn_dep, - ], - native: true, -) - -proc_macro_error_dep = declare_dependency( - link_with: _proc_macro_error_rs, -) - -meson.override_dependency('proc-macro-error-1-rs', proc_macro_error_dep, native: true) diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build new file mode 100644 index 0000000000..52a244d2b1 --- /dev/null +++ b/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build @@ -0,0 +1,3 @@ +extra_args = [ + '--cfg', 'use_fallback', +] diff --git a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build deleted file mode 100644 index a85d7c0714..0000000000 --- a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -project('proc-macro-error-attr-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.12.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('proc-macro2-1-rs', required: true) -subproject('quote-1-rs', required: true) - -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) -quote_dep = dependency('quote-1-rs', native: true) - -rust = import('rust') -_proc_macro_error_attr_rs = rust.proc_macro( - 'proc_macro_error_attr', - files('src/lib.rs'), - override_options: ['rust_std=2018', 'build.rust_std=2018'], - rust_args: [ - '--cap-lints', 'allow', - ], - dependencies: [ - proc_macro2_dep, - quote_dep, - ], -) - -proc_macro_error_attr_dep = declare_dependency( - link_with: _proc_macro_error_attr_rs, -) - -meson.override_dependency('proc-macro-error-attr-1-rs', proc_macro_error_attr_dep, native: true) diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson.build deleted file mode 100644 index ba7de07029..0000000000 --- a/subprojects/packagefiles/proc-macro2-1-rs/meson.build +++ /dev/null @@ -1,35 +0,0 @@ -project('proc-macro2-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.0.95', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('unicode-ident-1-rs', required: true) - -unicode_ident_dep = dependency('unicode-ident-1-rs', native: true) - -_proc_macro2_rs = static_library( - 'proc_macro2', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="proc-macro"', - '--cfg', 'no_literal_byte_character', - '--cfg', 'no_literal_c_string', - '--cfg', 'no_source_text', - '--cfg', 'wrap_proc_macro', - ], - dependencies: [ - unicode_ident_dep, - ], - native: true, -) - -proc_macro2_dep = declare_dependency( - link_with: _proc_macro2_rs, -) - -meson.override_dependency('proc-macro2-1-rs', proc_macro2_dep, native: true) diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson/meson.build new file mode 100644 index 0000000000..09712bb0b0 --- /dev/null +++ b/subprojects/packagefiles/proc-macro2-1-rs/meson/meson.build @@ -0,0 +1,6 @@ +extra_args = [ + '--cfg', 'no_literal_byte_character', + '--cfg', 'no_literal_c_string', + '--cfg', 'no_source_text', + '--cfg', 'wrap_proc_macro', +] diff --git a/subprojects/packagefiles/quote-1-rs/meson.build b/subprojects/packagefiles/quote-1-rs/meson.build deleted file mode 100644 index bf41fad99b..0000000000 --- a/subprojects/packagefiles/quote-1-rs/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -project('quote-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.12.0', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('proc-macro2-1-rs', required: true) - -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) - -_quote_rs = static_library( - 'quote', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="proc-macro"', - ], - dependencies: [ - proc_macro2_dep, - ], - native: true, -) - -quote_dep = declare_dependency( - link_with: _quote_rs, -) - -meson.override_dependency('quote-1-rs', quote_dep, native: true) diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build deleted file mode 100644 index 3e6dc318a9..0000000000 --- a/subprojects/packagefiles/syn-2-rs/meson.build +++ /dev/null @@ -1,43 +0,0 @@ -project('syn-2-rs', 'rust', - meson_version: '>=1.5.0', - version: '2.0.104', - license: 'MIT OR Apache-2.0', - default_options: []) - -subproject('proc-macro2-1-rs', required: true) -subproject('quote-1-rs', required: true) -subproject('unicode-ident-1-rs', required: true) - -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) -quote_dep = dependency('quote-1-rs', native: true) -unicode_ident_dep = dependency('unicode-ident-1-rs', native: true) - -_syn_rs = static_library( - 'syn', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: [ - '--cap-lints', 'allow', - '--cfg', 'feature="full"', - '--cfg', 'feature="derive"', - '--cfg', 'feature="parsing"', - '--cfg', 'feature="printing"', - '--cfg', 'feature="clone-impls"', - '--cfg', 'feature="proc-macro"', - '--cfg', 'feature="extra-traits"', - ], - dependencies: [ - quote_dep, - proc_macro2_dep, - unicode_ident_dep, - ], - native: true, -) - -syn_dep = declare_dependency( - link_with: _syn_rs, -) - -meson.override_dependency('syn-2-rs', syn_dep, native: true) diff --git a/subprojects/packagefiles/unicode-ident-1-rs/meson.build b/subprojects/packagefiles/unicode-ident-1-rs/meson.build deleted file mode 100644 index 11a5dab97d..0000000000 --- a/subprojects/packagefiles/unicode-ident-1-rs/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -project('unicode-ident-1-rs', 'rust', - meson_version: '>=1.5.0', - version: '1.0.12', - license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016', - default_options: []) - -_unicode_ident_rs = static_library( - 'unicode_ident', - files('src/lib.rs'), - gnu_symbol_visibility: 'hidden', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - rust_args: ['--cap-lints', 'allow'], - dependencies: [], - native: true, -) - -unicode_ident_dep = declare_dependency( - link_with: _unicode_ident_rs, -) - -meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true) diff --git a/subprojects/probe-0.5-rs.wrap b/subprojects/probe-0.5-rs.wrap index d3c6b18724..72e771ec78 100644 --- a/subprojects/probe-0.5-rs.wrap +++ b/subprojects/probe-0.5-rs.wrap @@ -4,4 +4,3 @@ source_url = https://crates.io/api/v1/crates/probe/0.5.2/download source_filename = probe-0.5.2.tar.gz source_hash = 136558b6e1ebaecc92755d0ffaf9421f519531bed30cc2ad23b22cb00965cc5e method = cargo -patch_directory = probe-0.5-rs diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap index 4f300c3ac4..e57921bfad 100644 --- a/subprojects/proc-macro-error-1-rs.wrap +++ b/subprojects/proc-macro-error-1-rs.wrap @@ -7,4 +7,4 @@ method = cargo patch_directory = proc-macro-error-1-rs # bump this version number on every change to meson.build or the patches: -# v2 +# v3 diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap index 739e451c37..456d2c2b6d 100644 --- a/subprojects/proc-macro-error-attr-1-rs.wrap +++ b/subprojects/proc-macro-error-attr-1-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/downloa source_filename = proc-macro-error-attr-1.0.4.tar.gz source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869 method = cargo -patch_directory = proc-macro-error-attr-1-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/proc-macro2-1-rs.wrap b/subprojects/proc-macro2-1-rs.wrap index 3600f4eb19..676d1a3a8c 100644 --- a/subprojects/proc-macro2-1-rs.wrap +++ b/subprojects/proc-macro2-1-rs.wrap @@ -7,4 +7,4 @@ method = cargo patch_directory = proc-macro2-1-rs # bump this version number on every change to meson.build or the patches: -# v2 +# v3 diff --git a/subprojects/quote-1-rs.wrap b/subprojects/quote-1-rs.wrap index 10626be652..5f38f56499 100644 --- a/subprojects/quote-1-rs.wrap +++ b/subprojects/quote-1-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/quote/1.0.36/download source_filename = quote-1.0.36.0.tar.gz source_hash = 0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7 method = cargo -patch_directory = quote-1-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/syn-2-rs.wrap b/subprojects/syn-2-rs.wrap index db6576f581..4b97bed258 100644 --- a/subprojects/syn-2-rs.wrap +++ b/subprojects/syn-2-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/syn/2.0.104/download source_filename = syn-2.0.104.0.tar.gz source_hash = 17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40 method = cargo -patch_directory = syn-2-rs # bump this version number on every change to meson.build or the patches: # v2 diff --git a/subprojects/unicode-ident-1-rs.wrap b/subprojects/unicode-ident-1-rs.wrap index b420ebfe1f..90aae02ba0 100644 --- a/subprojects/unicode-ident-1-rs.wrap +++ b/subprojects/unicode-ident-1-rs.wrap @@ -4,7 +4,6 @@ source_url = https://crates.io/api/v1/crates/unicode-ident/1.0.12/download source_filename = unicode-ident-1.0.12.tar.gz source_hash = 3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b method = cargo -patch_directory = unicode-ident-1-rs # bump this version number on every change to meson.build or the patches: # v2 From aaac1f8229efaf1bd13ccdff1a88af142aebafe9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 29 Apr 2026 10:36:52 +0200 Subject: [PATCH 410/627] meson: use compiler_target() to get rustc target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new method in Meson 1.11.x removes the need to pass the triple via config-host.mak. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 3 --- meson.build | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/configure b/configure index 7f637c018c..56158cd95f 100755 --- a/configure +++ b/configure @@ -1740,9 +1740,6 @@ if test "$container_command" != ""; then echo "CONTAINER_COMMAND=$container_command" >> $config_host_mak fi echo "SUBDIRS=$subdirs" >> $config_host_mak -if test "$rust" != disabled; then - echo "RUST_TARGET_TRIPLE=$rust_target_triple" >> $config_host_mak -fi echo "PYTHON=$python" >> $config_host_mak echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak echo "GENISOIMAGE=$genisoimage" >> $config_host_mak diff --git a/meson.build b/meson.build index 2139dfc7ce..2593eb9762 100644 --- a/meson.build +++ b/meson.build @@ -4747,7 +4747,7 @@ else endif summary_info += {'Rust support': have_rust} if have_rust - summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']} + summary_info += {'Rust target': rust.compiler_target(native: false)} summary_info += {'rustc': ' '.join(rustc.cmd_array())} summary_info += {'rustc version': rustc.version()} summary_info += {'rustdoc': rustdoc} From 4c5c26548b746e5866b2c00c353f43e6e322ad96 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 May 2026 17:47:55 +0200 Subject: [PATCH 411/627] rust: use meson automatic parsing of Cargo.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finally, automatic parsing of Cargo.toml is also possible for QEMU's own crates, not just for subprojects. This removes the need to list the dependencies and language editions in both Cargo.toml and meson.build files. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 7 +------ rust/bindings/chardev-sys/meson.build | 11 ++++------- rust/bindings/hwcore-sys/meson.build | 11 ++++------- rust/bindings/migration-sys/meson.build | 11 ++++------- rust/bindings/qom-sys/meson.build | 11 ++++------- rust/bindings/system-sys/meson.build | 11 ++++------- rust/bindings/util-sys/meson.build | 11 ++++------- rust/bits/meson.build | 7 ++----- rust/bql/meson.build | 13 +++---------- rust/chardev/meson.build | 8 ++------ rust/common/meson.build | 10 +++------- rust/hw/char/pl011/meson.build | 22 +--------------------- rust/hw/core/meson.build | 10 ++-------- rust/hw/timer/hpet/meson.build | 17 +---------------- rust/meson.build | 11 ----------- rust/migration/meson.build | 8 ++------ rust/qemu-macros/meson.build | 12 ++---------- rust/qom/meson.build | 8 ++------ rust/system/meson.build | 8 ++------ rust/trace/meson.build | 9 +++------ rust/util/meson.build | 7 ++----- 21 files changed, 52 insertions(+), 171 deletions(-) diff --git a/meson.build b/meson.build index 2593eb9762..3c6a82ab44 100644 --- a/meson.build +++ b/meson.build @@ -135,12 +135,7 @@ if have_rust rustfmt = find_program('rustfmt', required: false) - rustc_lint_args = run_command(rustc_args, '--lints', - capture: true, check: true).stdout().strip().splitlines() - if get_option('strict_rust_lints') - rustc_lint_args += ['-Dwarnings', '-Funknown_lints'] - endif - + rustc_lint_args = get_option('strict_rust_lints') ? ['-Dwarnings', '-Funknown_lints'] : [] add_project_arguments(rustc_lint_args + ['--cfg', 'MESON'], native: false, language: 'rust') add_project_arguments(rustc_lint_args + ['--cfg', 'MESON'], diff --git a/rust/bindings/chardev-sys/meson.build b/rust/bindings/chardev-sys/meson.build index 458075b806..7af5d74dd5 100644 --- a/rust/bindings/chardev-sys/meson.build +++ b/rust/bindings/chardev-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_chardev_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['chardev-sys'].split(), kwargs: bindgen_kwargs) -_chardev_sys_rs = static_library( - 'chardev_sys', - structured_sources(['lib.rs', _bindgen_chardev_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [glib_sys_rs, common_rs, qom_sys_rs, util_sys_rs], -) + +_chardev_sys_rs = cargo_ws.package('chardev-sys').library( + structured_sources(['lib.rs', _bindgen_chardev_rs])) +cargo_ws.package('chardev-sys').override_dependency(declare_dependency(link_with: _chardev_sys_rs)) chardev_sys_rs = declare_dependency(link_with: [_chardev_sys_rs]) diff --git a/rust/bindings/hwcore-sys/meson.build b/rust/bindings/hwcore-sys/meson.build index 3d51947b4a..6b8d218f69 100644 --- a/rust/bindings/hwcore-sys/meson.build +++ b/rust/bindings/hwcore-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_hwcore_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['hwcore-sys'].split(), kwargs: bindgen_kwargs) -_hwcore_sys_rs = static_library( - 'hwcore_sys', - structured_sources(['lib.rs', _bindgen_hwcore_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [common_rs, glib_sys_rs, qom_sys_rs, util_sys_rs, migration_sys_rs, chardev_sys_rs], -) + +_hwcore_sys_rs = cargo_ws.package('hwcore-sys').library( + structured_sources(['lib.rs', _bindgen_hwcore_rs])) +cargo_ws.package('hwcore-sys').override_dependency(declare_dependency(link_with: _hwcore_sys_rs)) hwcore_sys_rs = declare_dependency(link_with: [_hwcore_sys_rs]) diff --git a/rust/bindings/migration-sys/meson.build b/rust/bindings/migration-sys/meson.build index 9243acba30..91f2967c9b 100644 --- a/rust/bindings/migration-sys/meson.build +++ b/rust/bindings/migration-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_migration_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['migration-sys'].split(), kwargs: bindgen_kwargs) -_migration_sys_rs = static_library( - 'migration_sys', - structured_sources(['lib.rs', _bindgen_migration_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [glib_sys_rs, common_rs, util_sys_rs], -) + +_migration_sys_rs = cargo_ws.package('migration-sys').library( + structured_sources(['lib.rs', _bindgen_migration_rs])) +cargo_ws.package('migration-sys').override_dependency(declare_dependency(link_with: _migration_sys_rs)) migration_sys_rs = declare_dependency(link_with: [_migration_sys_rs]) diff --git a/rust/bindings/qom-sys/meson.build b/rust/bindings/qom-sys/meson.build index 8f8ae7d1bc..540e55eea8 100644 --- a/rust/bindings/qom-sys/meson.build +++ b/rust/bindings/qom-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_qom_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['qom-sys'].split(), kwargs: bindgen_kwargs) -_qom_sys_rs = static_library( - 'qom_sys', - structured_sources(['lib.rs', _bindgen_qom_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [glib_sys_rs, util_sys_rs], -) + +_qom_sys_rs = cargo_ws.package('qom-sys').library( + structured_sources(['lib.rs', _bindgen_qom_rs])) +cargo_ws.package('qom-sys').override_dependency(declare_dependency(link_with: _qom_sys_rs)) qom_sys_rs = declare_dependency(link_with: [_qom_sys_rs]) diff --git a/rust/bindings/system-sys/meson.build b/rust/bindings/system-sys/meson.build index aa5e880114..b1f4770499 100644 --- a/rust/bindings/system-sys/meson.build +++ b/rust/bindings/system-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_system_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['system-sys'].split(), kwargs: bindgen_kwargs) -_system_sys_rs = static_library( - 'system_sys', - structured_sources(['lib.rs', _bindgen_system_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [common_rs, glib_sys_rs, hwcore_sys_rs, migration_sys_rs, qom_sys_rs, util_sys_rs], -) + +_system_sys_rs = cargo_ws.package('system-sys').library( + structured_sources(['lib.rs', _bindgen_system_rs])) +cargo_ws.package('system-sys').override_dependency(declare_dependency(link_with: _system_sys_rs)) system_sys_rs = declare_dependency(link_with: [_system_sys_rs]) diff --git a/rust/bindings/util-sys/meson.build b/rust/bindings/util-sys/meson.build index c37f50a94b..5a9db6152e 100644 --- a/rust/bindings/util-sys/meson.build +++ b/rust/bindings/util-sys/meson.build @@ -1,12 +1,9 @@ _bindgen_util_rs = rust.bindgen( args: bindgen_args_common + bindgen_args_data['util-sys'].split(), kwargs: bindgen_kwargs) -_util_sys_rs = static_library( - 'util_sys', - structured_sources(['lib.rs', _bindgen_util_rs]), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - dependencies: [glib_sys_rs], -) + +_util_sys_rs = cargo_ws.package('util-sys').library( + structured_sources(['lib.rs', _bindgen_util_rs])) +cargo_ws.package('util-sys').override_dependency(declare_dependency(link_with: _util_sys_rs)) util_sys_rs = declare_dependency(link_with: [_util_sys_rs]) diff --git a/rust/bits/meson.build b/rust/bits/meson.build index c0094ffcf3..c64a17ba15 100644 --- a/rust/bits/meson.build +++ b/rust/bits/meson.build @@ -1,8 +1,5 @@ -_bits_rs = static_library( - 'bits', - 'src/lib.rs', - dependencies: [qemu_macros], -) +_bits_rs = cargo_ws.package('bits').library() +cargo_ws.package('bits').override_dependency(declare_dependency(link_with: _bits_rs)) bits_rs = declare_dependency(link_with: _bits_rs) diff --git a/rust/bql/meson.build b/rust/bql/meson.build index de295d2983..8bdc9b53a2 100644 --- a/rust/bql/meson.build +++ b/rust/bql/meson.build @@ -1,17 +1,10 @@ -_bql_cfg = run_command(rustc_args, - '--config-headers', config_host_h, '--features', files('Cargo.toml'), - capture: true, check: true).stdout().strip().splitlines() - +_bql_cfg = [] if get_option('debug_mutex') _bql_cfg += ['--cfg', 'feature="debug_cell"'] endif -_bql_rs = static_library( - 'bql', - 'src/lib.rs', - rust_args: _bql_cfg, - dependencies: [glib_sys_rs, util_sys_rs], -) +_bql_rs = cargo_ws.package('bql').library(rust_args: _bql_cfg) +cargo_ws.package('bql').override_dependency(declare_dependency(link_with: _bql_rs)) bql_rs = declare_dependency(link_with: [_bql_rs], dependencies: [qemuutil]) diff --git a/rust/chardev/meson.build b/rust/chardev/meson.build index 7b267fd23a..f3462e9209 100644 --- a/rust/chardev/meson.build +++ b/rust/chardev/meson.build @@ -1,8 +1,4 @@ -_chardev_rs = static_library( - 'chardev', - 'src/lib.rs', - link_with: [_bql_rs, _migration_rs, _qom_rs, _util_rs], - dependencies: [glib_sys_rs, common_rs, qemu_macros, chardev_sys_rs], -) +_chardev_rs = cargo_ws.package('chardev').library() +cargo_ws.package('chardev').override_dependency(declare_dependency(link_with: _chardev_rs)) chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev, qemuutil]) diff --git a/rust/common/meson.build b/rust/common/meson.build index 57091b18fc..43afe417dc 100644 --- a/rust/common/meson.build +++ b/rust/common/meson.build @@ -1,13 +1,9 @@ _common_cfg = run_command(rustc_args, - '--config-headers', config_host_h, '--features', files('Cargo.toml'), + '--config-headers', config_host_h, files('Cargo.toml'), capture: true, check: true).stdout().strip().splitlines() -_common_rs = static_library( - 'common', - 'src/lib.rs', - rust_args: _common_cfg, - dependencies: [libc_rs, qemu_macros], -) +_common_rs = cargo_ws.package('common').library(rust_args: _common_cfg) +cargo_ws.package('common').override_dependency(declare_dependency(link_with: _common_rs)) common_rs = declare_dependency(link_with: [_common_rs]) diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build index 1a1a09e508..92b7d375f7 100644 --- a/rust/hw/char/pl011/meson.build +++ b/rust/hw/char/pl011/meson.build @@ -8,8 +8,7 @@ _libpl011_bindings_inc_rs = rust.bindgen( kwargs: bindgen_kwargs, ) -_libpl011_rs = static_library( - 'pl011', +_libpl011_rs = cargo_ws.package('pl011').library( structured_sources( [ 'src/lib.rs', @@ -19,25 +18,6 @@ _libpl011_rs = static_library( ], {'.' : _libpl011_bindings_inc_rs}, ), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - link_with: [ - _util_rs, - _migration_rs, - _bql_rs, - _qom_rs, - _chardev_rs, - _system_rs, - _hwcore_rs, - _trace_rs - ], - dependencies: [ - bilge_rs, - bilge_impl_rs, - bits_rs, - common_rs, - glib_sys_rs, - ], ) rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency( diff --git a/rust/hw/core/meson.build b/rust/hw/core/meson.build index 6d1bfd4d20..da0f13d314 100644 --- a/rust/hw/core/meson.build +++ b/rust/hw/core/meson.build @@ -1,11 +1,5 @@ -_hwcore_rs = static_library( - 'hwcore', - 'src/lib.rs', - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - link_with: [_bql_rs, _chardev_rs, _migration_rs, _qom_rs, _util_rs], - dependencies: [glib_sys_rs, qemu_macros, common_rs, hwcore_sys_rs], -) +_hwcore_rs = cargo_ws.package('hwcore').library() +cargo_ws.package('hwcore').override_dependency(declare_dependency(link_with: _hwcore_rs)) hwcore_rs = declare_dependency(link_with: [_hwcore_rs], dependencies: [qom_rs, hwcore]) diff --git a/rust/hw/timer/hpet/meson.build b/rust/hw/timer/hpet/meson.build index 3bb7ce2a6c..419e8f40b7 100644 --- a/rust/hw/timer/hpet/meson.build +++ b/rust/hw/timer/hpet/meson.build @@ -1,19 +1,4 @@ -_libhpet_rs = static_library( - 'hpet', - files('src/lib.rs'), - override_options: ['rust_std=2021', 'build.rust_std=2021'], - rust_abi: 'rust', - link_with: [ - _util_rs, - _migration_rs, - _bql_rs, - _qom_rs, - _system_rs, - _hwcore_rs, - _trace_rs, - ], - dependencies: [common_rs], -) +_libhpet_rs = cargo_ws.package('hpet').library() rust_devices_ss.add(when: 'CONFIG_X_HPET_RUST', if_true: [declare_dependency( link_whole: [_libhpet_rs], diff --git a/rust/meson.build b/rust/meson.build index 1622a50a97..c0c4e52c1b 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -5,17 +5,6 @@ else endif cargo_ws = import('rust').workspace() -anyhow_rs = cargo_ws.subproject('anyhow').dependency() -bilge_rs = cargo_ws.subproject('bilge').dependency() -bilge_impl_rs = cargo_ws.subproject('bilge-impl').dependency() -foreign_rs = cargo_ws.subproject('foreign').dependency() -glib_sys_rs = cargo_ws.subproject('glib-sys').dependency() -libc_rs = cargo_ws.subproject('libc').dependency() -probe_rs = cargo_ws.subproject('probe').dependency() -quote_rs_native = cargo_ws.subproject('quote').dependency() -syn_rs_native = cargo_ws.subproject('syn').dependency() -proc_macro2_rs_native = cargo_ws.subproject('proc-macro2').dependency() -attrs_rs_native = cargo_ws.subproject('attrs').dependency() genrs = [] diff --git a/rust/migration/meson.build b/rust/migration/meson.build index 9626689777..b9ba82989e 100644 --- a/rust/migration/meson.build +++ b/rust/migration/meson.build @@ -1,9 +1,5 @@ -_migration_rs = static_library( - 'migration', - 'src/lib.rs', - link_with: [_util_rs, _bql_rs], - dependencies: [common_rs, glib_sys_rs, qemu_macros, migration_sys_rs], -) +_migration_rs = cargo_ws.package('migration').library() +cargo_ws.package('migration').override_dependency(declare_dependency(link_with: _migration_rs)) migration_rs = declare_dependency(link_with: [_migration_rs], dependencies: [bql_rs, migration, qemuutil]) diff --git a/rust/qemu-macros/meson.build b/rust/qemu-macros/meson.build index cdea5bf439..7b25ccefe3 100644 --- a/rust/qemu-macros/meson.build +++ b/rust/qemu-macros/meson.build @@ -1,13 +1,5 @@ -_qemu_macros_rs = rust.proc_macro( - 'qemu_macros', - files('src/lib.rs'), - dependencies: [ - attrs_rs_native, - proc_macro2_rs_native, - quote_rs_native, - syn_rs_native, - ], -) +_qemu_macros_rs = cargo_ws.package('qemu_macros').proc_macro() +cargo_ws.package('qemu_macros').override_dependency(declare_dependency(link_with: _qemu_macros_rs)) qemu_macros = declare_dependency( link_with: _qemu_macros_rs, diff --git a/rust/qom/meson.build b/rust/qom/meson.build index 9865da280c..6736cfb24c 100644 --- a/rust/qom/meson.build +++ b/rust/qom/meson.build @@ -1,9 +1,5 @@ -_qom_rs = static_library( - 'qom', - 'src/lib.rs', - link_with: [_bql_rs, _migration_rs], - dependencies: [common_rs, glib_sys_rs, qemu_macros, qom_sys_rs], -) +_qom_rs = cargo_ws.package('qom').library() +cargo_ws.package('qom').override_dependency(declare_dependency(link_with: _qom_rs)) qom_rs = declare_dependency(link_with: [_qom_rs], dependencies: [qemu_macros, qom, qemuutil]) diff --git a/rust/system/meson.build b/rust/system/meson.build index 89c1f2b84d..b1edcd6bbe 100644 --- a/rust/system/meson.build +++ b/rust/system/meson.build @@ -1,9 +1,5 @@ -_system_rs = static_library( - 'system', - 'src/lib.rs', - link_with: [_bql_rs, _hwcore_rs, _migration_rs, _qom_rs, _util_rs], - dependencies: [glib_sys_rs, common_rs, qemu_macros, system_sys_rs], -) +_system_rs = cargo_ws.package('system').library() +cargo_ws.package('system').override_dependency(declare_dependency(link_with: _system_rs)) system_rs = declare_dependency(link_with: [_system_rs], dependencies: [hwcore]) diff --git a/rust/trace/meson.build b/rust/trace/meson.build index 0071a49cf7..b049f73b54 100644 --- a/rust/trace/meson.build +++ b/rust/trace/meson.build @@ -7,11 +7,8 @@ lib_rs = configure_file( 'MESON_BUILD_ROOT': meson.project_build_root(), }) -_trace_rs = static_library( - 'trace', # Library name, - lib_rs, - trace_rs_targets, # List of generated `.rs` custom targets - dependencies: [libc_rs, probe_rs], -) +_trace_rs = cargo_ws.package('trace').library( + structured_sources([lib_rs, trace_rs_targets])) +cargo_ws.package('trace').override_dependency(declare_dependency(link_with: _trace_rs)) trace_rs = declare_dependency(link_with: _trace_rs) diff --git a/rust/util/meson.build b/rust/util/meson.build index 6d175ae0b0..704501b573 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -1,8 +1,5 @@ -_util_rs = static_library( - 'util', - 'src/lib.rs', - dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, util_sys_rs], -) +_util_rs = cargo_ws.package('util').library() +cargo_ws.package('util').override_dependency(declare_dependency(link_with: _util_rs)) util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom]) From aac1b59b8577fc939c297025886a44d25bd635c3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Jul 2026 15:57:39 +0200 Subject: [PATCH 412/627] docs: rust: update for new-style build rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 83 +++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 56 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index af142c4a69..94c550b39b 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -21,15 +21,11 @@ invokes rustc directly, building static libraries that are then linked together with the C code. This is completely automatic when you run ``make`` or ``ninja``. -However, QEMU's build system also tries to be easy to use for people who -are accustomed to the more "normal" Cargo-based development workflow. -In particular: - -* the set of warnings and lints that are used to build QEMU always - comes from the ``Cargo.toml`` workspace file - -* it is also possible to use ``cargo`` for common Rust-specific coding - tasks, in particular to invoke ``clippy``, ``rustfmt`` and ``rustdoc``. +However, Meson is able to consume ``Cargo.toml`` files and tries +to be easy to use for people who are accustomed to the more "normal" +Cargo-based development workflow. In the case of QEMU, in addition, +it is possible to use ``cargo`` for common Rust-specific coding +tasks, in particular to invoke ``clippy``, ``rustfmt`` and ``rustdoc``. To this end, QEMU includes a ``build.rs`` build script that picks up generated sources from QEMU's build directory and puts it in Cargo's @@ -466,63 +462,38 @@ Adding dependencies Generally, the set of dependent crates is kept small. Think twice before adding a new external crate, especially if it comes with a large set of dependencies itself. Sometimes QEMU only needs a small subset of the -functionality; see for example QEMU's ``assertions`` module. +functionality; see for example QEMU's ``assertions`` module. Also, +choose a version of the crate that works with QEMU's minimum supported +Rust version (|msrv|). On top of this recommendation, adding external crates to QEMU is a slightly complicated process, mostly due to the need to teach Meson how -to build them. While Meson has initial support for parsing ``Cargo.lock`` -files, it is still highly experimental and is therefore not used. +to download them. While QEMU uses Meson's support for parsing ``Cargo.toml`` +files, it ships ``.wrap`` files instead of using ``Cargo.lock``; this way, +distros can adjust the set of dependencies to the exact versions they use. +The versions specified in QEMU's ``Cargo.lock`` must be the same as the +one in the wrap file. -Therefore, external crates must be added as subprojects for Meson to -learn how to build them, as well as to the relevant ``Cargo.toml`` files. -The versions specified in ``Cargo.lock`` must be the same as the -subprojects; note that the QEMU source tree forms a Cargo `workspace`__, -and therefore there is a single lock file for the whole build. - -__ https://doc.rust-lang.org/cargo/reference/workspaces.html#virtual-workspace - -Choose a version of the crate that works with QEMU's minimum supported -Rust version (|msrv|). - -Second, a new ``wrap`` file must be added to teach Meson how to download the -crate. The wrap file must be named ``NAME-SEMVER-rs.wrap``, where ``NAME`` +The wrap file must be named ``NAME-SEMVER-rs.wrap``, where ``NAME`` is the name of the crate and ``SEMVER`` is the version up to and including the first non-zero number. For example, a crate with version ``0.2.3`` will use ``0.2`` for its ``SEMVER``, while a crate with version ``1.0.84`` will use ``1``. -Third, the Meson rules to build the crate must be added at -``subprojects/NAME-SEMVER-rs/meson.build``. Generally this includes: +Usually, Meson is able to figure out how to build the crate, and also handles +cross compilation correctly. For crates that have a ``build.rs`` file, +equivalent rules must be added to +``subprojects/packagefiles/NAME-SEMVER-rs/meson/meson.build``. +The file can modify the ``extra_args`` and ``extra_deps`` variables, +which contain respectively the compiler arguments and external dependencies +for the crate. -* ``subproject`` and ``dependency`` lines for all dependent crates +After every change to the ``meson/meson.build`` file you have to update the +patched version with ``meson subprojects update --reset ``NAME-SEMVER-rs``. +This might be automated in the future. -* a ``static_library`` or ``rust.proc_macro`` line to perform the actual build - -* ``declare_dependency`` and a ``meson.override_dependency`` lines to expose - the result to QEMU and to other subprojects - -Remember to add ``native: true`` to ``dependency``, ``static_library`` and -``meson.override_dependency`` for dependencies of procedural macros. -If a crate is needed in both procedural macros and QEMU binaries, everything -apart from ``subproject`` must be duplicated to build both native and -non-native versions of the crate. - -It's important to specify the right compiler options. These include: - -* the language edition (which can be found in the ``Cargo.toml`` file) - -* the ``--cfg`` (which have to be "reverse engineered" from the ``build.rs`` - file of the crate). - -* usually, a ``--cap-lints allow`` argument to hide warnings from rustc - or clippy. - -After every change to the ``meson.build`` file you have to update the patched -version with ``meson subprojects update --reset ``NAME-SEMVER-rs``. This might -be automated in the future. - -Also, after every change to the ``meson.build`` file it is strongly suggested to -do a dummy change to the ``.wrap`` file (for example adding a comment like -``# version 2``), which will help Meson notice that the subproject is out of date. +Also, after every change to the file it is strongly suggested to do a dummy +change to the ``.wrap`` file (for example adding a comment like ``# version 2``), +which will help Meson notice that the subproject is out of date. As a last step, add the new subproject to ``scripts/archive-source.sh``, ``scripts/make-release`` and ``subprojects/.gitignore``. From 0836a79adafe9c5089839621ac761f84b92e95cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 May 2026 17:53:42 +0200 Subject: [PATCH 413/627] scripts: remove now dead parts of rustc_args.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic to parse the [lints] section has been integrated into Meson and can be removed. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- meson.build | 1 - scripts/rust/rustc_args.py | 80 +------------------------------------- 2 files changed, 1 insertion(+), 80 deletions(-) diff --git a/meson.build b/meson.build index 3c6a82ab44..6dcfdceb50 100644 --- a/meson.build +++ b/meson.build @@ -130,7 +130,6 @@ endif if have_rust rustc_args = [find_program('scripts/rust/rustc_args.py'), - '--rustc-version', rustc.version(), '--workspace', meson.project_source_root()] rustfmt = find_program('rustfmt', required: false) diff --git a/scripts/rust/rustc_args.py b/scripts/rust/rustc_args.py index 8098053720..107b944c16 100644 --- a/scripts/rust/rustc_args.py +++ b/scripts/rust/rustc_args.py @@ -25,10 +25,9 @@ along with this program. If not, see . """ import argparse -from dataclasses import dataclass import logging from pathlib import Path -from typing import Any, Iterable, List, Mapping, Optional, Set +from typing import Any, Iterable, Mapping, Optional, Set try: import tomllib @@ -74,40 +73,6 @@ class CargoTOML: return table -@dataclass -class LintFlag: - flags: List[str] - priority: int - - -def generate_lint_flags(cargo_toml: CargoTOML) -> Iterable[str]: - """Converts Cargo.toml lints to rustc -A/-D/-F/-W flags.""" - - toml_lints = cargo_toml.lints - - lint_list = [] - for k, v in toml_lints.items(): - prefix = "" if k == "rust" else k + "::" - for lint, data in v.items(): - level = data if isinstance(data, str) else data["level"] - priority = 0 if isinstance(data, str) else data.get("priority", 0) - if level == "deny": - flag = "-D" - elif level == "allow": - flag = "-A" - elif level == "warn": - flag = "-W" - elif level == "forbid": - flag = "-F" - else: - raise Exception(f"invalid level {level} for {prefix}{lint}") - lint_list.append(LintFlag(flags=[flag, prefix + lint], priority=priority)) - - lint_list.sort(key=lambda x: x.priority) - for lint in lint_list: - yield from lint.flags - - def generate_cfg_flags(header: str, cargo_toml: CargoTOML) -> Iterable[str]: """Converts defines from config[..].h headers to rustc --cfg flags.""" @@ -154,60 +119,17 @@ def main() -> None: required=False, default=None, ) - parser.add_argument( - "--features", - action="store_true", - dest="features", - help="generate --check-cfg arguments for features", - required=False, - default=None, - ) - parser.add_argument( - "--lints", - action="store_true", - dest="lints", - help="generate arguments from [lints] table", - required=False, - default=None, - ) - parser.add_argument( - "--rustc-version", - metavar="VERSION", - dest="rustc_version", - action="store", - help="version of rustc", - required=False, - default="1.0.0", - ) args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.DEBUG) logging.debug("args: %s", args) - rustc_version = tuple((int(x) for x in args.rustc_version.split('.')[0:2])) if args.workspace: workspace_cargo_toml = Path(args.workspace, "Cargo.toml").resolve() cargo_toml = CargoTOML(args.cargo_toml, str(workspace_cargo_toml)) else: cargo_toml = CargoTOML(args.cargo_toml, None) - if args.lints: - for tok in generate_lint_flags(cargo_toml): - print(tok) - - if rustc_version >= (1, 80): - if args.lints: - print("--check-cfg") - print("cfg(test)") - for cfg in sorted(cargo_toml.check_cfg): - print("--check-cfg") - print(cfg) - if args.features: - for feature in cargo_toml.get_table("features"): - if feature != "default": - print("--check-cfg") - print(f'cfg(feature,values("{feature}"))') - for header in args.config_headers: for tok in generate_cfg_flags(header, cargo_toml): print(tok) From 7d33e694afdd9afe748aeea69bc768a26784e6ab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Jul 2026 12:01:24 +0200 Subject: [PATCH 414/627] rust: update Cargo dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update dependencies that are not used by meson, only by Cargo. Several packages have now reached v1 and therefore updates may be less intrusive in the future. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- Cargo.lock | 85 +++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c94c2386d9..66f684098d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", @@ -212,12 +212,6 @@ version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - [[package]] name = "migration" version = "0.1.0" @@ -342,29 +336,20 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "serde" -version = "1.0.226" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" -dependencies = [ - "serde_core", -] - [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -373,18 +358,18 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "syn" @@ -413,9 +398,9 @@ dependencies = [ [[package]] name = "system-deps" -version = "7.0.5" +version = "7.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" dependencies = [ "cfg-expr", "heck", @@ -458,38 +443,43 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" dependencies = [ - "serde", + "indexmap", + "serde_core", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "toml_edit" -version = "0.22.27" +name = "toml_parser" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", "winnow", ] +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + [[package]] name = "trace" version = "0.1.0" @@ -537,9 +527,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" From 64574f1c517bc5a6eee56d94d7db46fd602044d8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 13 May 2025 10:23:44 +0200 Subject: [PATCH 415/627] rust: pl011: switch from bilge to bitfield-struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bilge crate is heavily reliant on traits and, because trait functions are never const, bilge and const mix about as well as water and oil. In addition, it has support for the zerocopy crate that only works for an older version, and is hard to update because the implementation doesn't like that zerocopy::FromBits and bilge::FromBits are the same name. zerocopy is definitely something that QEMU could use in the future. The bitfield-struct crate, instead, is built from the ground up to support const. Its use is pretty much the same (device code does not change at all, only register declarations do), with some things being more verbose and others being simpler. The code for the crate itself is much smaller, too. It does have two disadvantages: it does not let you annotate enums as bitfields, and it does not integrate with arbitrary-int. Thus, it requires manual size annotations for anything that is not a bool, iNN or uNN. Lack of support for arbitrary-int is a very small deal, while enums are a bit more annoying because they require some repetition and an implementation of two functions from_bits() and into_bits(). However, the latter is already provided by the "bits!" and "#[derive(common::TryInto)]" utilities, and thus is not manual in QEMU's case. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- Cargo.lock | 14 ++- Cargo.toml | 1 + rust/hw/char/pl011/Cargo.toml | 3 +- rust/hw/char/pl011/src/registers.rs | 108 +++++++++++------------ scripts/archive-source.sh | 1 + scripts/make-release | 1 + subprojects/.gitignore | 1 + subprojects/bitfield-struct-0.13-rs.wrap | 6 ++ 8 files changed, 75 insertions(+), 60 deletions(-) create mode 100644 subprojects/bitfield-struct-0.13-rs.wrap diff --git a/Cargo.lock b/Cargo.lock index 66f684098d..6f683e8bb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,17 @@ dependencies = [ "syn", ] +[[package]] +name = "bitfield-struct" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca6739863c590881f038d033a146c51ddae239186a4327014839fd864f44ed5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bilge" version = "0.2.0" @@ -243,8 +254,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" name = "pl011" version = "0.1.0" dependencies = [ - "bilge", - "bilge-impl", + "bitfield-struct", "bits", "bql", "chardev", diff --git a/Cargo.toml b/Cargo.toml index 0566850ece..b35704faab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,5 +101,6 @@ used_underscore_binding = "deny" #wildcard_imports = "deny" # still have many bindings::* imports # these may have false positives +enum_variant_names = "allow" #option_if_let_else = "deny" cognitive_complexity = "deny" diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml index 5b319455ee..d303c241e4 100644 --- a/rust/hw/char/pl011/Cargo.toml +++ b/rust/hw/char/pl011/Cargo.toml @@ -14,8 +14,7 @@ rust-version.workspace = true [dependencies] glib-sys.workspace = true -bilge = { version = "0.2.0" } -bilge-impl = { version = "0.2.0" } +bitfield-struct = { version = "0.13" } bits = { path = "../../../bits" } common = { path = "../../../common" } util = { path = "../../../util" } diff --git a/rust/hw/char/pl011/src/registers.rs b/rust/hw/char/pl011/src/registers.rs index fa572811b2..a8ab8ad93d 100644 --- a/rust/hw/char/pl011/src/registers.rs +++ b/rust/hw/char/pl011/src/registers.rs @@ -5,12 +5,16 @@ //! Device registers exposed as typed structs which are backed by arbitrary //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc. +// rustc prefers "constant-like" enums to use upper case names, but that +// is inconsistent in its own way. +#![allow(non_upper_case_globals)] + // For more detail see the PL011 Technical Reference Manual DDI0183: // https://developer.arm.com/documentation/ddi0183/latest/ -use bilge::prelude::*; +use bitfield_struct::bitfield; use bits::bits; -use migration::{impl_vmstate_bitsized, impl_vmstate_forward}; +use migration::impl_vmstate_forward; /// Offset of each register from the base memory address of the device. #[doc(alias = "offset")] @@ -78,14 +82,18 @@ pub enum RegisterOffset { /// The `UARTRSR` register is updated only when a read occurs /// from the `UARTDR` register with the same status information /// that can also be obtained by reading the `UARTDR` register -#[bitsize(8)] -#[derive(Clone, Copy, Default, DebugBits, FromBits)] +#[bitfield(u8)] pub struct Errors { pub framing_error: bool, pub parity_error: bool, pub break_error: bool, pub overrun_error: bool, - _reserved_unpredictable: u4, + #[bits(4)] + _reserved_unpredictable: u8, +} + +impl Errors { + pub const BREAK: Self = Errors::new().with_break_error(true); } /// Data Register, `UARTDR` @@ -93,19 +101,18 @@ pub struct Errors { /// The `UARTDR` register is the data register; write for TX and /// read for RX. It is a 12-bit register, where bits 7..0 are the /// character and bits 11..8 are error bits. -#[bitsize(32)] -#[derive(Clone, Copy, Default, DebugBits, FromBits)] +#[bitfield(u32)] #[doc(alias = "UARTDR")] pub struct Data { pub data: u8, + #[bits(8)] pub errors: Errors, _reserved: u16, } -impl_vmstate_bitsized!(Data); +impl_vmstate_forward!(Data); impl Data { - // bilge is not very const-friendly, unfortunately - pub const BREAK: Self = Self { value: 1 << 10 }; + pub const BREAK: Self = Self::new().with_errors(Errors::BREAK); } /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR` @@ -119,13 +126,14 @@ impl Data { /// and UARTECR for writes, but really it's a single error status /// register where writing anything to the register clears the error /// bits. -#[bitsize(32)] -#[derive(Clone, Copy, DebugBits, FromBits)] +#[bitfield(u32)] pub struct ReceiveStatusErrorClear { + #[bits(8)] pub errors: Errors, - _reserved_unpredictable: u24, + #[bits(24)] + _reserved_unpredictable: u32, } -impl_vmstate_bitsized!(ReceiveStatusErrorClear); +impl_vmstate_forward!(ReceiveStatusErrorClear); impl ReceiveStatusErrorClear { pub fn set_from_data(&mut self, data: Data) { @@ -138,14 +146,7 @@ impl ReceiveStatusErrorClear { } } -impl Default for ReceiveStatusErrorClear { - fn default() -> Self { - 0.into() - } -} - -#[bitsize(32)] -#[derive(Clone, Copy, DebugBits, FromBits)] +#[bitfield(u32, default = false)] /// Flag Register, `UARTFR` /// /// This has the usual inbound RS232 modem-control signals, plus flags @@ -171,9 +172,10 @@ pub struct Flags { pub transmit_fifo_empty: bool, /// RI: Ring indicator pub ring_indicator: bool, - _reserved_zero_no_modify: u23, + #[bits(23)] + _reserved_zero_no_modify: u32, } -impl_vmstate_bitsized!(Flags); +impl_vmstate_forward!(Flags); impl Flags { pub fn reset(&mut self) { @@ -183,16 +185,14 @@ impl Flags { impl Default for Flags { fn default() -> Self { - let mut ret: Self = 0.into(); // After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1 - ret.set_receive_fifo_empty(true); - ret.set_transmit_fifo_empty(true); - ret + Self::from(0) + .with_receive_fifo_empty(true) + .with_transmit_fifo_empty(true) } } -#[bitsize(32)] -#[derive(Clone, Copy, DebugBits, FromBits)] +#[bitfield(u32)] /// Line Control Register, `UARTLCR_H` #[doc(alias = "UARTLCR_H")] pub struct LineControl { @@ -201,48 +201,46 @@ pub struct LineControl { /// PEN: Parity enable pub parity_enabled: bool, /// EPS: Even parity select + #[bits(1)] pub parity: Parity, /// STP2: Two stop bits select pub two_stops_bits: bool, /// FEN: Enable FIFOs + #[bits(1)] pub fifos_enabled: Mode, /// WLEN: Word length in bits /// b11 = 8 bits /// b10 = 7 bits /// b01 = 6 bits /// b00 = 5 bits. + #[bits(2)] pub word_length: WordLength, /// SPS Stick parity select pub sticky_parity: bool, /// 31:8 - Reserved, do not modify, read as zero. - _reserved_zero_no_modify: u24, + #[bits(24)] + _reserved_zero_no_modify: u32, } -impl_vmstate_bitsized!(LineControl); +impl_vmstate_forward!(LineControl); impl LineControl { pub fn reset(&mut self) { // All the bits are cleared to 0 when reset. - *self = 0.into(); + *self = Self::default(); } } -impl Default for LineControl { - fn default() -> Self { - 0.into() - } -} - -#[bitsize(1)] -#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)] /// `EPS` "Even parity select", field of [Line Control /// register](LineControl). +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)] pub enum Parity { Odd = 0, Even = 1, } -#[bitsize(1)] -#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)] +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)] /// `FEN` "Enable FIFOs" or Device mode, field of [Line Control /// register](LineControl). pub enum Mode { @@ -253,8 +251,8 @@ pub enum Mode { FIFO = 1, } -#[bitsize(2)] -#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)] +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)] #[allow(clippy::enum_variant_names)] /// `WLEN` Word length, field of [Line Control register](LineControl). /// @@ -276,9 +274,8 @@ pub enum WordLength { /// The `UARTCR` register is the control register. It contains various /// enable bits, and the bits to write to set the usual outbound RS232 /// modem control signals. All bits reset to 0 except TXE and RXE. -#[bitsize(32)] +#[bitfield(u32, default = false)] #[doc(alias = "UARTCR")] -#[derive(Clone, Copy, DebugBits, FromBits)] pub struct Control { /// `UARTEN` UART enable: 0 = UART is disabled. pub enable_uart: bool, @@ -286,9 +283,10 @@ pub struct Control { /// QEMU does not model this. pub enable_sir: bool, /// `SIRLP` SIR low-power IrDA mode. QEMU does not model this. - pub sir_lowpower_irda_mode: u1, + pub sir_lowpower_irda_mode: bool, /// Reserved, do not modify, read as zero. - _reserved_zero_no_modify: u4, + #[bits(4)] + _reserved_zero_no_modify: u8, /// `LBE` Loopback enable: feed UART output back to the input pub enable_loopback: bool, /// `TXE` Transmit enable @@ -310,21 +308,19 @@ pub struct Control { /// 31:16 - Reserved, do not modify, read as zero. _reserved_zero_no_modify2: u16, } -impl_vmstate_bitsized!(Control); +impl_vmstate_forward!(Control); impl Control { pub fn reset(&mut self) { - *self = 0.into(); - self.set_enable_receive(true); - self.set_enable_transmit(true); + *self = Self::default(); } } impl Default for Control { fn default() -> Self { - let mut ret: Self = 0.into(); - ret.reset(); - ret + Self::from(0) + .with_enable_receive(true) + .with_enable_transmit(true) } } diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index a37acab524..5d52644df9 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -34,6 +34,7 @@ subprojects=( berkeley-testfloat-3 bilge-0.2-rs bilge-impl-0.2-rs + bitfield-0.9-rs either-1-rs foreign-0.3-rs glib-sys-0.21-rs diff --git a/scripts/make-release b/scripts/make-release index 5f54b0e793..fc0dc4bceb 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -42,6 +42,7 @@ fi SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs + bilge-impl-0.2-rs bitfield-0.9-rs either-1-rs foreign-0.3-rs itertools-0.11-rs libc-0.2-rs probe-0.5-rs proc-macro2-1-rs proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs syn-2-rs unicode-ident-1-rs" diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 011ce4dc3b..984f5865dc 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -11,6 +11,7 @@ /attrs-* /bilge-* /bilge-impl-* +/bitfield-struct-* /either-* /foreign-* /glib-sys-* diff --git a/subprojects/bitfield-struct-0.13-rs.wrap b/subprojects/bitfield-struct-0.13-rs.wrap new file mode 100644 index 0000000000..dcffe0abd8 --- /dev/null +++ b/subprojects/bitfield-struct-0.13-rs.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = bitfield-struct-0.13.0 +source_url = https://crates.io/api/v1/crates/bitfield-struct/0.13.0/download +source_filename = bitfield-struct-0.13.0.tar.gz +source_hash = 3ca6739863c590881f038d033a146c51ddae239186a4327014839fd864f44ed5 +method = cargo From 3ac34c6d25d84353c882ab0e11ea25229d4f1a48 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Jul 2026 11:52:41 +0200 Subject: [PATCH 416/627] rust: remove bilge crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It has just been replaced with bitfield-struct. Reviewed-by: Marc-André Lureau Signed-off-by: Paolo Bonzini --- Cargo.lock | 73 ------------------- rust/migration/src/vmstate.rs | 45 +----------- scripts/archive-source.sh | 6 -- scripts/make-release | 5 +- subprojects/.gitignore | 7 -- subprojects/arbitrary-int-1-rs.wrap | 9 --- subprojects/bilge-0.2-rs.wrap | 9 --- subprojects/bilge-impl-0.2-rs.wrap | 9 --- subprojects/either-1-rs.wrap | 9 --- subprojects/itertools-0.11-rs.wrap | 9 --- .../proc-macro-error-1-rs/meson/meson.build | 3 - subprojects/proc-macro-error-1-rs.wrap | 10 --- subprojects/proc-macro-error-attr-1-rs.wrap | 9 --- 13 files changed, 5 insertions(+), 198 deletions(-) delete mode 100644 subprojects/arbitrary-int-1-rs.wrap delete mode 100644 subprojects/bilge-0.2-rs.wrap delete mode 100644 subprojects/bilge-impl-0.2-rs.wrap delete mode 100644 subprojects/either-1-rs.wrap delete mode 100644 subprojects/itertools-0.11-rs.wrap delete mode 100644 subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build delete mode 100644 subprojects/proc-macro-error-1-rs.wrap delete mode 100644 subprojects/proc-macro-error-attr-1-rs.wrap diff --git a/Cargo.lock b/Cargo.lock index 6f683e8bb1..ad664a812d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "arbitrary-int" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d" - [[package]] name = "attrs" version = "0.2.9" @@ -35,29 +29,6 @@ dependencies = [ "syn", ] -[[package]] -name = "bilge" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57" -dependencies = [ - "arbitrary-int", - "bilge-impl", -] - -[[package]] -name = "bilge-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8" -dependencies = [ - "itertools", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "bits" version = "0.1.0" @@ -114,12 +85,6 @@ dependencies = [ "qemu_macros", ] -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - [[package]] name = "equivalent" version = "1.0.2" @@ -208,15 +173,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "libc" version = "0.2.162" @@ -274,29 +230,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "136558b6e1ebaecc92755d0ffaf9421f519531bed30cc2ad23b22cb00965cc5e" -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.95" @@ -529,12 +462,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "winnow" version = "1.0.4" diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index 63d78b4f27..7409b592a2 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -11,8 +11,7 @@ //! migration format for a struct. This is based on the [`VMState`] trait, //! which is defined by all migratable types. //! -//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward), -//! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and +//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and //! [`impl_vmstate_struct`](crate::impl_vmstate_struct), which help with the //! definition of the [`VMState`] trait (respectively for transparent structs, //! nested structs and `bilge`-defined types) @@ -90,7 +89,7 @@ macro_rules! call_func_with_field { /// The contents of this trait go straight into structs that are parsed by C /// code and used to introspect into other structs. Generally, you don't need /// to implement it except via macros that do it for you, such as -/// `impl_vmstate_bitsized!`. +/// `impl_vmstate_forward!`. pub unsafe trait VMState { /// The base contents of a `VMStateField` (minus the name and offset) for /// the type that is implementing the trait. @@ -133,9 +132,8 @@ pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags /// * an array of any of the above /// /// In order to support other types, the trait `VMState` must be implemented -/// for them. The macros [`impl_vmstate_forward`](crate::impl_vmstate_forward), -/// [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), and -/// [`impl_vmstate_struct`](crate::impl_vmstate_struct) help with this. +/// for them. The macros [`impl_vmstate_forward`](crate::impl_vmstate_forward) +/// and [`impl_vmstate_struct`](crate::impl_vmstate_struct) help with this. /// /// [`BqlCell`]: ../../bql/cell/struct.BqlCell.html /// [`BqlRefCell`]: ../../bql/cell/struct.BqlRefCell.html @@ -211,41 +209,6 @@ impl_vmstate_transparent!(std::pin::Pin where T: VMState); impl_vmstate_transparent!(common::Opaque where T: VMState); impl_vmstate_transparent!(std::mem::ManuallyDrop where T: VMState); -#[macro_export] -macro_rules! impl_vmstate_bitsized { - ($type:ty) => { - unsafe impl $crate::vmstate::VMState for $type { - const BASE: $crate::bindings::VMStateField = - <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt - as ::bilge::prelude::Number>::UnderlyingType - as $crate::vmstate::VMState>::BASE; - const VARRAY_FLAG: $crate::bindings::VMStateFlags = - <<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt - as ::bilge::prelude::Number>::UnderlyingType - as $crate::vmstate::VMState>::VARRAY_FLAG; - } - - impl $crate::migratable::ToMigrationState for $type { - type Migrated = <<$type as ::bilge::prelude::Bitsized>::ArbitraryInt - as ::bilge::prelude::Number>::UnderlyingType; - - fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), $crate::InvalidError> { - *target = Self::Migrated::from(*self); - Ok(()) - } - - fn restore_migrated_state_mut( - &mut self, - source: Self::Migrated, - version_id: u8, - ) -> Result<(), $crate::InvalidError> { - *self = Self::from(source); - Ok(()) - } - } - }; -} - // Scalar types using predefined VMStateInfos macro_rules! impl_vmstate_scalar { diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh index 5d52644df9..399b2d99e8 100755 --- a/scripts/archive-source.sh +++ b/scripts/archive-source.sh @@ -32,19 +32,13 @@ subprojects=( attrs-0.2-rs berkeley-softfloat-3 berkeley-testfloat-3 - bilge-0.2-rs - bilge-impl-0.2-rs bitfield-0.9-rs - either-1-rs foreign-0.3-rs glib-sys-0.21-rs - itertools-0.11-rs keycodemapdb libc-0.2-rs libvfio-user probe-0.5-rs - proc-macro-error-1-rs - proc-macro-error-attr-1-rs proc-macro2-1-rs quote-1-rs syn-2-rs diff --git a/scripts/make-release b/scripts/make-release index fc0dc4bceb..b5944d3928 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -41,10 +41,7 @@ fi # Only include wraps that are invoked with subproject() SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs - bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs - bilge-impl-0.2-rs bitfield-0.9-rs either-1-rs foreign-0.3-rs itertools-0.11-rs - libc-0.2-rs probe-0.5-rs proc-macro2-1-rs - proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs + bitfield-0.9-rs foreign-0.3-rs libc-0.2-rs probe-0.5-rs proc-macro2-1-rs quote-1-rs syn-2-rs unicode-ident-1-rs" src="$1" diff --git a/subprojects/.gitignore b/subprojects/.gitignore index 984f5865dc..3559b2c758 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -7,19 +7,12 @@ /libvfio-user /slirp /anyhow-* -/arbitrary-int-* /attrs-* -/bilge-* -/bilge-impl-* /bitfield-struct-* -/either-* /foreign-* /glib-sys-* -/itertools-* /libc-* /probe-* -/proc-macro-error-* -/proc-macro-error-attr-* /proc-macro* /quote-* /syn-* diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap deleted file mode 100644 index 5cf4b11e4a..0000000000 --- a/subprojects/arbitrary-int-1-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = arbitrary-int-1.2.7 -source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download -source_filename = arbitrary-int-1.2.7.tar.gz -source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap deleted file mode 100644 index cff10f6710..0000000000 --- a/subprojects/bilge-0.2-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = bilge-0.2.0 -source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download -source_filename = bilge-0.2.0.tar.gz -source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57 -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap deleted file mode 100644 index f8963eba73..0000000000 --- a/subprojects/bilge-impl-0.2-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = bilge-impl-0.2.0 -source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download -source_filename = bilge-impl-0.2.0.tar.gz -source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8 -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap deleted file mode 100644 index 51c97df153..0000000000 --- a/subprojects/either-1-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = either-1.12.0 -source_url = https://crates.io/api/v1/crates/either/1.12.0/download -source_filename = either-1.12.0.tar.gz -source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap deleted file mode 100644 index e123ab389a..0000000000 --- a/subprojects/itertools-0.11-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = itertools-0.11.0 -source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download -source_filename = itertools-0.11.0.tar.gz -source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57 -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build deleted file mode 100644 index 52a244d2b1..0000000000 --- a/subprojects/packagefiles/proc-macro-error-1-rs/meson/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -extra_args = [ - '--cfg', 'use_fallback', -] diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap deleted file mode 100644 index e57921bfad..0000000000 --- a/subprojects/proc-macro-error-1-rs.wrap +++ /dev/null @@ -1,10 +0,0 @@ -[wrap-file] -directory = proc-macro-error-1.0.4 -source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download -source_filename = proc-macro-error-1.0.4.tar.gz -source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c -method = cargo -patch_directory = proc-macro-error-1-rs - -# bump this version number on every change to meson.build or the patches: -# v3 diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap deleted file mode 100644 index 456d2c2b6d..0000000000 --- a/subprojects/proc-macro-error-attr-1-rs.wrap +++ /dev/null @@ -1,9 +0,0 @@ -[wrap-file] -directory = proc-macro-error-attr-1.0.4 -source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download -source_filename = proc-macro-error-attr-1.0.4.tar.gz -source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869 -method = cargo - -# bump this version number on every change to meson.build or the patches: -# v2 From dd45df326e420ed5fc3c181b716ff459beb4ac9e Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 13 Aug 2026 19:09:58 +0800 Subject: [PATCH 417/627] target/loongarch: Add kvm support dintc This patch adds Kvm put/get msgint CSRs and check msgint feature. Signed-off-by: Song Gao Reviewed-by: Bibo Mao Message-ID: <20260813111000.446232-2-gaosong@loongson.cn> --- target/loongarch/cpu.c | 5 ++- target/loongarch/cpu.h | 1 + target/loongarch/kvm/kvm.c | 74 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 8cd5bc18a3..48e1ad83c9 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -451,9 +451,6 @@ static void loongarch_max_initfn(Object *obj) cpu->ptw = ON_OFF_AUTO_AUTO; if (tcg_enabled()) { - cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1); - cpu->msgint = ON_OFF_AUTO_AUTO; - uint32_t data = cpu->env.cpucfg[2]; data = FIELD_DP32(data, CPUCFG2, HPTW, 1); /* Enable LA v1.1 instructions */ @@ -468,6 +465,8 @@ static void loongarch_max_initfn(Object *obj) data = FIELD_DP32(data, CPUCFG3, DBAR_HINTS, 1); cpu->env.cpucfg[3] = data; } + cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1); + cpu->msgint = ON_OFF_AUTO_AUTO; } #if defined(CONFIG_KVM) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index ad30c73167..97db3b453f 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -301,6 +301,7 @@ enum loongarch_features { LOONGARCH_FEATURE_PV_IPI, LOONGARCH_FEATURE_STEALTIME, LOONGARCH_FEATURE_PTW, + LOONGARCH_FEATURE_MSGINT, }; typedef struct LoongArchBT { diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 4d0cad5732..15082a01f8 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -36,6 +36,13 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; +static bool kvm_cpu_has_msgint(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + + return FIELD_EX64(cpu->env.cpucfg[1], CPUCFG1, MSG_INT); +} + static int kvm_get_stealtime(CPUState *cs) { CPULoongArchState *env = cpu_env(cs); @@ -362,6 +369,25 @@ static int kvm_loongarch_get_csr(CPUState *cs) ret |= kvm_loongarch_get_pmu(cs); + /* + * CSR register MSGIS getting must be put after CSR register CSR_ESTAT, + * Since register CSR_ESTAT will sync software pending MSGINT status to + * hardware register and modify HW CSR MSGIS registers. + */ + if (kvm_cpu_has_msgint(cs)) { + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(0)), + &sys->CSR_MSGIS[0]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(1)), + &sys->CSR_MSGIS[1]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(2)), + &sys->CSR_MSGIS[2]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(3)), + &sys->CSR_MSGIS[3]); + } + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), &sys->CSR_TVAL); @@ -538,6 +564,20 @@ static int kvm_loongarch_put_csr(CPUState *cs, KvmPutState level) ret |= kvm_loongarch_put_pmu(cs); + if (kvm_cpu_has_msgint(cs)) { + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(0)), + &sys->CSR_MSGIS[0]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(1)), + &sys->CSR_MSGIS[1]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(2)), + &sys->CSR_MSGIS[2]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MSGIS(3)), + &sys->CSR_MSGIS[3]); + } + /* * timer cfg must be put at last since it is used to enable * guest timer @@ -993,6 +1033,12 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); return (ret == 0); + case LOONGARCH_FEATURE_MSGINT: + attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; + attr.attr = KVM_LOONGARCH_VM_FEAT_MSGINT; + ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); + return (ret == 0); + default: return false; } @@ -1166,6 +1212,28 @@ static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp) return 0; } +static int kvm_cpu_check_msgint(CPUState *cs, Error **errp) +{ + CPULoongArchState *env = cpu_env(cs); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + bool kvm_supported; + + kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_MSGINT); + env->cpucfg[1] = FIELD_DP32(env->cpucfg[1], CPUCFG1, MSG_INT, 0); + if (cpu->msgint == ON_OFF_AUTO_ON) { + if (kvm_supported) { + env->cpucfg[1] = FIELD_DP32(env->cpucfg[1], CPUCFG1, MSG_INT, 1); + } else { + error_setg(errp, "'msgint' feature not supported by KVM on this host"); + return -ENOTSUP; + } + } else if ((cpu->msgint == ON_OFF_AUTO_AUTO) && kvm_supported) { + env->cpucfg[1] = FIELD_DP32(env->cpucfg[1], CPUCFG1, MSG_INT, 1); + } + + return 0; +} + int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) { return 0; @@ -1221,6 +1289,12 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } + ret = kvm_cpu_check_msgint(cs, &local_err); + if (ret < 0) { + error_report_err(local_err); + return ret; + } + return 0; } From 06e75b3923a4dc265155a2859c33fc4405718771 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 13 Aug 2026 19:09:59 +0800 Subject: [PATCH 418/627] Add dintc kvm_irqchip_in_kernel support Function kvm_dintc_realize() is added if kvm_irqchip_in_kernel is set. It is to create and initialize DINTC device in kernel mode. and use kvm_irqchip_send_msi() to send msi to kernel. Signed-off-by: Song Gao Reviewed-by: Bibo Mao Message-ID: <20260813111000.446232-3-gaosong@loongson.cn> --- hw/intc/loongarch_dintc.c | 13 +++++++++ hw/intc/loongarch_dintc_kvm.c | 48 +++++++++++++++++++++++++++++++ hw/intc/meson.build | 2 ++ include/hw/intc/loongarch_dintc.h | 10 +++++++ 4 files changed, 73 insertions(+) create mode 100644 hw/intc/loongarch_dintc_kvm.c diff --git a/hw/intc/loongarch_dintc.c b/hw/intc/loongarch_dintc.c index e40292887c..94d418261c 100644 --- a/hw/intc/loongarch_dintc.c +++ b/hw/intc/loongarch_dintc.c @@ -68,6 +68,15 @@ static void loongarch_dintc_mem_write(void *opaque, hwaddr addr, } irq_num = FIELD_EX64(msg_addr, MSG_ADDR, IRQ_NUM); + if (kvm_irqchip_in_kernel()) { + MSIMessage msg; + + msg.address = msg_addr; + msg.data = val; + kvm_irqchip_send_msi(kvm_state, msg); + return; + } + async_run_on_cpu(cs, do_set_vcpu_dintc_irq, RUN_ON_CPU_HOST_INT(irq_num)); qemu_set_irq(s->cpu[cpu_num].parent_irq, 1); @@ -110,6 +119,10 @@ static void loongarch_dintc_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out(dev, &s->cpu[i].parent_irq, 1); } + if (kvm_irqchip_in_kernel()) { + kvm_dintc_realize(dev, errp); + } + return; } diff --git a/hw/intc/loongarch_dintc_kvm.c b/hw/intc/loongarch_dintc_kvm.c new file mode 100644 index 0000000000..1137bcd9a6 --- /dev/null +++ b/hw/intc/loongarch_dintc_kvm.c @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch DINTC interrupt kvm support + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/intc/loongarch_dintc.h" +#include "linux/kvm.h" +#include "qapi/error.h" +#include "system/kvm.h" + +void kvm_dintc_realize(DeviceState *dev, Error **errp) +{ + LoongArchDINTCState *lds = LOONGARCH_DINTC(dev); + int ret; + + ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_DMSINTC, false); + if (ret < 0) { + fprintf(stderr, "create KVM_DEV_TYPE_LOONGARCH_AVEC failed: %s\n", + strerror(-ret)); + abort(); + } + lds->dev_fd = ret; + + /* init dintc config */ + lds->msg_addr_base = VIRT_DINTC_BASE; + lds->msg_addr_size = VIRT_DINTC_SIZE; + + ret = kvm_device_access(lds->dev_fd, KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL, + KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE, + &lds->msg_addr_base, true, NULL); + if (ret < 0) { + fprintf(stderr, "KVM_DEV_LOONGARCH_DINTC_MSG_ADDR_BASE failed: %s\n", + strerror(ret)); + abort(); + } + + ret = kvm_device_access(lds->dev_fd, KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL, + KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE, + &lds->msg_addr_size, true, NULL); + if (ret < 0) { + fprintf(stderr, "KVM_DEV_LOONGARCH_DINTC_MSG_ADDR_SIZE failed: %s\n", + strerror(ret)); + abort(); + } +} diff --git a/hw/intc/meson.build b/hw/intc/meson.build index a1401cb521..4373f16d0b 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -90,3 +90,5 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extio specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'], if_true: files('loongarch_extioi_kvm.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_DINTC', if_true: files('loongarch_dintc.c')) +specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_DINTC'], + if_true: files('loongarch_dintc_kvm.c')) diff --git a/include/hw/intc/loongarch_dintc.h b/include/hw/intc/loongarch_dintc.h index 1f4f65705a..95a7879e26 100644 --- a/include/hw/intc/loongarch_dintc.h +++ b/include/hw/intc/loongarch_dintc.h @@ -9,8 +9,13 @@ #include "hw/core/sysbus.h" #include "hw/loongarch/virt.h" #include "system/memory.h" +#include "hw/pci-host/ls7a.h" #define NR_VECTORS 256 +#define IRQ_BIT_BASE 5 +#define IRQ_BIT_LEN 8 +#define CPU_BIT_BASE 13 +#define CPU_BIT_LEN 8 #define TYPE_LOONGARCH_DINTC "loongarch_dintc" OBJECT_DECLARE_TYPE(LoongArchDINTCState, LoongArchDINTCClass, LOONGARCH_DINTC) @@ -25,7 +30,10 @@ struct LoongArchDINTCState { SysBusDevice parent_obj; MemoryRegion dintc_mmio; DINTCCore *cpu; + int dev_fd; uint32_t num_cpu; + uint64_t msg_addr_base; + uint64_t msg_addr_size; }; struct LoongArchDINTCClass { @@ -34,3 +42,5 @@ struct LoongArchDINTCClass { DeviceRealize parent_realize; DeviceUnrealize parent_unrealize; }; + +void kvm_dintc_realize(DeviceState *dev, Error **errp); From 11563efaba79377d2004041da514f857c876a151 Mon Sep 17 00:00:00 2001 From: gaosong Date: Thu, 13 Aug 2026 19:10:00 +0800 Subject: [PATCH 419/627] target/loongarch: KVM disable msgint In KVM mode, msgint is disabled by default; please enable it manually. e.g ... -cpu max,msgint=on ... Signed-off-by: gaosong Reviewed-by: Bibo Mao Message-ID: <20260813111000.446232-4-gaosong@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 48e1ad83c9..bd819247c7 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -450,6 +450,9 @@ static void loongarch_max_initfn(Object *obj) loongarch_la464_initfn(obj); cpu->ptw = ON_OFF_AUTO_AUTO; + if (kvm_enabled()){ + cpu->msgint=ON_OFF_AUTO_OFF; + } if (tcg_enabled()) { uint32_t data = cpu->env.cpucfg[2]; data = FIELD_DP32(data, CPUCFG2, HPTW, 1); @@ -464,9 +467,9 @@ static void loongarch_max_initfn(Object *obj) data = cpu->env.cpucfg[3]; data = FIELD_DP32(data, CPUCFG3, DBAR_HINTS, 1); cpu->env.cpucfg[3] = data; + cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1); + cpu->msgint = ON_OFF_AUTO_AUTO; } - cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1); - cpu->msgint = ON_OFF_AUTO_AUTO; } #if defined(CONFIG_KVM) From 215a4fc08f2aafce54c168cf41c64c79187430c1 Mon Sep 17 00:00:00 2001 From: Jan Mercl <0xjnml@gmail.com> Date: Wed, 19 Aug 2026 15:24:22 +0200 Subject: [PATCH 420/627] target/loongarch: check FPE before reading fcc in bceqz/bcnez gen_cz_bc() loads env->cf[cj] without CHECK_FPE, unlike every other translator that touches an fcc register (trans_fcmp.c.inc and trans_fmov.c.inc, for movcf2gr/movgr2cf/movcf2fr/movfr2cf/fsel). A guest that manages the FPU lazily -- Linux clears CSR.EUEN.FPE in lose_fpu() on every context switch -- relies on the next fcc access raising a Floating-Point-Disabled exception so the kernel can restore that task's fcc. Because bceqz and bcnez never raise it, they branch on the condition flag left behind by whichever task last owned the FPU. Real Loongson hardware does raise the exception, so this is TCG-only. It surfaces as Go binaries dying at startup in runtime.check() with "fatal error: float64nan1" -- roughly one process start in a thousand once the guest has more runnable tasks than vCPUs -- and in general as a conditional branch silently taking the wrong path. With four tasks each executing 5M bcnez on a 2-vCPU guest, master mispredicts 89 of 20000000. With this patch, 0 of 100000000 over five runs; a Loongson-3C5000 is likewise 0 of 600000000. CHECK_FPE is defined in trans_farith.c.inc, which translate.c includes before trans_branch.c.inc, so it is already in scope. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4209 Cc: qemu-stable@nongnu.org Signed-off-by: Jan Mercl <0xjnml@gmail.com> Reviewed-by: Richard Henderson Message-ID: <20260819132422.5164-1-0xjnml@gmail.com> Signed-off-by: Song Gao --- target/loongarch/tcg/insn_trans/trans_branch.c.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/loongarch/tcg/insn_trans/trans_branch.c.inc b/target/loongarch/tcg/insn_trans/trans_branch.c.inc index f94c1f37ab..da07778658 100644 --- a/target/loongarch/tcg/insn_trans/trans_branch.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_branch.c.inc @@ -66,6 +66,8 @@ static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) TCGv src1 = tcg_temp_new(); TCGv src2 = tcg_constant_tl(0); + CHECK_FPE; + tcg_gen_ld8u_tl(src1, tcg_env, offsetof(CPULoongArchState, cf[a->cj])); gen_bc(ctx, src1, src2, a->offs, cond); From 184417d4adc97e10d07add5b4129387dadf1e131 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Tue, 18 Aug 2026 14:39:05 +0530 Subject: [PATCH 421/627] MAINTAINERS: elevating myself to be a maintainer for igvm I have worked enough on the igvm to be confident to elevate myself to a maintainer role. Signed-off-by: Ani Sinha Message-ID: <20260818090905.87090-1-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b51f5c3e60..9e0a2a656f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4118,7 +4118,7 @@ F: tests/uefi-test-tools/ IGVM Firmware M: Gerd Hoffmann M: Stefano Garzarella -R: Ani Sinha +M: Ani Sinha S: Maintained F: backends/igvm*.c F: docs/system/igvm.rst From acce06adc0651fe5a19596ac5733142031343c60 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 17 Aug 2026 19:49:56 +0530 Subject: [PATCH 422/627] igvm: store IgvmCfg pointer in QIgvm Store a pointer to IgvmCfg instead of only IgvmFile in QIgvm. Allows to store additional state in the (persistent) IgvmCfg struct. Reviewed-by: Ani Sinha Reviewed-by: Alexander Graf Signed-off-by: Gerd Hoffmann Message-ID: <20260817142010.80693-2-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- backends/igvm.c | 57 ++++++++++++++++++++-------------- include/system/igvm-internal.h | 2 +- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/backends/igvm.c b/backends/igvm.c index 80e87fe602..534032fed8 100644 --- a/backends/igvm.c +++ b/backends/igvm.c @@ -178,7 +178,8 @@ static int qigvm_handler(QIgvm *ctx, IgvmVariableHeaderType raw_type, if (handlers[handler].type != type) { continue; } - header_handle = igvm_get_header(ctx->file, handlers[handler].section, + header_handle = igvm_get_header(ctx->cfg->file, + handlers[handler].section, ctx->current_header_index); if (header_handle < 0) { error_setg( @@ -187,7 +188,7 @@ static int qigvm_handler(QIgvm *ctx, IgvmVariableHeaderType raw_type, (int)header_handle); return -1; } - header_data = igvm_get_buffer(ctx->file, header_handle); + header_data = igvm_get_buffer(ctx->cfg->file, header_handle); if (header_data != NULL) { header_data += sizeof(IGVM_VHS_VARIABLE_HEADER); result = handlers[handler].handler(ctx, header_data, errp); @@ -198,7 +199,7 @@ static int qigvm_handler(QIgvm *ctx, IgvmVariableHeaderType raw_type, header_handle, type); result = -1; } - igvm_free_buffer(ctx->file, header_handle); + igvm_free_buffer(ctx->cfg->file, header_handle); return result; } @@ -344,7 +345,8 @@ static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index, for (page_index = 0; page_index < page_count; page_index++) { data_handle = igvm_get_header_data( - ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, page_index + start_index); + ctx->cfg->file, IGVM_HEADER_SECTION_DIRECTIVE, + page_index + start_index); if (data_handle == IGVMAPI_NO_DATA) { /* No data indicates a zero page */ memset(®ion[page_index * page_size], 0, page_size); @@ -357,7 +359,7 @@ static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index, return -1; } else { zero = false; - data_size = igvm_get_buffer_size(ctx->file, data_handle); + data_size = igvm_get_buffer_size(ctx->cfg->file, data_handle); if (data_size < page_size) { memset(®ion[page_index * page_size], 0, page_size); } else if (data_size > page_size) { @@ -367,14 +369,14 @@ static int qigvm_process_mem_region(QIgvm *ctx, unsigned start_index, page_index + start_index); return -1; } - data = igvm_get_buffer(ctx->file, data_handle); + data = igvm_get_buffer(ctx->cfg->file, data_handle); if (data == NULL) { error_setg(errp, "IGVM: No buffer for handle %d", data_handle); - igvm_free_buffer(ctx->file, data_handle); + igvm_free_buffer(ctx->cfg->file, data_handle); return -1; } memcpy(®ion[page_index * page_size], data, data_size); - igvm_free_buffer(ctx->file, data_handle); + igvm_free_buffer(ctx->cfg->file, data_handle); } } @@ -411,7 +413,8 @@ static int qigvm_process_mem_page(QIgvm *ctx, ctx->region_start = page_data->gpa; ctx->region_start_index = ctx->current_header_index; } else { - if (!qigvm_page_attrs_equal(ctx->file, ctx->current_header_index, + if (!qigvm_page_attrs_equal(ctx->cfg->file, + ctx->current_header_index, page_data, &ctx->region_prev_page_data) || ((ctx->region_prev_page_data.gpa + @@ -474,7 +477,8 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, return 0; } - data_handle = igvm_get_header_data(ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, + data_handle = igvm_get_header_data(ctx->cfg->file, + IGVM_HEADER_SECTION_DIRECTIVE, ctx->current_header_index); if (data_handle < 0) { error_setg(errp, "Invalid VP context in IGVM file. Error code: %X", @@ -482,7 +486,7 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, return -1; } - data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle); + data = (uint8_t *)igvm_get_buffer(ctx->cfg->file, data_handle); if (data == NULL) { error_setg(errp, "IGVM: No buffer for handle %d", data_handle); result = -1; @@ -491,7 +495,8 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, if (ctx->machine_state->cgs) { result = ctx->cgsc->set_guest_state( - vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle), + vp_context->gpa, data, + igvm_get_buffer_size(ctx->cfg->file, data_handle), CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp); } else if (target_arch() == SYS_EMU_TARGET_X86_64) { result = qigvm_x86_set_vp_context(data, vp_context->vp_index, errp); @@ -504,7 +509,7 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, } exit: - igvm_free_buffer(ctx->file, data_handle); + igvm_free_buffer(ctx->cfg->file, data_handle); if (result < 0) { return result; } @@ -863,7 +868,8 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp) uint32_t compatibility_mask_sev_snp = 0; uint32_t compatibility_mask = 0; - header_count = igvm_header_count(ctx->file, IGVM_HEADER_SECTION_PLATFORM); + header_count = igvm_header_count(ctx->cfg->file, + IGVM_HEADER_SECTION_PLATFORM); if (header_count < 0) { error_setg(errp, "Invalid platform header count in IGVM file. Error code: %X", @@ -874,11 +880,11 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp) for (header_index = 0; header_index < (unsigned)header_count; header_index++) { IgvmVariableHeaderType typ = igvm_get_header_type( - ctx->file, IGVM_HEADER_SECTION_PLATFORM, header_index); + ctx->cfg->file, IGVM_HEADER_SECTION_PLATFORM, header_index); typ = igvm_vht_type(typ); if (typ == IGVM_VHT_SUPPORTED_PLATFORM) { header_handle = igvm_get_header( - ctx->file, IGVM_HEADER_SECTION_PLATFORM, header_index); + ctx->cfg->file, IGVM_HEADER_SECTION_PLATFORM, header_index); if (header_handle < 0) { error_setg(errp, "Invalid platform header in IGVM file. " @@ -887,11 +893,11 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp) return -1; } platform = - (IGVM_VHS_SUPPORTED_PLATFORM *)(igvm_get_buffer(ctx->file, + (IGVM_VHS_SUPPORTED_PLATFORM *)(igvm_get_buffer(ctx->cfg->file, header_handle)); if (platform == NULL) { error_setg(errp, "IGVM: No buffer for handle %d", header_handle); - igvm_free_buffer(ctx->file, header_handle); + igvm_free_buffer(ctx->cfg->file, header_handle); return -1; } @@ -922,7 +928,7 @@ static int qigvm_supported_platform_compat_mask(QIgvm *ctx, Error **errp) } else if (platform->platform_type == IGVM_PLATFORM_TYPE_NATIVE) { compatibility_mask = platform->compatibility_mask; } - igvm_free_buffer(ctx->file, header_handle); + igvm_free_buffer(ctx->cfg->file, header_handle); } } /* Choose the strongest supported isolation technology */ @@ -999,7 +1005,7 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state, error_setg(errp, "No IGVM file loaded."); return -1; } - ctx.file = cfg->file; + ctx.cfg = cfg; trace_igvm_process_file(cfg->file, onlyVpContext); ctx.machine_state = machine_state; @@ -1021,7 +1027,8 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state, goto cleanup; } - header_count = igvm_header_count(ctx.file, IGVM_HEADER_SECTION_DIRECTIVE); + header_count = igvm_header_count(ctx.cfg->file, + IGVM_HEADER_SECTION_DIRECTIVE); if (header_count <= 0) { error_setg( errp, "Invalid directive header count in IGVM file. Error code: %X", @@ -1035,7 +1042,8 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state, ctx.current_header_index < (unsigned)header_count; ctx.current_header_index++) { IgvmVariableHeaderType raw_type = igvm_get_header_type( - ctx.file, IGVM_HEADER_SECTION_DIRECTIVE, ctx.current_header_index); + ctx.cfg->file, IGVM_HEADER_SECTION_DIRECTIVE, + ctx.current_header_index); if (!onlyVpContext || igvm_vht_type(raw_type) == IGVM_VHT_VP_CONTEXT) { if (qigvm_handler(&ctx, raw_type, errp) < 0) { goto cleanup_parameters; @@ -1053,7 +1061,7 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state, } header_count = - igvm_header_count(ctx.file, IGVM_HEADER_SECTION_INITIALIZATION); + igvm_header_count(ctx.cfg->file, IGVM_HEADER_SECTION_INITIALIZATION); if (header_count < 0) { error_setg( errp, @@ -1066,7 +1074,8 @@ int qigvm_process_file(IgvmCfg *cfg, MachineState *machine_state, ctx.current_header_index < (unsigned)header_count; ctx.current_header_index++) { IgvmVariableHeaderType type = - igvm_get_header_type(ctx.file, IGVM_HEADER_SECTION_INITIALIZATION, + igvm_get_header_type(ctx.cfg->file, + IGVM_HEADER_SECTION_INITIALIZATION, ctx.current_header_index); if (qigvm_handler(&ctx, type, errp) < 0) { goto cleanup_parameters; diff --git a/include/system/igvm-internal.h b/include/system/igvm-internal.h index 7eb3792ed8..b5720fae0c 100644 --- a/include/system/igvm-internal.h +++ b/include/system/igvm-internal.h @@ -43,7 +43,7 @@ typedef struct QIgvmParameterData { * file. */ struct QIgvm { - IgvmHandle file; + IgvmCfg *cfg; MachineState *machine_state; ConfidentialGuestSupportClass *cgsc; uint32_t compatibility_mask; From 14eb43761dc2d732f8f86b051f31323f1cf1fd80 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 17 Aug 2026 19:49:57 +0530 Subject: [PATCH 423/627] igvm: track memory regions Memory regions added by the current IGVM needs to be tracked so that they can be freed when a new IGVM is loaded. Reviewed-by: Ani Sinha Reviewed-by: Alexander Graf Signed-off-by: Gerd Hoffmann Message-ID: <20260817142010.80693-3-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- backends/igvm-cfg.c | 1 + backends/igvm.c | 20 ++++++++++++-------- include/system/igvm-internal.h | 6 ++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/backends/igvm-cfg.c b/backends/igvm-cfg.c index e1f09855f6..38438a7b1e 100644 --- a/backends/igvm-cfg.c +++ b/backends/igvm-cfg.c @@ -65,6 +65,7 @@ static void igvm_complete(UserCreatable *uc, Error **errp) IgvmCfg *igvm = IGVM_CFG(uc); igvm->file = qigvm_file_init(igvm->filename, errp); + QTAILQ_INIT(&igvm->memory_regions); } OBJECT_DEFINE_TYPE_WITH_INTERFACES(IgvmCfg, igvm_cfg, IGVM_CFG, OBJECT, diff --git a/backends/igvm.c b/backends/igvm.c index 534032fed8..9e7c90d386 100644 --- a/backends/igvm.c +++ b/backends/igvm.c @@ -220,7 +220,7 @@ static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size, int region_identifier, Error **errp) { ERRP_GUARD(); - MemoryRegion *igvm_pages = NULL; + IgvmMemoryRegion *imr = NULL; Int128 gpa_region_size; MemoryRegionSection mrs = memory_region_find(get_system_memory(), addr, size); @@ -254,23 +254,27 @@ static void *qigvm_prepare_memory(QIgvm *ctx, uint64_t addr, uint64_t size, */ g_autofree char *region_name = g_strdup_printf("igvm.%X", region_identifier); - igvm_pages = g_new0(MemoryRegion, 1); + imr = g_new0(IgvmMemoryRegion, 1); + imr->mr = g_new0(MemoryRegion, 1); if (ctx->machine_state->cgs && ctx->machine_state->cgs->require_guest_memfd) { - if (!memory_region_init_ram_guest_memfd(igvm_pages, NULL, + if (!memory_region_init_ram_guest_memfd(imr->mr, NULL, region_name, size, errp)) { - g_free(igvm_pages); + g_free(imr->mr); + g_free(imr); return NULL; } } else { - if (!memory_region_init_ram(igvm_pages, NULL, region_name, size, + if (!memory_region_init_ram(imr->mr, NULL, region_name, size, errp)) { - g_free(igvm_pages); + g_free(imr->mr); + g_free(imr); return NULL; } } - memory_region_add_subregion(get_system_memory(), addr, igvm_pages); - return memory_region_get_ram_ptr(igvm_pages); + memory_region_add_subregion(get_system_memory(), addr, imr->mr); + QTAILQ_INSERT_TAIL(&ctx->cfg->memory_regions, imr, next); + return memory_region_get_ram_ptr(imr->mr); } } diff --git a/include/system/igvm-internal.h b/include/system/igvm-internal.h index b5720fae0c..9e9fa1d9af 100644 --- a/include/system/igvm-internal.h +++ b/include/system/igvm-internal.h @@ -18,6 +18,11 @@ #include "system/confidential-guest-support.h" #include +typedef struct IgvmMemoryRegion { + QTAILQ_ENTRY(IgvmMemoryRegion) next; + MemoryRegion *mr; +} IgvmMemoryRegion; + struct IgvmCfg { Object parent_obj; @@ -29,6 +34,7 @@ struct IgvmCfg { char *filename; IgvmHandle file; ResettableState reset_state; + QTAILQ_HEAD(, IgvmMemoryRegion) memory_regions; }; typedef struct QIgvmParameterData { From 94cfb5afe77858536265c957f47d10d85d75908c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 17 Aug 2026 19:49:58 +0530 Subject: [PATCH 424/627] igvm: cleanup memory regions This change cleans up existing memory regions that were created by the current IGVM. The cleanup would be necessary when a new IGVM is loaded. This cleanup function is called in a subsequent patch. Reviewed-by: Alexander Graf Tested-by: Ani Sinha Signed-off-by: Gerd Hoffmann Message-ID: <20260817142010.80693-4-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- backends/igvm-cfg.c | 2 ++ backends/igvm.c | 19 +++++++++++++++++++ include/system/igvm.h | 1 + 3 files changed, 22 insertions(+) diff --git a/backends/igvm-cfg.c b/backends/igvm-cfg.c index 38438a7b1e..935ba54f54 100644 --- a/backends/igvm-cfg.c +++ b/backends/igvm-cfg.c @@ -52,6 +52,8 @@ static void igvm_reset_hold(Object *obj, ResetType type) trace_igvm_reset_hold(type); + /* cleanup existing memory regions first */ + qigvm_cleanup_memory(igvm); qigvm_process_file(igvm, ms, false, &error_fatal); } diff --git a/backends/igvm.c b/backends/igvm.c index 9e7c90d386..9b101c8182 100644 --- a/backends/igvm.c +++ b/backends/igvm.c @@ -14,6 +14,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/target-info-qapi.h" +#include "migration/vmstate.h" #include "system/igvm.h" #include "system/igvm-cfg.h" #include "system/igvm-internal.h" @@ -1109,3 +1110,21 @@ cleanup_parameters: cleanup: return retval; } + +/* + * cleanup any memory regions created by qigvm_prepare_memory() + */ +void qigvm_cleanup_memory(IgvmCfg *cfg) +{ + IgvmMemoryRegion *imr, *tmp; + + QTAILQ_FOREACH_SAFE(imr, &cfg->memory_regions, next, tmp) + { + memory_region_del_subregion(get_system_memory(), imr->mr); + vmstate_unregister_ram(imr->mr, NULL); + QTAILQ_REMOVE(&cfg->memory_regions, imr, next); + /* this triggers MemoryRegion cleanup */ + object_unparent(OBJECT(imr->mr)); + g_free(imr); + } +} diff --git a/include/system/igvm.h b/include/system/igvm.h index 64d3542311..e219f1a4ed 100644 --- a/include/system/igvm.h +++ b/include/system/igvm.h @@ -20,6 +20,7 @@ typedef struct QIgvm QIgvm; int qigvm_process_file(IgvmCfg *igvm, MachineState *machine_state, bool onlyVpContext, Error **errp); +void qigvm_cleanup_memory(IgvmCfg *igvm); /* x86 native */ int qigvm_x86_get_mem_map_entry(int index, From 0102503dc58d5f34e49f4d9cb7020271aa90b149 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:49:59 +0530 Subject: [PATCH 425/627] system/memory: add a tracepoint for memory_region_finalize cosmetic: add a tracepoint to track when memory regions are getting freed. Useful for debugging and tracking all freed memory regions. Reviewed-by: Peter Xu Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-5-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- system/memory.c | 1 + system/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/system/memory.c b/system/memory.c index da710bbade..9760721e45 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1691,6 +1691,7 @@ static void memory_region_finalize(Object *obj) { MemoryRegion *mr = MEMORY_REGION(obj); + trace_memory_region_finalize(mr->name); /* * Each memory region (that can be freed) must have an owner, and it * always has the same lifecycle of its owner. It means when reaching diff --git a/system/trace-events b/system/trace-events index d483b31419..38ad0be8a9 100644 --- a/system/trace-events +++ b/system/trace-events @@ -25,6 +25,7 @@ flatview_new(void *view, void *root) "%p (root %p)" flatview_destroy(void *view, void *root) "%p (root %p)" flatview_destroy_rcu(void *view, void *root) "%p (root %p)" global_dirty_changed(unsigned int bitmask) "bitmask 0x%"PRIx32 +memory_region_finalize(const char* name) "mr %s" # physmem.c address_space_map(void *as, uint64_t addr, uint64_t len, bool is_write, uint32_t attrs) "as:%p addr 0x%"PRIx64":%"PRIx64" write:%d attrs:0x%x" From 68e54556e731432dd5ceff3daf5889e2096d42ae Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:50:00 +0530 Subject: [PATCH 426/627] backends/igvm: add a tracepoint for qigvm_cleanup_memory Useful for debugging memory region cleanups. Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-6-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- backends/igvm.c | 1 + backends/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/backends/igvm.c b/backends/igvm.c index 9b101c8182..7b7bdc72b7 100644 --- a/backends/igvm.c +++ b/backends/igvm.c @@ -1120,6 +1120,7 @@ void qigvm_cleanup_memory(IgvmCfg *cfg) QTAILQ_FOREACH_SAFE(imr, &cfg->memory_regions, next, tmp) { + trace_qigvm_cleanup_memory(imr->mr->name); memory_region_del_subregion(get_system_memory(), imr->mr); vmstate_unregister_ram(imr->mr, NULL); QTAILQ_REMOVE(&cfg->memory_regions, imr, next); diff --git a/backends/trace-events b/backends/trace-events index 009a25b0be..9b7b9b7d68 100644 --- a/backends/trace-events +++ b/backends/trace-events @@ -33,3 +33,4 @@ igvm_reset_hold(int type) "type=%u" igvm_reset_exit(int type) "type=%u" igvm_file_loaded(const char *fn, int32_t handle) "fn=%s, handle=0x%x" igvm_process_file(int32_t handle, bool context_only) "handle=0x%x context-only=%d" +qigvm_cleanup_memory(const char* name) "freeing mr %s" From b23f6d5294cc2b3bcf99c4c28b5b58b8ae5bc1f1 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Wed, 19 Aug 2026 09:41:05 +0530 Subject: [PATCH 427/627] hw/misc/vmlaunchupdate: add api header Add a separate header file for guest usable api definitions. CC: Alex Graf CC: Gerd Hoffman Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260819041105.110625-1-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- .../standard-headers/misc/vmlaunchupdate.h | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 include/standard-headers/misc/vmlaunchupdate.h diff --git a/include/standard-headers/misc/vmlaunchupdate.h b/include/standard-headers/misc/vmlaunchupdate.h new file mode 100644 index 0000000000..7f8382a765 --- /dev/null +++ b/include/standard-headers/misc/vmlaunchupdate.h @@ -0,0 +1,102 @@ +/* + * Guest driven VM launch state update device via IGVM. + * The definitions in this header defines the API for the hypervisor interface. + * For details and specification, please look at docs/specs/vmlaunchupdate.rst. + * + * Copyright (C) 2026 Red Hat, Inc. + * + * Authors: Ani Sinha + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ +#ifndef VMLAUNCHUPDATE_API_H +#define VMLAUNCHUPDATE_API_H + +/* fw-cfg file definition */ +#define FILE_VMLAUNCHUPDATE "etc/vmlaunchupdate" + +/* version */ +#define VM_LAUNCHUPDATE_VERSION 0x01 + +/* format bits, used by both 'capabilities' and 'control' */ + +/* igvm */ +#define VM_LAUNCHUPDATE_FORMAT_IGVM (1ULL << 32) + +/* 'control' field bits */ + +/* disable vmlaunchupdate interface */ +#define VM_LAUNCHUPDATE_CTL_DISABLE (1 << 0) +/* revert to the original host provided igvm */ +#define VM_LAUNCHUPDATE_CTL_HOST_IGVM (1 << 1) + +/* The combination of the above two ctl interfaces work as + * follows: + * + * A) CTL_HOST_IGVM=off CTL_DISABLE=off + * + * Supplied IGVM file replaces the firmware permanently. Updating the + * firmware again is possible. + * + * B) CTL_HOST_IGVM=off CTL_DISABLE=on + * + * Supplied IGVM file replaces the firmware permanently. Updating the + * firmware again is not possible. + * + * C) CTL_HOST_IGVM=on CTL_DISABLE=off + * + * Supplied IGVM file replaces the firmware for one reset. Resetting + * again will switch back to the original firmware. Updating the + * firmware again is possible. + * + * D) CTL_HOST_IGVM=on CTL_DISABLE=on + * + * Supplied IGVM file replaces the firmware for one reset. Resetting + * again will switch back to the original firmware. Updating the + * firmware again is NOT possible. + * + */ + +/* status code */ +enum VMLaunchUpdateStatus { + VM_LAUNCHUPDATE_SUCCESS = 0, + VM_LAUNCHUPDATE_LOAD_FAIL = 1, + VM_LAUNCHUPDATE_NOT_IGVM_INIT = 2, +}; + +typedef struct QEMU_PACKED { + /* api version */ + uint16_t version; + + /* + * The guest can read this in order to determine if loading new IGVM + * succeeded. + */ + uint16_t status; + + uint32_t _padding; + + /* VMM capabilities, read-only. */ + uint64_t capabilities; + /* control bits, see VMFWUPDATE_CTL_* */ + uint64_t control; + + /* + * address and size of the IGVM image. Will be cleared when + * the write completes successfully and IGVM file is correctly parsed. + */ + uint64_t fw_image_addr; + uint64_t fw_image_size; + + /* + * address + size of opaque blob. The guest can use this to pass on + * information, for example which memory region the linux kernel has been + * loaded to. writable, will be kept intact on firmware update. + */ + uint64_t opaque_addr; + uint64_t opaque_size; + +} VMLaunchUpdate; + +#endif From 30688c02a76e50e4da779a99a7316c49cbdd840e Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:50:02 +0530 Subject: [PATCH 428/627] hw/misc/vmlaunchupdate: Introduce hypervisor fw-cfg interface support VM launch update is a mechanism where the virtual machines can use IGVM file bundle to boot into a trusted execution environment without having to depend on a untrusted party to provide the IGVM bundle or firmware image. This is particularly useful for confidential virtual machines that are deployed in the cloud where the tenant and the cloud provider are two different entities. In this scenario, virtual machines can bring their own trusted IGVM file containing a trusted firmware image bundled as a part of their filesystem and then use this hypervisor interface to update to a trusted and deterministic boot state. This also allows the guests to have a consistent measurements on the firmware image. Currently, this mechanism only works if the VM was started with IGVM in the first place. This change introduces support for the fw-cfg based hypervisor interface and the corresponding device. The interface is made generic enough so that guests are free to use their own ABI to pass required information between initial and trusted execution contexts (where they are running their own trusted boot state) without the hypervisor getting involved in between. Currently, this device is only supported for x86_64 machines. Presence of IGVM host libraries is also required for parsing IGVM files. Hence, the device cannot be initialized for other machine types or hosts where IGVM support is not present. Trying to initialize it for arm for example will lead to failure: $ ./qemu-system-arm -device vm-launch-update -machine virt qemu-system-arm: -device vm-launch-update: This machine does not support vm-launch-update device A document detailing the specification is added in a subsequent patch. Please see docs/specs/vmlaunchupdate.rst. Functional and qtests are added in a subsequent patch. CC: Alex Graf CC: Gerd Hoffman Reviewed-by: Gerd Hoffmann Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-8-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- hw/misc/meson.build | 3 + hw/misc/trace-events | 6 + hw/misc/vmlaunchupdate.c | 333 +++++++++++++++++++++++++++++++ include/hw/misc/vmlaunchupdate.h | 38 ++++ 4 files changed, 380 insertions(+) create mode 100644 hw/misc/vmlaunchupdate.c create mode 100644 include/hw/misc/vmlaunchupdate.h diff --git a/hw/misc/meson.build b/hw/misc/meson.build index e86d9ad6b3..858ca845a2 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -164,6 +164,9 @@ specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) specific_ss.add(when: 'CONFIG_RISCV_MIPS_CMGCR', if_true: files('riscv_cmgcr.c')) specific_ss.add(when: 'CONFIG_RISCV_MIPS_CPC', if_true: files('riscv_cpc.c')) +if igvm.found() + specific_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmlaunchupdate.c')) +endif system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index c9a868b3ef..2d6d2238c5 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -442,3 +442,9 @@ iommu_testdev_dma_read(uint64_t gva, uint32_t len) "gva=0x%" PRIx64 " len=%u" iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=0x%x actual=0x%x" iommu_testdev_dma_result(uint32_t result) "DMA completed result=0x%x" iommu_testdev_dma_armed(bool armed) "armed=%d" + +# vmlaunchupdate.c +launch_update_write(void) "" +vmlaunch_reset_enter(void) "" +vm_launchupdate_finalize(void) "" +restore_host_x86_igvm(void) "" diff --git a/hw/misc/vmlaunchupdate.c b/hw/misc/vmlaunchupdate.c new file mode 100644 index 0000000000..afa2d278ae --- /dev/null +++ b/hw/misc/vmlaunchupdate.c @@ -0,0 +1,333 @@ +/* + * Guest driven VM launch component update (using IGVM) device + * For details and specification, please look at docs/specs/vmlaunchupdate.rst. + * + * Copyright (C) 2026 Red Hat, Inc. + * + * Authors: Ani Sinha + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "system/physmem.h" +#include "system/reset.h" +#include "qemu/target-info-qapi.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/core/qdev-properties.h" +#include "hw/i386/pc.h" +#include "exec/cpu-common.h" +#include "hw/misc/vmlaunchupdate.h" +#include "system/igvm.h" +#include "system/igvm-internal.h" +#include "qemu/error-report.h" +#include "trace.h" + +/* returns NULL unless there is exactly one device */ +static VMLaunchUpdateState *vm_launchupdate_find(void) +{ + Object *o = object_resolve_path_type("", TYPE_VMLAUNCHUPDATE, NULL); + + return o ? VMLAUNCHUPDATE(o) : NULL; +} + +static bool vmlaunchupdate_supported(void) +{ + return target_arch() == SYS_EMU_TARGET_X86_64; +} + +static void init_vm_launch_update(VMLaunchUpdateState *s) +{ + s->launch_update.capabilities = VM_LAUNCHUPDATE_FORMAT_IGVM; + s->launch_update.control = 0; + + if (s->disabled) { + s->launch_update.control |= VM_LAUNCHUPDATE_CTL_DISABLE; + } + + s->launch_update.version = VM_LAUNCHUPDATE_VERSION; + return; +} + +static void clear_init_vm_launch_update(VMLaunchUpdateState *s) +{ + memset(&s->launch_update, 0, sizeof(s->launch_update)); + init_vm_launch_update(s); +} + +static bool no_igvmcfg(X86MachineState *x86m) +{ + IgvmCfg *igvmc; + + if (!x86m) { + return true; + } + + igvmc = x86m->igvm; + + if (!igvmc) { + /* The VM was not started with an IGVM, bail */ + info_report("guest was not initially started with IGVM, " + "not changing launch state."); + return true; + } + return false; +} + +static int process_x86_igvm(VMLaunchUpdateState *s, + uint64_t fw_image_addr, uint64_t fw_image_size) +{ + X86MachineState *x86machine = X86_MACHINE(qdev_get_machine()); + IgvmCfg *igvmc = x86machine->igvm; + IgvmHandle igvm; + void *image_addr_ptr; + hwaddr len; + + if (no_igvmcfg(x86machine)) { + return -2; + } + + if (!fw_image_addr || !fw_image_size) { + return -1; + } + + len = (hwaddr) fw_image_size; + image_addr_ptr = physical_memory_map((hwaddr) fw_image_addr, + (hwaddr *) &len, 0); + + if (!image_addr_ptr || (len < fw_image_size)) { + warn_report("vmlaunchupdate: Invalid guest addresses."); + goto err; + } + + igvm = igvm_new_from_binary(image_addr_ptr, fw_image_size); + if (igvm < 0) { + warn_report("vmlaunchupdate: Unable to parse IGVM file %" + PRIx64 ": %" PRIx64, fw_image_addr, fw_image_size); + goto err; + } + + /* free previous file context */ + if (igvmc->file >= 0) { + igvm_free(igvmc->file); + } + /* set new context */ + igvmc->file = igvm; + + physical_memory_unmap(image_addr_ptr, len, 0, 0); + info_report("vmlaunchupdate: new IGVM context set."); + + return 0; + err: + if (image_addr_ptr) { + physical_memory_unmap(image_addr_ptr, len, 0, 0); + } + return -1; +} + +static void restore_host_x86_igvm(void) +{ + X86MachineState *x86machine = X86_MACHINE(qdev_get_machine()); + IgvmCfg *igvmc = x86machine->igvm; + Error *errp = NULL; + + if (no_igvmcfg(x86machine)) { + return; + } + + /* free previous file context */ + if (igvmc->file >= 0) { + igvm_free(igvmc->file); + } + + info_report("restoring original host IGVM: %s", igvmc->filename); + igvmc->file = qigvm_file_init(igvmc->filename, &errp); + assert(!errp); + + info_report("vmlaunchupdate: host IGVM context set."); + + trace_restore_host_x86_igvm(); + + return; +} + +static bool fw_address_cleared(VMLaunchUpdateState *s) +{ + return !s->launch_update.fw_image_addr && + !s->launch_update.fw_image_size; +} + +static void launch_update_write(void *dev, off_t offset, size_t len) +{ + VMLaunchUpdateState *s = VMLAUNCHUPDATE(dev); + uint64_t addr; + uint64_t size; + int rc; + + s->launch_update.status = VM_LAUNCHUPDATE_SUCCESS; + + if (s->disabled) { + goto end; + } + + if (s->launch_update.control & VM_LAUNCHUPDATE_CTL_DISABLE) { + s->disabled = true; + goto end; + } + + if (fw_address_cleared(s) && + (s->launch_update.control & VM_LAUNCHUPDATE_CTL_HOST_IGVM)) { + /* restore host IGVM on immediate next reset */ + s->host_igvm_on_reset = true; + goto end; + } + + if (!(s->launch_update.control & VM_LAUNCHUPDATE_FORMAT_IGVM) && + !fw_address_cleared(s)) { + /* at least one address provided but the format is not IGVM */ + s->launch_update.status = VM_LAUNCHUPDATE_LOAD_FAIL; + goto end; + } + + /* process guest provided IGVM image */ + if (s->launch_update.control & VM_LAUNCHUPDATE_FORMAT_IGVM) { + if (target_arch() == SYS_EMU_TARGET_X86_64) { + addr = le64_to_cpu(s->launch_update.fw_image_addr); + size = le64_to_cpu(s->launch_update.fw_image_size); + rc = process_x86_igvm(s, addr, size); + if (rc < 0) { + switch (rc) { + case -2: + s->launch_update.status = VM_LAUNCHUPDATE_NOT_IGVM_INIT; + break; + default: + s->launch_update.status = VM_LAUNCHUPDATE_LOAD_FAIL; + } + goto end; + } + } + /* process other machines here when support is added */ + } + + /* clear the addresses */ + s->launch_update.fw_image_addr = 0x0; + s->launch_update.fw_image_size = 0x0; + + end: + trace_launch_update_write(); + return; +} + +static void launch_update_select(void *dev) +{ + VMLaunchUpdateState *s = VMLAUNCHUPDATE(dev); + init_vm_launch_update(s); +} + +static void vmlaunch_reset_enter(Object *obj, ResetType type) +{ + VMLaunchUpdateState *s = VMLAUNCHUPDATE(obj); + + if (target_arch() != SYS_EMU_TARGET_X86_64) { + return; + } + + if (s->host_igvm_on_reset) { + restore_host_x86_igvm(); + s->host_igvm_on_reset = false; + /* restoring host igvm enables the interface again */ + s->disabled = false; + /* clear the host IGVM ctrl bit */ + s->launch_update.control &= ~VM_LAUNCHUPDATE_CTL_HOST_IGVM; + } + + if ((s->launch_update.control & VM_LAUNCHUPDATE_CTL_HOST_IGVM) && + (s->launch_update.status == VM_LAUNCHUPDATE_SUCCESS)) { + info_report("vmlaunchupdate: next reset will use host igvm"); + s->host_igvm_on_reset = true; + } + + trace_vmlaunch_reset_enter(); +} + +static ResettableState *vmlaunch_reset_state(Object *obj) +{ + VMLaunchUpdateState *s = VMLAUNCHUPDATE(obj); + + return &s->reset_state; +} + +static void vm_launchupdate_realize(DeviceState *dev, Error **errp) +{ + VMLaunchUpdateState *s = VMLAUNCHUPDATE(dev); + FWCfgState *fw_cfg = fw_cfg_find(); + + /* multiple devices are not supported */ + if (!vm_launchupdate_find()) { + error_setg(errp, "at most one %s device is permitted", + TYPE_VMLAUNCHUPDATE); + return; + } + + /* if current machine is not supported, do not initialize */ + if (!vmlaunchupdate_supported()) { + error_setg(errp, + "This machine does not support vm-launch-update device"); + return; + } + + /* fw_cfg with DMA support is necessary to support this device */ + if (!fw_cfg || !fw_cfg_dma_enabled(fw_cfg)) { + error_setg(errp, "%s device requires fw_cfg", + TYPE_VMLAUNCHUPDATE); + return; + } + + fw_cfg_add_file_callback(fw_cfg, FILE_VMLAUNCHUPDATE, + launch_update_select, launch_update_write, s, + &s->launch_update, + sizeof(s->launch_update), + false); + + clear_init_vm_launch_update(s); + /* + * This device requires to register a global reset because it is + * not plugged to a bus (which, as its QOM parent, would reset it). + */ + qemu_register_resettable(OBJECT(s)); +} + +static void vm_launchupdate_finalize(Object *obj) +{ + qemu_unregister_resettable(obj); + trace_vm_launchupdate_finalize(); +} + +static void vmlaunchupdate_device_class_init(ObjectClass *klass, + const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + /* we are not interested in migration - so no need to populate dc->vmsd */ + dc->desc = "VM launch state update device"; + dc->realize = vm_launchupdate_realize; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + rc->phases.enter = vmlaunch_reset_enter; + rc->get_state = vmlaunch_reset_state; +} + +static const TypeInfo vmlaunchupdate_device_types[] = { + { + .name = TYPE_VMLAUNCHUPDATE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VMLaunchUpdateState), + .class_init = vmlaunchupdate_device_class_init, + .instance_finalize = vm_launchupdate_finalize, + }, +}; + +DEFINE_TYPES(vmlaunchupdate_device_types) diff --git a/include/hw/misc/vmlaunchupdate.h b/include/hw/misc/vmlaunchupdate.h new file mode 100644 index 0000000000..02f96cebdc --- /dev/null +++ b/include/hw/misc/vmlaunchupdate.h @@ -0,0 +1,38 @@ +/* + * Guest driven VM launch state update device via IGVM. + * For details and specification, please look at docs/specs/vmlaunchupdate.rst. + * + * Copyright (C) 2026 Red Hat, Inc. + * + * Authors: Ani Sinha + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ +#ifndef VMLAUNCHUPDATE_H +#define VMLAUNCHUPDATE_H + +#include "hw/core/qdev.h" +#include "qom/object.h" +#include "qemu/units.h" +#include "system/igvm-cfg.h" +#include "standard-headers/misc/vmlaunchupdate.h" + +#define TYPE_VMLAUNCHUPDATE "vm-launch-update" + +typedef struct VMLaunchUpdateState { + DeviceState parent_obj; + VMLaunchUpdate launch_update; + bool disabled; + bool host_igvm_on_reset; + ResettableState reset_state; +} VMLaunchUpdateState; + + +typedef struct VMLaunchUpdateStateClass { + ObjectClass parent_class; +} VMLaunchUpdateStateClass; + +OBJECT_DECLARE_SIMPLE_TYPE(VMLaunchUpdateState, VMLAUNCHUPDATE); + +#endif From 76c16b3c37e705218844264e48b3657d14529d23 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:50:03 +0530 Subject: [PATCH 429/627] docs/spec: Add a specification document for vm-launch-update device This change adds a specification document and expanation for the vm-launch-update device. CC: Alex Graf CC: Gerd Hoffman Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-9-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- docs/specs/index.rst | 1 + docs/specs/vmlaunchupdate.rst | 198 ++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 docs/specs/vmlaunchupdate.rst diff --git a/docs/specs/index.rst b/docs/specs/index.rst index b7909a108a..3cdf242661 100644 --- a/docs/specs/index.rst +++ b/docs/specs/index.rst @@ -34,6 +34,7 @@ guest hardware that is specific to QEMU. virt-ctlr vmcoreinfo vmgenid + vmlaunchupdate rapl-msr rocker riscv-iommu diff --git a/docs/specs/vmlaunchupdate.rst b/docs/specs/vmlaunchupdate.rst new file mode 100644 index 0000000000..2f1e95afbf --- /dev/null +++ b/docs/specs/vmlaunchupdate.rst @@ -0,0 +1,198 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +VMLAUNCHUPDATE Interface Specification +###################################### + +Introduction +************ + +``VmLaunchUpdate`` is an extension to ``fw-cfg`` that allows guests to replace +boot state in their virtual machine using IGVM file container. Through a combination +of this ``fw-cfg`` hypervisor interface, an IGVM file containing specific directives +and with hypervisor stack knowledge, guests can deterministically replace the launch +state for guests. This is useful for environments like SEV-SNP where the +launch payload becomes the launch digest. Guests can use vm-launch-update device to +provide a measured, full guest payload (BIOS image, kernel, initramfs, kernel +command line) to the virtual machine which enables them to easily reason about +integrity of the resulting system. +It is also to be noted that this mechanism currently works only when the guest was +already started with an IGVM file defining its initial launch state. Subsequent +guest resets will use the launch state as defined in the guest provided IGVM file, +not the file with which the guest was initially started. If the guest was not started +with IGVM, writing a new bundle through the ``fw-cfg`` interface has no effect. + +For more information, please see the `KVM Forum 2024 presentation `__ +about this work. + + +.. _KVMFORUM: https://www.youtube.com/watch?v=VCMBxU6tAto + +Base Requirements +***************** + +#. **fw-cfg**: + The target system must provide a ``fw-cfg`` interface. For x86 based + environments, this ``fw-cfg`` interface must be accessible through PIO ports + 0x510 and 0x511. The ``fw-cfg`` interface does not need to be announced as part + of system device tables such as DSDT. The ``fw-cfg`` interface must support the + DMA interface. It may only support the DMA interface for write operations. + +#. **IGVM support**: + The hypervisor must provide support for parsing and executing the IGVM file bundle. + +#. **Confidential guests**: + For confidential guests, the hypervisor must support guest reset. Otherwise, the new + boot state provided through IGVM will not be applied. + +The Fw-cfg File +*************** + +Guests drive vmlaunchupdate through special ``fw-cfg`` files that control its flow +followed by a standard system reset operation. When the ``vm-launch-update`` device +is available, it provides the following ``fw-cfg`` file: + +* ``etc/vmlaunchupdate`` - It exposes a structure of the following type, all in + little-endian format: + +.. code-block:: c + :linenos: + + typedef struct { + uint16_t version; + uint16_t status; + + uint32_t _padding; + + uint64_t capabilities; + uint64_t control; + + uint64_t fw_image_addr; + uint64_t fw_image_size; + + uint64_t opaque_addr; + uint64_t opaque_size; + + } VMLaunchUpdate; + + +Currently, the ``version`` number (line 2 above) is initialized to the value ``1``. +Only IGVM files are supported at present. The ``capabilities`` (line 7) and ``control`` (line 8) both support +the following single value: + +* ``VM_LAUNCHUPDATE_FORMAT_IGVM`` + + This value is used by the hypervisor to indicate that only IGVM container files are supported. + This is set as a part of ``capabilities`` parameter (line 7) in the above structure. This same value + is passed by the guest to the hypervisor in the ``control`` parameter (line 8) in the above structure + to indicate that the guest passed IGVM file in memory to the hypervisor. The starting guest physical + address of the IGVM file in memory is specified in ``fw_image_addr`` and it's length is specified in + ``fw_image_size`` by the guest. If any other value is passed by the guest in the ``control`` parameter, + the write is ignored by the hypervisor. + +Following ``control`` parameters are supported: + +* ``VM_LAUNCHUPDATE_CTL_DISABLE`` + + This value is set in the ``control`` parameter by the guest in order to disable this ``fw-cfg`` + hypervisor interface from further updating the guest launch state with a new IGVM file. + +* ``VM_LAUNCHUPDATE_CTL_HOST_IGVM`` + + This value is set in the ``control`` parameter by the guest in order to send request to the + hypervisor to initialize the guest using the original host provided IGVM file. + It is useful if the guest wanted to update the UKIs present in the ESP and upon + reset, use one of the updated UKIs present there. If the guest passed addresses in memory + where its own IGVM file is loaded (see below) while also setting this control value, the next + reset will load the guest provided IGVM file and a subsequent second reset will restore the original + host IGVM. If the guest did not provide any addresses of its own IGVM (the address values are + cleared) while setting this control parameter, the immediate next guest reset will load the + original host provided IGVM file. + + The combination of the above two ctl interfaces work as + follows: + + A) ``CTL_HOST_IGVM`` = off ``CTL_DISABLE`` = off + + Supplied IGVM file replaces the firmware permanently. Updating the + firmware again is possible. + + B) ``CTL_HOST_IGVM`` = off ``CTL_DISABLE`` = on + + Supplied IGVM file replaces the firmware permanently. Updating the + firmware again is not possible. + + C) ``CTL_HOST_IGVM`` = on ``CTL_DISABLE`` = off + + Supplied IGVM file replaces the firmware for one reset. Resetting + again will switch back to the original firmware. Updating the + firmware again is possible. + + D) ``CTL_HOST_IGVM`` = on ``CTL_DISABLE`` = on + + Supplied IGVM file replaces the firmware for one reset. Resetting + again will switch back to the original firmware. Updating the + firmware again is NOT possible. + +``fw_image_addr`` (line 10) is the base guest physical address of the guest memory where the IGVM file of size +``fw_image_size`` (line 11) is loaded. ``opaque_addr`` (line 13) and ``opaque_size`` (line 14) are used by +the guest for passing data across resets. The contents of this guest memory are preserved across the +reset. For confidential guests, this memory region must come from guest shared unencrypted memory. + +``status`` (line 3) is written by the hypervisor and it indicates the result of the IGVM loading operation. +A success indicates status code 0. Otherwise a non-zero status code indicates failure. The nature of the +failure is indicated by the value of the code. + +Triggering the Launch State Update using IGVM +********************************************* + +To initiate the launch update process, the guest issues a standard system reset +operation through any of the means implemented by the machine model. + +On a write to the ``etc/vmlaunchupdate`` interface, the hypervisor evaluates whether this +hypervisor interface is disabled. If it is, it ignores any writes to this ``fw-cfg`` file +by the guest. No updates to initial launch state is performed. + +If the hypervisor interface is enabled, upon write to the ``etc/vmlaunchupdate`` interface, +the hypervisor parses the IGVM file bundle passed to it in memory, with starting guest physical +address at ``fw_image_addr`` and length ``fw_image_size``. If parsing is successful, it creates +a context handle to the IGVM file. If parsing and context loading is successful and there are no +errors, ``fw_image_addr`` and ``fw_image_size`` are cleared. The guest can check this in order +to determine if the IGVM was successfully parsed and the new context was loaded. If not, the +guest can throw error and abort rebooting to new IGVM boot state. Alternatively, the guest can +also check the ``status`` code from the ``fw-cfg`` file. A status code of 0 indicates success +of the operation. Non-zero status code indicates failure. Exact nature of the failure is +indicated by the value of the code. Currently, only two error values are supported: + +* ``VM_LAUNCHUPDATE_LOAD_FAIL`` - defined as value 1 and is set when loading of the IGVM file failed. +* ``VM_LAUNCHUPDATE_NOT_IGVM_INIT`` - defined as value 2 and is set when the guest was not started with + IGVM file. + +Upon guest reset, the hypervisor executes the IGVM bundle using +the context handle, setting the initial launch state of the guest accordingly. +If an invalid IGVM file is passed, parsing the file fails and the hypervisor ignores it +when ``fw-cfg`` files are written. In this case, the initial launch state +is not modified. If invalid addresses are passed, the hypervisor ignores them as well and no +new launch state is set. + +The launch state update mechanism works both for confidential and non-confidential +guests. In confidential guests, as a part of the reset operation, all existing +guest shared memory (shared with the hypervisor) as well as the guest memory region +starting with ``opaque_addr`` and length ``opaque_size`` are preserved. +The reset causes recreation of the VM context which triggers a fresh +measurement of the replaced BIOS region and reset CPU state. + +For non-confidential guests, there is no concept of guest private memory and all the existing +guest memory is preserved (this is the default behaviour today - QEMU does not reset/clear +guest memory upon reset). + +In both confidential and non-confidential cases, CPU and device state are reset to +the reset states specified in IGVM. In confidential environments, the guest +always resumes operation in the highest privileged mode available to it (VMPL0 in SEV-SNP). + +Closing Remarks +*************** +The exact content of the memory region specified by starting address ``opaque_addr`` +and length ``opaque_size`` is guest specific and is hypervisor agnostic. The hypervisor does +not care about the contents of this memory region. Therefore, it is not included in this +specification. As of writing this document, TDX guests on QEMU does not support IGVM. +Therefore, this mechanism cannot be used to change launch state of TDX guests. From f0e7be2e8b647c43dad3b3cabe3b50b071205351 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:50:04 +0530 Subject: [PATCH 430/627] tests/qtest: Add small igvm files for testing purpose Needed by launchupdate-test.c. README file is added with explanation on how to build these IGVM files. CC: Alex Graf CC: Gerd Hoffman Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-10-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- tests/data/igvm/README | 45 ++++++++++++++++++++++++++++++++++ tests/data/igvm/hello.igvm | Bin 0 -> 137112 bytes tests/data/igvm/qemuinit.igvm | Bin 0 -> 137112 bytes 3 files changed, 45 insertions(+) create mode 100644 tests/data/igvm/README create mode 100644 tests/data/igvm/hello.igvm create mode 100644 tests/data/igvm/qemuinit.igvm diff --git a/tests/data/igvm/README b/tests/data/igvm/README new file mode 100644 index 0000000000..d4d26478ee --- /dev/null +++ b/tests/data/igvm/README @@ -0,0 +1,45 @@ + +=== This is the readme file for all IGVM file bundles provided === +=== All IGVM files are covered by GPL v2 or later === +SPDX-License-Identifier: GPL-2.0-or-later + +Small IGVM file bundles required for tesing vm-launch-update device +=================================================================== + +This directory contains IGVM files required for launchupdate-test.c. +These IGVM bundles can be built from the following repository: + +https://gitlab.com/anisinha/virt-firmware-rs + +Just type "make" in the top of the repository. The built IGVM files +can be found in the target/x86_64-unknown-none/debug directory. + +$ ls -l ./target/x86_64-unknown-none/debug/*.igvm +-rw-r--r--. 1 anisinha anisinha 153624 Jun 8 10:05 ./target/x86_64-unknown-none/debug/hello.igvm +-rw-r--r--. 1 anisinha anisinha 157848 Jun 8 10:05 ./target/x86_64-unknown-none/debug/igvmtest.igvm +-rw-r--r--. 1 anisinha anisinha 987384 Jun 8 10:05 ./target/x86_64-unknown-none/debug/mefisto.igvm +-rw-r--r--. 1 anisinha anisinha 368312 Jun 8 10:05 ./target/x86_64-unknown-none/debug/qemuinit.igvm +-rw-r--r--. 1 anisinha anisinha 223944 Jun 8 10:05 ./target/x86_64-unknown-none/debug/snptest.igvm + +The IGVM bundles for sev-snp testing are also kept in a seperate directory /snp_igvm_bundles in the +above repository for use without requiring to build from source: + +$ virtfirmware-rs/snp_igvm_bundles$ ls -l +total 388 +-rw-r--r-- 1 anisinha anisinha 199176 Aug 7 00:58 snptest.igvm +-rw-r--r-- 1 anisinha anisinha 195048 Aug 6 06:10 snptest-nohello.igvm + +Following files are used by the tests/qtest/launchupdate-test.c for non-coco case: + +hello.igvm +qemuinit.igvm + +For confidential case (that is when COCO=1 is passed in the environment), the following +IGVM bundles are used: + +snptest-nohello.igvm +snptest.igvm + +The IGVM bundles used by the confidential case are not checked into the QEMU +repository. Users who wish to test the confidential case can use the IGVM +bundles from https://gitlab.com/anisinha/virt-firmware-rs as mentioned above. diff --git a/tests/data/igvm/hello.igvm b/tests/data/igvm/hello.igvm new file mode 100644 index 0000000000000000000000000000000000000000..2d3ffda5b157c13d109ef965d1c0f41e9a34caf5 GIT binary patch literal 137112 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


b%X`Syga=^G9 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 literal 0 HcmV?d00001 diff --git a/tests/data/igvm/qemuinit.igvm b/tests/data/igvm/qemuinit.igvm new file mode 100644 index 0000000000000000000000000000000000000000..08e605ae0d8164b115bd2ac8b65530ecc7d78eaf GIT binary patch literal 137112 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 arvjY{bSluPK&Jwo3Un&aslWqP;Qs Date: Mon, 17 Aug 2026 19:50:05 +0530 Subject: [PATCH 431/627] Add functional and unit tests for the vm-launch-update device This patchset adds functional and unit tests that exercize various functions and behaviors of vm-launch-update device. It uses the IGVM files that were introduced in the previous patch for exercizing the hypervisor interface. CC: Alex Graf CC: Gerd Hoffman Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-11-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- tests/functional/aarch64/meson.build | 4 + .../aarch64/test_vm_launch_update_aarch.py | 33 + tests/functional/x86_64/meson.build | 4 + .../x86_64/test_vm_launch_update.py | 48 ++ tests/qtest/launchupdate-test.c | 625 ++++++++++++++++++ tests/qtest/meson.build | 2 + 6 files changed, 716 insertions(+) create mode 100755 tests/functional/aarch64/test_vm_launch_update_aarch.py create mode 100755 tests/functional/x86_64/test_vm_launch_update.py create mode 100644 tests/qtest/launchupdate-test.c diff --git a/tests/functional/aarch64/meson.build b/tests/functional/aarch64/meson.build index e81afd6c39..f0881bed16 100644 --- a/tests/functional/aarch64/meson.build +++ b/tests/functional/aarch64/meson.build @@ -25,6 +25,10 @@ tests_aarch64_system_quick = [ 'vmstate', ] +if igvm.found() + tests_aarch64_system_quick += [ 'vm_launch_update_aarch' ] +endif + tests_aarch64_system_thorough = [ 'aspeed_ast2700a1', 'aspeed_ast2700a2', diff --git a/tests/functional/aarch64/test_vm_launch_update_aarch.py b/tests/functional/aarch64/test_vm_launch_update_aarch.py new file mode 100755 index 0000000000..2b3d7cf4a3 --- /dev/null +++ b/tests/functional/aarch64/test_vm_launch_update_aarch.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# +# Check for vm-launch-update device. +# +# Copyright (c) 2026 Red Hat, Inc. +# +# Author: +# Ani Sinha +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest + +class VmLaunchUpdateDeviceCheck(QemuSystemTest): + + def aarch64_fail_test(self): + """ + Currently the device is only supported for pc platforms. + """ + self.vm.add_args('-machine', 'virt', '-device', + 'vm-launch-update,id=fwupd1') + self.vm.set_qmp_monitor(enabled=False) + self.vm.launch() + self.vm.wait() + self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1") + self.assertRegex(self.vm.get_log(), + r'This machine does not support vm-launch-update device') + + def test_vm_launch_update(self): + self.aarch64_fail_test() + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build index 27b31f2e96..0353b2af8e 100644 --- a/tests/functional/x86_64/meson.build +++ b/tests/functional/x86_64/meson.build @@ -28,6 +28,10 @@ if not get_option('asan') tests_x86_64_system_quick += [ 'memlock' ] endif +if igvm.found() + tests_x86_64_system_quick += [ 'vm_launch_update' ] +endif + tests_x86_64_system_thorough = [ 'acpi_bits', 'hotplug_blk', diff --git a/tests/functional/x86_64/test_vm_launch_update.py b/tests/functional/x86_64/test_vm_launch_update.py new file mode 100755 index 0000000000..aac7ef915f --- /dev/null +++ b/tests/functional/x86_64/test_vm_launch_update.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Check for vm-launch-update device. +# +# Copyright (c) 2026 Red Hat, Inc. +# +# Author: +# Ani Sinha +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest +import time + +class VmLaunchUpdateDeviceCheck(QemuSystemTest): + DELAY_BOOT_SEQUENCE = 1 + + def vm_launch_update_pass(self): + """ + Basic test to make sure vm-launch-update device can be instantiated. + """ + self.vm.add_args('-device', 'vm-launch-update,id=fwupd1') + self.vm.set_qmp_monitor(enabled=False) + self.vm.launch() + time.sleep(self.DELAY_BOOT_SEQUENCE) + self.vm.shutdown() + self.assertEqual(self.vm.exitcode(), 0, "QEMU exit code should be 0") + + def multiple_device_fail(self): + """ + Only one vm-launch-update device can be instantiated. Ensure failure if + user tries to create more than one device. + """ + self.vm.add_args('-device', 'vm-launch-update,id=fw1', + '-device', 'vm-launch-update,id=fw2') + self.vm.set_qmp_monitor(enabled=False) + self.vm.launch() + self.vm.wait() + self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1") + self.assertRegex(self.vm.get_log(), + r'at most one vm-launch-update device is permitted') + + def test_vm_launch_update(self): + self.vm_launch_update_pass() + self.multiple_device_fail() + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/qtest/launchupdate-test.c b/tests/qtest/launchupdate-test.c new file mode 100644 index 0000000000..225c843df5 --- /dev/null +++ b/tests/qtest/launchupdate-test.c @@ -0,0 +1,625 @@ +/* + * vmlaunchupdate device fwcfg test. + * + * Copyright (c) 2026 Red Hat, Inc. + * + * Author: + * Ani Sinha + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqos/libqos-pc.h" +#include "libqtest.h" +#include "standard-headers/linux/qemu_fw_cfg.h" +#include "libqos/fw_cfg.h" +#include "qemu/bswap.h" +#include "hw/misc/vmlaunchupdate.h" + +#define WAIT_SEC 10 +static bool debug; +static bool trace; +static bool confidential; + +static void test_vm_launch_update_capability(void) +{ + QFWCFG *fw_cfg; + QTestState *s; + VMLaunchUpdate launch_update; + size_t filesize; + uint64_t capabilities; + + if (!qtest_has_device("vm-launch-update")) { + g_test_skip("Device vm-launch-update is not available"); + return; + } + + s = qtest_init("-device vm-launch-update"); + fw_cfg = pc_fw_cfg_init(s); + + filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + capabilities = le64_to_cpu(launch_update.capabilities); + g_assert_cmpint(capabilities, ==, VM_LAUNCHUPDATE_FORMAT_IGVM); + pc_fw_cfg_uninit(fw_cfg); + qtest_quit(s); +} + + +static void test_vm_launch_update_disable(void) +{ + QFWCFG *fw_cfg; + QOSState *qs; + VMLaunchUpdate launch_update; + uint64_t control; + size_t filesize; + + if (!qtest_has_device("vm-launch-update")) { + g_test_skip("Device vm-launch-update is not available"); + return; + } + + /* use default accelerator */ + qs = qtest_pc_boot("-device vm-launch-update"); + + fw_cfg = pc_fw_cfg_init(qs->qts); + + filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + control = le64_to_cpu(launch_update.control); + g_assert_cmpint(VM_LAUNCHUPDATE_CTL_DISABLE & control, ==, 0); + + /* disable the device */ + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.control |= VM_LAUNCHUPDATE_CTL_DISABLE; + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + /* try to clear the dsable flag */ + memset(&launch_update, 0, sizeof(launch_update)); + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + /* check if the device is still disabled */ + filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + control = le64_to_cpu(launch_update.control); + g_assert_cmpint(VM_LAUNCHUPDATE_CTL_DISABLE & control, ==, 1); + + pc_fw_cfg_uninit(fw_cfg); + qtest_shutdown(qs); +} + +static void check_error(void) +{ + QFWCFG *fw_cfg; + QOSState *qs; + VMLaunchUpdate launch_update; + uint16_t status; + size_t filesize; + + if (!qtest_has_device("vm-launch-update")) { + g_test_skip("Device vm-launch-update is not available"); + return; + } + + /* guest not started with IGVM and with default accelerator */ + qs = qtest_pc_boot("-device vm-launch-update"); + + fw_cfg = pc_fw_cfg_init(qs->qts); + + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.fw_image_size = 50; + launch_update.fw_image_addr = cpu_to_le64(0xdeadbeef); + launch_update.control |= VM_LAUNCHUPDATE_FORMAT_IGVM; + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + memset(&launch_update, 0, sizeof(launch_update)); + filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + status = le64_to_cpu(launch_update.status); + /* should fail with NOT_IGVM_INIT */ + g_assert_cmpint(status, ==, VM_LAUNCHUPDATE_NOT_IGVM_INIT); + + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.fw_image_size = 50; + launch_update.fw_image_addr = cpu_to_le64(0xdeadbeef); + /* control set to 0, not VM_LAUNCHUPDATE_FORMAT_IGVM */ + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + memset(&launch_update, 0, sizeof(launch_update)); + filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + status = le64_to_cpu(launch_update.status); + /* should fail with LOAD_FAIL since it was not IGVM format */ + g_assert_cmpint(status, ==, VM_LAUNCHUPDATE_LOAD_FAIL); +} + +static int64_t get_image_size(const char *filename) +{ + int fd; + int64_t size; + fd = open(filename, O_RDONLY | O_BINARY); + g_assert_true(fd > 0); + size = lseek(fd, 0, SEEK_END); + close(fd); + return size; +} + +static ssize_t load_image(const char *igvm_f, void **addr, size_t *size) +{ + ssize_t actsize = 0, l = 0; + int f_igvm_f; + size_t l_size; + + f_igvm_f = open(igvm_f, O_RDONLY | O_BINARY); + g_assert_true(f_igvm_f); + l_size = get_image_size(igvm_f); + g_assert_true(l_size > 0); + *addr = g_malloc0(l_size); + g_assert_true(*addr); + + while (l < l_size) { + actsize = read(f_igvm_f, *addr + l, 1); + if (actsize < 0) { + break; + } + l += actsize; + } + + close(f_igvm_f); + *size = l_size; + return actsize < 0 ? -1 : l; +} + +static guint32 match_string(char *serial_f, const char *exp_out) +{ + GError *error = NULL; + g_autofree gchar *f_contents = NULL; + g_autofree GRegex *regex = NULL; + g_autofree GMatchInfo *match_info = NULL; + gsize len; + guint32 count = 0; + gboolean ret; + + ret = g_file_get_contents(serial_f, &f_contents, &len, &error); + g_assert(ret); + g_assert_no_error(error); + + regex = g_regex_new(exp_out, G_REGEX_CASELESS, 0, &error); + g_assert_no_error(error); + + ret = g_regex_match_full(regex, f_contents, -1, 0, 0, &match_info, &error); + g_assert_no_error(error); + + while (g_match_info_matches(match_info)) { + gchar *word = g_match_info_fetch(match_info, 0); + g_free(word); + g_match_info_next(match_info, &error); + count++; + } + g_regex_unref(regex); + return count; +} + +static int wait_for_match(char *serial_f, + const char *exp_out, int64_t timeout_s, + guint32 count) +{ + time_t start, delta; + int ret = -1; + + start = time(NULL); + while (1) { + if (match_string(serial_f, exp_out) == count) { + ret = 0; + break; + } + + delta = time(NULL) - start; + if (delta >= timeout_s) { + fprintf(stderr, "timed out waiting to read serial output\n"); + break; + } + + /* wait 20 ms before trying again */ + if (false) { + fprintf(stderr, + "sleeping 20 ms before checking serial output again.\n"); + } + g_usleep(20000); + } + return ret; +} + +static void set_test_params(const char **igvm_f, const char **igvm_init, + const char **snp, const char **cgs) +{ + if (confidential) { + *snp = "-object \'{\"qom-type\":\"sev-snp-guest\",\"id\":\"lsec0\"," + "\"cbitpos\":51,\"reduced-phys-bits\":1,\"policy\":196608}\'"; + *cgs = "confidential-guest-support=lsec0"; + /* + * The following two IGVM files can be built from the source + * present in https://gitlab.com/anisinha/virt-firmware-rs . + * Typing 'make' from the top of this repository will build the + * IGVM files for both confidential and + * non-confidential tests. The IGVM files for the non-coco + * case has been checked-in into the QEMU repository for + * convenience and easy CI pipeline testing. + */ + *igvm_f = "tests/data/igvm/snptest.igvm"; /* prints 'hello world' */ + *igvm_init = "tests/data/igvm/snptest-nohello.igvm"; + } else { + *igvm_f = "tests/data/igvm/hello.igvm"; + *igvm_init = "tests/data/igvm/qemuinit.igvm"; + *snp = ""; + *cgs = ""; + } + + return; +} + +static void set_expected_out(const char **exp_out, const char **exp_out2, + const char **exp_out3) +{ + *exp_out = "Hello world!"; + *exp_out2 = "Test succeeded!"; + *exp_out3 = "boot process complete with initial igvm"; + + return; +} + +static QOSState *set_qemu_args(const char *cgs, const char *tp, char *serialf, + const char *igvm_init, const char *snp) +{ + QOSState *qs; + + if (tp) { + qs = qtest_pc_boot("-machine q35,igvm-cfg=igvm0,%s -m 1G -accel kvm " + "-device vm-launch-update %s " + "-chardev file,id=serial0,path=%s " + "-serial chardev:serial0 " + "-object igvm-cfg,id=igvm0,file=%s %s", + cgs, tp, serialf, igvm_init, snp); + } else { + qs = qtest_pc_boot("-machine q35,igvm-cfg=igvm0,%s -m 1G -accel kvm " + "-device vm-launch-update " + "-chardev file,id=serial0,path=%s " + "-serial chardev:serial0 " + "-object igvm-cfg,id=igvm0,file=%s %s", + cgs, serialf, igvm_init, snp); + } + + return qs; +} + +static void test_load_igvm(void) +{ + const char *igvm_f; + const char *igvm_init; + int ser_fd; + g_autofree void *igvm_blob = NULL; + g_autofree char *serialtmp = NULL; + const char *exp_out; + const char *exp_out2; + const char *exp_out3; + const char *tracepoints = "--trace memory_region_finalize " + "--trace qigvm_cleanup_memory -D /tmp/qemu-debug.log "; + const char *snp, *cgs; + uint64_t gaddr; + size_t igvm_sz; + size_t filesize; + QFWCFG *fw_cfg; + QOSState *qs; + VMLaunchUpdate launch_update; + + if (!trace) { + tracepoints = ""; + } + + if (!qtest_has_machine("q35")) { + g_test_skip("q35 machine not available"); + return; + } + + if (!qtest_has_accel("kvm")) { + g_test_skip("No KVM accelerator available"); + return; + } + + if (!qtest_has_device("vm-launch-update")) { + g_test_skip("Device vm-launch-update is not available"); + return; + } + + set_test_params(&igvm_f, &igvm_init, &snp, &cgs); + set_expected_out(&exp_out, &exp_out2, &exp_out3); + + if (!g_file_test(igvm_f, G_FILE_TEST_EXISTS) || + !g_file_test(igvm_init, G_FILE_TEST_EXISTS)) { + g_test_skip("igvm file bundle(s) does not exist!"); + return; + } + + ser_fd = g_file_open_tmp("launchupdate-qtest-serial-sXXXXXX", + &serialtmp, NULL); + g_assert_true(ser_fd != -1); + + if (debug) { + fprintf(stderr, "serial console file is %s\n", serialtmp); + } + + qs = set_qemu_args(cgs, tracepoints, serialtmp, igvm_init, snp); + + fw_cfg = pc_fw_cfg_init(qs->qts); + + if (debug) { + fprintf(stderr, "target endianness: %s\n", + qtest_big_endian(qs->qts) ? "big" : "little"); + } + + /* exp_out3 should be printed once from initial boot */ + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 1) == 0); + + if (debug) { + fprintf(stderr, "initially booted with host igvm\n"); + } + + g_assert_true(load_image(igvm_f, &igvm_blob, &igvm_sz) == igvm_sz); + + /* create a data buffer in guest memory */ + gaddr = guest_alloc(&qs->alloc, igvm_sz); + + if (debug) { + fprintf(stderr, "guest paddr: %"PRIx64 " igvm size: %lu\n", + gaddr, igvm_sz); + } + + if (debug) { + fprintf(stderr, "writing igvm file into the guest memory\n"); + } + + qtest_bufwrite(qs->qts, gaddr, igvm_blob, igvm_sz); + + if (debug) { + fprintf(stderr, + "tell hypervisor where igvm is loaded in guest memory\n"); + } + + /* now tell hypervisor where we loaded the bios */ + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.fw_image_size = cpu_to_le64(igvm_sz); + launch_update.fw_image_addr = cpu_to_le64(gaddr); + launch_update.control |= VM_LAUNCHUPDATE_FORMAT_IGVM; + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + if (debug) { + fprintf(stderr, "resetting the virtual machine now\n"); + } + + qtest_system_reset(qs->qts); + + /* expected string should be printed on the console */ + g_assert_true(wait_for_match(serialtmp, exp_out, WAIT_SEC, 1) == 0); + g_assert_true(wait_for_match(serialtmp, exp_out2, WAIT_SEC, 1) == 0); + + if (debug) { + fprintf(stderr, "hello world found on console\n"); + } + + /* check if VM_LAUNCHUPDATE_CTL_HOST_IGVM function works */ + + /* set only VM_LAUNCHUPDATE_CTL_HOST_IGVM control without IGVM bundle */ + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.control |= VM_LAUNCHUPDATE_CTL_HOST_IGVM; + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + /* now reset the guest */ + if (debug) { + fprintf(stderr, + "resetting again in order to restore host provided IGVM\n"); + } + qtest_system_reset(qs->qts); + + /* + * exp_out3 should be printed twice, once from initial boot, + * once from restoring host igvm. + */ + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 2) == 0); + + if (debug) { + fprintf(stderr, "booted with host igvm again\n"); + } + + close(ser_fd); + guest_free(&qs->alloc, gaddr); + pc_fw_cfg_uninit(fw_cfg); + /* qtest_quit() kils QEMU, first by sending SIGTERM, then SIGKILL */ + qtest_quit(qs->qts); +} + +static void test_set_ctrl_once_and_reset_to_host_igvm(void) +{ + const char *igvm_f; + const char *igvm_init; + int ser_fd; + g_autofree void *igvm_blob = NULL; + g_autofree char *serialtmp = NULL; + const char *exp_out; + const char *exp_out2; + const char *exp_out3; + const char *snp, *cgs; + uint64_t gaddr; + size_t igvm_sz; + size_t filesize; + QFWCFG *fw_cfg; + QOSState *qs; + VMLaunchUpdate launch_update; + + if (!qtest_has_machine("q35")) { + g_test_skip("q35 machine not available"); + return; + } + + if (!qtest_has_accel("kvm")) { + g_test_skip("No KVM accelerator available"); + return; + } + + if (!qtest_has_device("vm-launch-update")) { + g_test_skip("Device vm-launch-update is not available"); + return; + } + + set_test_params(&igvm_f, &igvm_init, &snp, &cgs); + set_expected_out(&exp_out, &exp_out2, &exp_out3); + + if (!g_file_test(igvm_f, G_FILE_TEST_EXISTS) || + !g_file_test(igvm_init, G_FILE_TEST_EXISTS)) { + g_test_skip("igvm file bundle(s) does not exist!"); + return; + } + + ser_fd = g_file_open_tmp("launchupdate-qtest-serial-sXXXXXX", + &serialtmp, NULL); + g_assert_true(ser_fd != -1); + + if (debug) { + fprintf(stderr, "serial console file is %s\n", serialtmp); + } + + qs = set_qemu_args(cgs, NULL, serialtmp, igvm_init, snp); + + fw_cfg = pc_fw_cfg_init(qs->qts); + + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 1) == 0); + + if (debug) { + fprintf(stderr, "initially booted with host igvm\n"); + } + + g_assert_true(load_image(igvm_f, &igvm_blob, &igvm_sz) == igvm_sz); + + /* create a data buffer in guest memory */ + gaddr = guest_alloc(&qs->alloc, igvm_sz); + + if (debug) { + fprintf(stderr, "guest paddr: %"PRIx64 " igvm size: %lu\n", + gaddr, igvm_sz); + } + + if (debug) { + fprintf(stderr, "writing igvm file into the guest memory\n"); + } + + qtest_bufwrite(qs->qts, gaddr, igvm_blob, igvm_sz); + + if (debug) { + fprintf(stderr, + "tell hypervisor where igvm is loaded in guest memory\n"); + } + + /* now tell hypervisor where we loaded the bios */ + memset(&launch_update, 0, sizeof(launch_update)); + launch_update.fw_image_size = cpu_to_le64(igvm_sz); + launch_update.fw_image_addr = cpu_to_le64(gaddr); + + /* set both host ctrl and format_igvm ctrl once */ + launch_update.control |= VM_LAUNCHUPDATE_FORMAT_IGVM; + launch_update.control |= VM_LAUNCHUPDATE_CTL_HOST_IGVM; + + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, + &launch_update, sizeof(launch_update)); + g_assert_cmpint(filesize, ==, sizeof(launch_update)); + + if (debug) { + fprintf(stderr, "resetting the virtual machine. This should load " + "user provided igvm.\n"); + } + + qtest_system_reset(qs->qts); + + /* expected string should be printed on the console */ + g_assert_true(wait_for_match(serialtmp, exp_out, WAIT_SEC, 1) == 0); + g_assert_true(wait_for_match(serialtmp, exp_out2, WAIT_SEC, 1) == 0); + + if (debug) { + fprintf(stderr, "hello world found on console\n"); + fprintf(stderr, "Now resetting again in order to reset to host igvm\n"); + } + + qtest_system_reset(qs->qts); + + /* + * exp_out3 should be printed twice, once from initial boot, + * once from restoring host igvm. + */ + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 2) == 0); + + if (debug) { + fprintf(stderr, "booted with host igvm\n"); + } + + close(ser_fd); + guest_free(&qs->alloc, gaddr); + pc_fw_cfg_uninit(fw_cfg); + /* qtest_quit() kils QEMU, first by sending SIGTERM, then SIGKILL */ + qtest_quit(qs->qts); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "x86_64")) { + g_test_skip("vmlaunchupdate tests are only available on x86_64\n"); + return 0; + } + + g_test_add_func("/vm-launch-update/cap", test_vm_launch_update_capability); + g_test_add_func("/vm-launch-update/disabled", + test_vm_launch_update_disable); + + g_test_add_func("/vm-launch-update/errorcheck", check_error); + g_test_add_func("/vm-launch-update/load_igvm", + test_load_igvm); + g_test_add_func("/vm-launch-update/ctrl_set_once", + test_set_ctrl_once_and_reset_to_host_igvm); + + if (getenv("LAUNCHUPDATE_DEBUG")) { + debug = true; + } + if (getenv("LAUNCHUPDATE_TRACE")) { + trace = true; + } + if (getenv("COCO")) { + confidential = true; + } + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index f7c7d06620..12ed368997 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -61,6 +61,8 @@ qtests_i386 = \ (config_all_devices.has_key('CONFIG_Q35') ? ['e820-test'] : []) + \ (config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['vmcoreinfo-test'] : []) + \ (config_all_devices.has_key('CONFIG_Q35') ? ['dump-test'] : []) + \ + (igvm.found() and + config_all_devices.has_key('CONFIG_FW_CFG_DMA') ? ['launchupdate-test'] : []) + \ (config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + \ (config_all_devices.has_key('CONFIG_I440FX') ? ['ide-test'] : []) + \ (config_all_devices.has_key('CONFIG_I440FX') ? ['numa-test'] : []) + \ From e27a2b5f36a0fc913ab9a55a00f77a33ec6cc4f0 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 17 Aug 2026 19:50:06 +0530 Subject: [PATCH 432/627] Update MAINTAINERS Add maintainers for vm-launch-update device and associated documentation and test code. Reviewed-by: Alexander Graf Signed-off-by: Ani Sinha Message-ID: <20260817142010.80693-12-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9e0a2a656f..1f9c08d766 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2851,6 +2851,19 @@ F: include/hw/acpi/vmgenid.h F: docs/specs/vmgenid.rst F: tests/qtest/vmgenid-test.c +VM Launch Update +M: Ani Sinha +M: Gerd Hoffman +S: Maintained +F: hw/misc/vmlaunchupdate.c +F: include/hw/misc/vmlaunchupdate.h +F: include/standard-headers/misc/vmlaunchupdate.h +F: docs/specs/vmlaunchupdate.rst +F: tests/functional/aarch64/test_vm_launch_update_aarch.py +F: tests/functional/x86_64/test_vm_launch_update.py +F: tests/qtest/launchupdate-test.c +F: tests/data/igvm/* + LED M: Philippe Mathieu-Daudé S: Maintained From 1bfce83996929033fa14a123967bf40976888661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 433/627] target/arm: Restrict arm_do_plugin_vcpu_discon_cb() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far TCG plugins can only be used when TCG is available. Move the arm_do_plugin_vcpu_discon_cb() call within the 'if tcg_enabled' block and wrap the definition with #ifdef'ry. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20260814080507.23196-1-philmd@oss.qualcomm.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index af45234ad2..adae2b2b8e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8915,6 +8915,7 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode, } } +#ifdef CONFIG_TCG void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from) { switch (cs->exception_index) { @@ -8932,6 +8933,7 @@ void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from) qemu_plugin_vcpu_exception_cb(cs, from); } } +#endif static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs) { @@ -9677,9 +9679,9 @@ void arm_cpu_do_interrupt(CPUState *cs) if (tcg_enabled()) { cpu_set_interrupt(cs, CPU_INTERRUPT_EXITTB); - } - arm_do_plugin_vcpu_discon_cb(cs, last_pc); + arm_do_plugin_vcpu_discon_cb(cs, last_pc); + } } #endif /* !CONFIG_USER_ONLY */ From d05febdd32cc6d6a0700994d25ae3ffccdc97e76 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 434/627] hw/intc: Fix arm kvm gicv3 selection While 39a8c3941e may have fixed WHPX, it certainly didn't help KVM: $ QTEST_QEMU_BINARY=./qemu-system-aarch64 ./tests/qtest/arm-cpu-features ... qemu-system-aarch64: unknown type 'kvm-arm-gicv3' That patch did remove a test for TARGET_AARCH64, which is fine because it has been a long time since we supported KVM for AArch32. Cc: qemu-stable@nongnu.org Fixes: 39a8c3941e ("hw/intc/arm_gicv3: Fix ARM_GICV3 dependency for KVM / WHPX") Signed-off-by: Richard Henderson Message-id: 20260812200308.289238-1-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 4373f16d0b..0620b0792a 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c')) specific_ss.add(when: ['CONFIG_WHPX', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_whpx.c')) specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_hvf.c')) stub_ss.add(files('arm_gicv3_hvf_stub.c')) -specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c')) +specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c')) arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c')) specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c')) specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c')) From a0c093900d84f6668c27eaeab4ca74935b5857b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 435/627] hw/intc/arm_gicv3: Have GIC kconfig select GICv3 for HVF and WHPX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While trying to fix the GICv3 dependency on KVM and WHPX in commit 39a8c3941eb, we missed the Kconfig ARM_GIC symbol only selects GICv3 for TCG, not HVF and WHPX. Fix that. Cc: qemu-stable@nongnu.org Fixes: 39a8c3941eb ("hw/intc/arm_gicv3: Fix ARM_GICV3 dependency for KVM / WHPX") Signed-off-by: Philippe Mathieu-Daudé Message-id: 20260812220816.94034-1-philmd@oss.qualcomm.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 097de4efc5..05e697967d 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -26,7 +26,7 @@ config APIC config ARM_GIC bool - select ARM_GICV3 if TCG + select ARM_GICV3 if TCG || HVF || WHPX select ARM_GIC_KVM if KVM select MSI_NONBROKEN From 66d0446738c7be74b40746e3eebe5cfbeea56d45 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 436/627] target/arm: Tidy cpu_max_initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once we have eliminated hwaccel_enabled, only tcg and qtest remain. Separate tcg from qtest initialization. Remove an assert on aarch64_enabled that is directly protected by a preceding if. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260812204435.295067-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index 88b7c04633..0a310d1b15 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -203,29 +203,32 @@ static void cpu_max_initfn(Object *obj) return; } - if (tcg_enabled() || qtest_enabled()) { - aarch64_aa32_a57_init(obj, !aarch64_enabled); - } - - if (!aarch64_enabled) { - aa32_max_features(cpu); -#ifdef CONFIG_USER_ONLY - /* - * Break with true ARMv8 and add back old-style VFP short-vector - * support. Only do this for user-mode, where -cpu max is the default, - * so that older v6 and v7 programs are more likely to work without - * adjustment. - */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); -#endif - } else if (tcg_enabled()) { - assert(aarch64_enabled); + if (tcg_enabled()) { /* * '-cpu max' for TCG: we currently do this as * "A57 with extra things" */ - aarch64_max_tcg_initfn(obj); + aarch64_aa32_a57_init(obj, !aarch64_enabled); + if (!aarch64_enabled) { + aa32_max_features(cpu); +#ifdef CONFIG_USER_ONLY + /* + * Break with true ARMv8 and add back old-style VFP short-vector + * support. Only do this for user-mode, where -cpu max is the default, + * so that older v6 and v7 programs are more likely to work without + * adjustment. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +#endif + } else { + aarch64_max_tcg_initfn(obj); + } + return; } + + /* Ultimate fallback: -cpu max as cortex-a57. */ + assert(qtest_enabled()); + aarch64_aa32_a57_init(obj, !aarch64_enabled); } static const ARMCPUInfo arm_max_cpu = { From 9caff83f5b976da8285db55d363e861675e79777 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 437/627] target/arm: Pass ARMCPU to aarch64_aa32_a57_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no reason to pass Object when ARMCPU is more appropriate. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20260812204435.295067-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 7 +++---- target/arm/cpu64.c | 2 +- target/arm/internals.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index 0a310d1b15..bd858f010c 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -16,9 +16,8 @@ #include "target/arm/internals.h" #include "target/arm/cpregs.h" -void aarch64_aa32_a57_init(Object *obj, bool aa32_only) +void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa32_only) { - ARMCPU *cpu = ARM_CPU(obj); ARMISARegisters *isar = &cpu->isar; const bool aarch64_enabled = !aa32_only; @@ -208,7 +207,7 @@ static void cpu_max_initfn(Object *obj) * '-cpu max' for TCG: we currently do this as * "A57 with extra things" */ - aarch64_aa32_a57_init(obj, !aarch64_enabled); + aarch64_aa32_a57_init(cpu, !aarch64_enabled); if (!aarch64_enabled) { aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY @@ -228,7 +227,7 @@ static void cpu_max_initfn(Object *obj) /* Ultimate fallback: -cpu max as cortex-a57. */ assert(qtest_enabled()); - aarch64_aa32_a57_init(obj, !aarch64_enabled); + aarch64_aa32_a57_init(cpu, !aarch64_enabled); } static const ARMCPUInfo arm_max_cpu = { diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 2816735577..e3ee0253a0 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -688,7 +688,7 @@ void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) static void aarch64_a57_initfn(Object *obj) { - aarch64_aa32_a57_init(obj, false); + aarch64_aa32_a57_init(ARM_CPU(obj), false); } static void aarch64_a53_initfn(Object *obj) diff --git a/target/arm/internals.h b/target/arm/internals.h index 4026f67579..9c9196475b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1813,7 +1813,7 @@ void aarch64_max_tcg_initfn(Object *obj); void aarch64_add_pauth_properties(Object *obj); void aarch64_add_sve_properties(Object *obj); void aarch64_add_sme_properties(Object *obj); -void aarch64_aa32_a57_init(Object *obj, bool aa32_only); +void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa32_only); void aarch64_host_initfn(Object *obj); /* Return true if the gdbstub is presenting an AArch64 CPU */ From e5b092fa9251dec4f45f0f8a55ddd58f6cecac4d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 438/627] target/arm: Pass aarch64_enabled to aarch64_aa32_a57_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invert aa32_only argument to what is actually used. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20260812204435.295067-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 7 +++---- target/arm/cpu64.c | 2 +- target/arm/internals.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index bd858f010c..edb5b9e6c3 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -16,10 +16,9 @@ #include "target/arm/internals.h" #include "target/arm/cpregs.h" -void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa32_only) +void aarch64_aa32_a57_init(ARMCPU *cpu, bool aarch64_enabled) { ARMISARegisters *isar = &cpu->isar; - const bool aarch64_enabled = !aa32_only; cpu->dtb_compatible = "arm,cortex-a57"; set_feature(&cpu->env, ARM_FEATURE_V8); @@ -207,7 +206,7 @@ static void cpu_max_initfn(Object *obj) * '-cpu max' for TCG: we currently do this as * "A57 with extra things" */ - aarch64_aa32_a57_init(cpu, !aarch64_enabled); + aarch64_aa32_a57_init(cpu, aarch64_enabled); if (!aarch64_enabled) { aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY @@ -227,7 +226,7 @@ static void cpu_max_initfn(Object *obj) /* Ultimate fallback: -cpu max as cortex-a57. */ assert(qtest_enabled()); - aarch64_aa32_a57_init(cpu, !aarch64_enabled); + aarch64_aa32_a57_init(cpu, aarch64_enabled); } static const ARMCPUInfo arm_max_cpu = { diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index e3ee0253a0..faaf3ab879 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -688,7 +688,7 @@ void aarch64_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) static void aarch64_a57_initfn(Object *obj) { - aarch64_aa32_a57_init(ARM_CPU(obj), false); + aarch64_aa32_a57_init(ARM_CPU(obj), true); } static void aarch64_a53_initfn(Object *obj) diff --git a/target/arm/internals.h b/target/arm/internals.h index 9c9196475b..5e7f41a50d 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1813,7 +1813,7 @@ void aarch64_max_tcg_initfn(Object *obj); void aarch64_add_pauth_properties(Object *obj); void aarch64_add_sve_properties(Object *obj); void aarch64_add_sme_properties(Object *obj); -void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa32_only); +void aarch64_aa32_a57_init(ARMCPU *cpu, bool aa64_enabled); void aarch64_host_initfn(Object *obj); /* Return true if the gdbstub is presenting an AArch64 CPU */ From b5af4f6024023d5649c6ed248c837226491b3372 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 439/627] target/arm: Sink aarch64_aa32_a57_init into aarch64_max_tcg_initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20260812204435.295067-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 2 +- target/arm/tcg/cpu64.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index edb5b9e6c3..93f24114a5 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -206,8 +206,8 @@ static void cpu_max_initfn(Object *obj) * '-cpu max' for TCG: we currently do this as * "A57 with extra things" */ - aarch64_aa32_a57_init(cpu, aarch64_enabled); if (!aarch64_enabled) { + aarch64_aa32_a57_init(cpu, false); aa32_max_features(cpu); #ifdef CONFIG_USER_ONLY /* diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 24f34947ec..5649b853a7 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1167,6 +1167,8 @@ void aarch64_max_tcg_initfn(Object *obj) uint64_t t; uint32_t u; + aarch64_aa32_a57_init(cpu, true); + SET_IDREG(isar, CLIDR, 0x8200123); /* 64KB L1 dcache */ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7); From aa517d9774d63ffe41066e4c26c7540ee1625140 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 440/627] target/arm: Split out aarch32_max_tcg_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260812204435.295067-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 16 +--------------- target/arm/internals.h | 1 + target/arm/tcg/cpu32.c | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index 93f24114a5..7df7d015a9 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -202,22 +202,8 @@ static void cpu_max_initfn(Object *obj) } if (tcg_enabled()) { - /* - * '-cpu max' for TCG: we currently do this as - * "A57 with extra things" - */ if (!aarch64_enabled) { - aarch64_aa32_a57_init(cpu, false); - aa32_max_features(cpu); -#ifdef CONFIG_USER_ONLY - /* - * Break with true ARMv8 and add back old-style VFP short-vector - * support. Only do this for user-mode, where -cpu max is the default, - * so that older v6 and v7 programs are more likely to work without - * adjustment. - */ - cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); -#endif + aarch32_max_tcg_init(cpu); } else { aarch64_max_tcg_initfn(obj); } diff --git a/target/arm/internals.h b/target/arm/internals.h index 5e7f41a50d..f6b4e173a5 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1838,6 +1838,7 @@ uint32_t *arm_v7m_get_sp_ptr(CPUARMState *env, bool secure, bool el_is_in_host(CPUARMState *env, int el); void aa32_max_features(ARMCPU *cpu); +void aarch32_max_tcg_init(ARMCPU *cpu); int exception_target_el(CPUARMState *env); bool arm_singlestep_active(CPUARMState *env); bool arm_generate_debug_exceptions(CPUARMState *env); diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index 8220d785f5..e1ff074b47 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -748,3 +748,18 @@ static void arm_tcg_cpu_register_types(void) type_init(arm_tcg_cpu_register_types) #endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ + +void aarch32_max_tcg_init(ARMCPU *cpu) +{ + aarch64_aa32_a57_init(cpu, false); + aa32_max_features(cpu); +#ifdef CONFIG_USER_ONLY + /* + * Break with true ARMv8 and add back old-style VFP short-vector + * support. Only do this for user-mode, where -cpu max is the default, + * so that older v6 and v7 programs are more likely to work without + * adjustment. + */ + cpu->isar.mvfr0 = FIELD_DP32(cpu->isar.mvfr0, MVFR0, FPSHVEC, 1); +#endif +} From a2c25ce4138926c8ab44738263c35e8c329b9961 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 441/627] target/arm: Move aa32_max_features to tcg/cpu32.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is unused without TCG, so move. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260812204435.295067-7-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu-max.c | 96 ------------------------------------------ target/arm/tcg/cpu32.c | 96 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 96 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index 7df7d015a9..8d968336a8 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -85,102 +85,6 @@ void aarch64_aa32_a57_init(ARMCPU *cpu, bool aarch64_enabled) define_cortex_a72_a57_a53_cp_reginfo(cpu); } -/* Share AArch32 -cpu max features with AArch64. */ -void aa32_max_features(ARMCPU *cpu) -{ - uint32_t t; - ARMISARegisters *isar = &cpu->isar; - - /* Add additional features supported by QEMU */ - t = GET_IDREG(isar, ID_ISAR5); - t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */ - t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */ - t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */ - t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); - t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */ - t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */ - SET_IDREG(isar, ID_ISAR5, t); - - t = GET_IDREG(isar, ID_ISAR6); - t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */ - t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */ - t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */ - t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */ - t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */ - t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */ - t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */ - SET_IDREG(isar, ID_ISAR6, t); - - t = cpu->isar.mvfr1; - t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ - t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */ - cpu->isar.mvfr1 = t; - - t = cpu->isar.mvfr2; - t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ - t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ - cpu->isar.mvfr2 = t; - - FIELD_DP32_IDREG(isar, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ - - t = GET_IDREG(isar, ID_MMFR4); - t = FIELD_DP32(t, ID_MMFR4, HPDS, 2); /* FEAT_HPDS2 */ - t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ - t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ - t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ - t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT2 */ - SET_IDREG(isar, ID_MMFR4, t); - - FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 2); /* FEAT_ETS2 */ - - t = GET_IDREG(isar, ID_PFR0); - t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CSV2 */ - t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ - t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ - SET_IDREG(isar, ID_PFR0, t); - - t = GET_IDREG(isar, ID_PFR2); - t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ - t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ - SET_IDREG(isar, ID_PFR2, t); - - t = GET_IDREG(isar, ID_DFR0); - t = FIELD_DP32(t, ID_DFR0, COPDBG, 10); /* FEAT_Debugv8p8 */ - t = FIELD_DP32(t, ID_DFR0, COPSDBG, 10); /* FEAT_Debugv8p8 */ - t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ - SET_IDREG(isar, ID_DFR0, t); - - /* Debug ID registers. */ - - /* Bit[15] is RES1, Bit[13] and Bits[11:0] are RES0. */ - t = 0x00008000; - t = FIELD_DP32(t, DBGDIDR, SE_IMP, 1); - t = FIELD_DP32(t, DBGDIDR, NSUHD_IMP, 1); - t = FIELD_DP32(t, DBGDIDR, VERSION, 10); /* FEAT_Debugv8p8 */ - t = FIELD_DP32(t, DBGDIDR, CTX_CMPS, 1); - t = FIELD_DP32(t, DBGDIDR, BRPS, 5); - t = FIELD_DP32(t, DBGDIDR, WRPS, 3); - cpu->isar.dbgdidr = t; - - t = 0; - t = FIELD_DP32(t, DBGDEVID, PCSAMPLE, 3); - t = FIELD_DP32(t, DBGDEVID, WPADDRMASK, 1); - t = FIELD_DP32(t, DBGDEVID, BPADDRMASK, 15); - t = FIELD_DP32(t, DBGDEVID, VECTORCATCH, 0); - t = FIELD_DP32(t, DBGDEVID, VIRTEXTNS, 1); - t = FIELD_DP32(t, DBGDEVID, DOUBLELOCK, 1); - t = FIELD_DP32(t, DBGDEVID, AUXREGS, 0); - t = FIELD_DP32(t, DBGDEVID, CIDMASK, 0); - cpu->isar.dbgdevid = t; - - /* Bits[31:4] are RES0. */ - t = 0; - t = FIELD_DP32(t, DBGDEVID1, PCSROFFSET, 2); - cpu->isar.dbgdevid1 = t; - - FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ -} - /* * -cpu max: a CPU with as many features enabled as our emulation supports. * The version of '-cpu max' for qemu-system-aarch64 is defined in cpu64.c; diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index e1ff074b47..d5dd236152 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -749,6 +749,102 @@ type_init(arm_tcg_cpu_register_types) #endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */ +/* Share AArch32 -cpu max features with AArch64. */ +void aa32_max_features(ARMCPU *cpu) +{ + uint32_t t; + ARMISARegisters *isar = &cpu->isar; + + /* Add additional features supported by QEMU */ + t = GET_IDREG(isar, ID_ISAR5); + t = FIELD_DP32(t, ID_ISAR5, AES, 2); /* FEAT_PMULL */ + t = FIELD_DP32(t, ID_ISAR5, SHA1, 1); /* FEAT_SHA1 */ + t = FIELD_DP32(t, ID_ISAR5, SHA2, 1); /* FEAT_SHA256 */ + t = FIELD_DP32(t, ID_ISAR5, CRC32, 1); + t = FIELD_DP32(t, ID_ISAR5, RDM, 1); /* FEAT_RDM */ + t = FIELD_DP32(t, ID_ISAR5, VCMA, 1); /* FEAT_FCMA */ + SET_IDREG(isar, ID_ISAR5, t); + + t = GET_IDREG(isar, ID_ISAR6); + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); /* FEAT_JSCVT */ + t = FIELD_DP32(t, ID_ISAR6, DP, 1); /* Feat_DotProd */ + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); /* FEAT_FHM */ + t = FIELD_DP32(t, ID_ISAR6, SB, 1); /* FEAT_SB */ + t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1); /* FEAT_SPECRES */ + t = FIELD_DP32(t, ID_ISAR6, BF16, 1); /* FEAT_AA32BF16 */ + t = FIELD_DP32(t, ID_ISAR6, I8MM, 1); /* FEAT_AA32I8MM */ + SET_IDREG(isar, ID_ISAR6, t); + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ + t = FIELD_DP32(t, MVFR1, SIMDHP, 2); /* FEAT_FP16 */ + cpu->isar.mvfr1 = t; + + t = cpu->isar.mvfr2; + t = FIELD_DP32(t, MVFR2, SIMDMISC, 3); /* SIMD MaxNum */ + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + + FIELD_DP32_IDREG(isar, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ + + t = GET_IDREG(isar, ID_MMFR4); + t = FIELD_DP32(t, ID_MMFR4, HPDS, 2); /* FEAT_HPDS2 */ + t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ + t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ + t = FIELD_DP32(t, ID_MMFR4, EVT, 2); /* FEAT_EVT2 */ + SET_IDREG(isar, ID_MMFR4, t); + + FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 2); /* FEAT_ETS2 */ + + t = GET_IDREG(isar, ID_PFR0); + t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CSV2 */ + t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ + SET_IDREG(isar, ID_PFR0, t); + + t = GET_IDREG(isar, ID_PFR2); + t = FIELD_DP32(t, ID_PFR2, CSV3, 1); /* FEAT_CSV3 */ + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ + SET_IDREG(isar, ID_PFR2, t); + + t = GET_IDREG(isar, ID_DFR0); + t = FIELD_DP32(t, ID_DFR0, COPDBG, 10); /* FEAT_Debugv8p8 */ + t = FIELD_DP32(t, ID_DFR0, COPSDBG, 10); /* FEAT_Debugv8p8 */ + t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ + SET_IDREG(isar, ID_DFR0, t); + + /* Debug ID registers. */ + + /* Bit[15] is RES1, Bit[13] and Bits[11:0] are RES0. */ + t = 0x00008000; + t = FIELD_DP32(t, DBGDIDR, SE_IMP, 1); + t = FIELD_DP32(t, DBGDIDR, NSUHD_IMP, 1); + t = FIELD_DP32(t, DBGDIDR, VERSION, 10); /* FEAT_Debugv8p8 */ + t = FIELD_DP32(t, DBGDIDR, CTX_CMPS, 1); + t = FIELD_DP32(t, DBGDIDR, BRPS, 5); + t = FIELD_DP32(t, DBGDIDR, WRPS, 3); + cpu->isar.dbgdidr = t; + + t = 0; + t = FIELD_DP32(t, DBGDEVID, PCSAMPLE, 3); + t = FIELD_DP32(t, DBGDEVID, WPADDRMASK, 1); + t = FIELD_DP32(t, DBGDEVID, BPADDRMASK, 15); + t = FIELD_DP32(t, DBGDEVID, VECTORCATCH, 0); + t = FIELD_DP32(t, DBGDEVID, VIRTEXTNS, 1); + t = FIELD_DP32(t, DBGDEVID, DOUBLELOCK, 1); + t = FIELD_DP32(t, DBGDEVID, AUXREGS, 0); + t = FIELD_DP32(t, DBGDEVID, CIDMASK, 0); + cpu->isar.dbgdevid = t; + + /* Bits[31:4] are RES0. */ + t = 0; + t = FIELD_DP32(t, DBGDEVID1, PCSROFFSET, 2); + cpu->isar.dbgdevid1 = t; + + FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ +} + void aarch32_max_tcg_init(ARMCPU *cpu) { aarch64_aa32_a57_init(cpu, false); From 8d346a7109ac692edc4cb80c6a450a0076ed87af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 442/627] target/arm: Annotate arch revisions in aarch64_max_tcg_initfn Annotate the minimum revion from which each feature is OPTIONAL. Modulo some sorting of properties at the end, comment changes only. Signed-off-by: Richard Henderson Message-id: 20260812204435.295067-10-richard.henderson@linaro.org [PMM: fixed two minor comment issues] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/tcg/cpu64.c | 303 +++++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 144 deletions(-) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 5649b853a7..9ce514dda8 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1226,199 +1226,202 @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, CTR_EL0, DIC, 1); cpu->ctr = t; + /* + * Below, note the revision from which the feature is OPTIONAL. + */ t = GET_IDREG(isar, ID_AA64ISAR0); - t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ - t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); /* FEAT_CRC32 */ - t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 3); /* FEAT_LSE, FEAT_LSE128 */ - t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ - t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* FEAT_SM3 */ - t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* FEAT_SM4 */ - t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* FEAT_DotProd */ - t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* FEAT_FHM */ - t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* FEAT_FlagM2 */ - t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* FEAT_TLBIRANGE */ - t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* v8.0: FEAT_PMULL */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* v8.0: FEAT_SHA1 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* v8.1: FEAT_SHA512 */ + t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); /* v8.0: FEAT_CRC32 */ + t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 3); /* v9.3: FEAT_LSE128 */ + t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* v8.0: FEAT_RDM */ + t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* v8.1: FEAT_SHA3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); /* v8.1: FEAT_SM3 */ + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); /* v8.1: FEAT_SM4 */ + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); /* v8.1: FEAT_DotProd */ + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); /* v8.1: FEAT_FHM */ + t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.4: FEAT_FlagM2 */ + t = FIELD_DP64(t, ID_AA64ISAR0, TLB, 2); /* v8.3: FEAT_TLBIRANGE */ + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* v8.4: FEAT_RNG */ SET_IDREG(isar, ID_AA64ISAR0, t); t = GET_IDREG(isar, ID_AA64ISAR1); - t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ - t = FIELD_DP64(t, ID_AA64ISAR1, APA, PauthFeat_FPACCOMBINED); + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* v8.1: FEAT_DPB2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, APA, PauthFeat_FPACCOMBINED); /* v8.2 */ t = FIELD_DP64(t, ID_AA64ISAR1, API, 1); - t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* FEAT_JSCVT */ - t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* FEAT_FCMA */ - t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* FEAT_LRCPC2 */ - t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */ - t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */ - t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */ - t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 2); /* FEAT_BF16, FEAT_EBF16 */ - t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ - t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ - t = FIELD_DP64(t, ID_AA64ISAR1, XS, 1); /* FEAT_XS */ + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); /* v8.2: FEAT_JSCVT */ + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); /* v8.2: FEAT_FCMA */ + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* v8.2: FEAT_LRCPC2 */ + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* v8.4: FEAT_FRINTTS */ + t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* v8.0: FEAT_SB */ + t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* v8.0: FEAT_SPECRES */ + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 2); /* v8.2: FEAT_EBF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* v8.0: FEAT_DGH */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* v8.1: FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ISAR1, XS, 1); /* v8.6: FEAT_XS */ SET_IDREG(isar, ID_AA64ISAR1, t); t = GET_IDREG(isar, ID_AA64ISAR2); - t = FIELD_DP64(t, ID_AA64ISAR2, RPRES, 1); /* FEAT_RPRES */ - t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* FEAT_MOPS */ - t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */ - t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* FEAT_WFxT */ - t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* FEAT_CSSC, FEAT_CMPBR */ - t = FIELD_DP64(t, ID_AA64ISAR2, LUT, 1); /* FEAT_LUT */ - t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* FEAT_ATS1A */ + t = FIELD_DP64(t, ID_AA64ISAR2, RPRES, 1); /* v8.6: FEAT_RPRES */ + t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* v8.7: FEAT_MOPS */ + t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* v8.7: FEAT_HBC */ + t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* v8.6: FEAT_WFxT */ + t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* v9.3: FEAT_CMPBR */ + t = FIELD_DP64(t, ID_AA64ISAR2, LUT, 1); /* v9.2: FEAT_LUT */ + t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* v8.8: FEAT_ATS1A */ SET_IDREG(isar, ID_AA64ISAR2, t); 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 */ + t = FIELD_DP64(t, ID_AA64ISAR3, FAMINMAX, 1); /* v9.2: FEAT_FAMINMAX */ + t = FIELD_DP64(t, ID_AA64ISAR3, FPRCVT, 1); /* v9.5: FEAT_FPRCVT */ SET_IDREG(isar, ID_AA64ISAR3, t); t = GET_IDREG(isar, ID_AA64PFR0); - t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ - t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */ - t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */ - t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); - t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */ - t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ - t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 3); /* FEAT_CSV2_3 */ - t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* v8.2: FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* v8.2: FEAT_FP16 */ + t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* v8.3: FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1); /* v8.2: FEAT_SVE */ + t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* v8.3: FEAT_SEL2 */ + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* v8.3: FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 3); /* v8.0: FEAT_CSV2_3 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* v8.0: FEAT_CSV3 */ SET_IDREG(isar, ID_AA64PFR0, t); t = GET_IDREG(isar, ID_AA64PFR1); - t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* FEAT_BTI */ - t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* FEAT_SSBS2 */ + t = FIELD_DP64(t, ID_AA64PFR1, BT, 1); /* v8.4: FEAT_BTI */ + t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2); /* v8.0: FEAT_SSBS2 */ /* * Begin with full support for MTE. This will be downgraded to MTE=0 * during realize if the board provides no tag memory, much like * we do for EL2 with the virtualization=on property. */ - t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */ - t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ - t = FIELD_DP64(t, ID_AA64PFR1, SME, 2); /* FEAT_SME2 */ - t = FIELD_DP64(t, ID_AA64PFR1, RNDR_TRAP, 1); /* FEAT_RNG_TRAP */ - t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */ - t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* FEAT_NMI */ - t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* FEAT_GCS */ - /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */ + t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* v8.5: FEAT_MTE3 */ + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* v8.3: FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR1, SME, 2); /* v9.2: FEAT_SME2 */ + t = FIELD_DP64(t, ID_AA64PFR1, RNDR_TRAP, 1); /* v8.4: FEAT_RNG_TRAP */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* v8.0: FEAT_CSV2_3 */ + t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* v8.7: FEAT_NMI */ + t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* v9.3: FEAT_GCS */ + /* v8.7: FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */ t = FIELD_DP64(t, ID_AA64PFR1, MTEX, 1); SET_IDREG(isar, ID_AA64PFR1, t); t = GET_IDREG(isar, ID_AA64PFR2); - t = FIELD_DP64(t, ID_AA64PFR2, FPMR, 1); /* FEAT_FPMR */ - t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1); /* FEAT_MTE_TAGGED_FAR */ - t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 1); /* FEAT_MTE_STORE_ONLY */ - t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 1); /* FEAT_MTE_PERM */ + t = FIELD_DP64(t, ID_AA64PFR2, FPMR, 1); /* v9.2: FEAT_FPMR */ + t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1); /* v8.7: FEAT_MTE_TAGGED_FAR */ + t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 1); /* v8.7: FEAT_MTE_STORE_ONLY */ + t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 1); /* v8.7: FEAT_MTE_PERM */ SET_IDREG(isar, ID_AA64PFR2, t); t = GET_IDREG(isar, ID_AA64MMFR0); - t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1); /* 16k pages supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */ - t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */ - t = FIELD_DP64(t, ID_AA64MMFR0, ECV, 2); /* FEAT_ECV */ + t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* v8.1: FEAT_LPA: 52 bits */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1); /* v8.0: FEAT_TGran16K */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* v8.0: FEAT_S2TGran16K */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* v8.0: FEAT_S2TGran64K */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* v8.0: FEAT_S2TGran4K */ + t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* v8.5: FEAT_FGT */ + t = FIELD_DP64(t, ID_AA64MMFR0, ECV, 2); /* v8.5: FEAT_ECV_POFF */ SET_IDREG(isar, ID_AA64MMFR0, t); t = GET_IDREG(isar, ID_AA64MMFR1); - t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* FEAT_HAFDBS */ - t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ - t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 2); /* FEAT_HPDS2 */ - t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ - t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 3); /* FEAT_PAN3 */ - t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ - t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2); /* FEAT_ETS2 */ - t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ - t = FIELD_DP64(t, ID_AA64MMFR1, AFP, 1); /* FEAT_AFP */ - t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* FEAT_TIDCP1 */ - t = FIELD_DP64(t, ID_AA64MMFR1, CMOW, 1); /* FEAT_CMOW */ + t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* v8.0: FEAT_HAFDBS */ + t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* v8.0: FEAT_VMID16 */ + t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* v8.0: FEAT_VHE */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 2); /* v8.1: FEAT_HPDS2 */ + t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* v8.0: FEAT_LOR */ + t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 3); /* v8.1: FEAT_PAN3 */ + t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* v8.1: FEAT_XNX */ + t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2); /* v8.0: FEAT_ETS2 */ + t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* v8.6: FEAT_HCX */ + t = FIELD_DP64(t, ID_AA64MMFR1, AFP, 1); /* v8.6: FEAT_AFP */ + t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* v8.7: FEAT_TIDCP1 */ + t = FIELD_DP64(t, ID_AA64MMFR1, CMOW, 1); /* v8.7: FEAT_CMOW */ SET_IDREG(isar, ID_AA64MMFR1, t); t = GET_IDREG(isar, ID_AA64MMFR2); - t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* FEAT_TTCNP */ - t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* FEAT_UAO */ - t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */ - t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */ - t = FIELD_DP64(t, ID_AA64MMFR2, NV, 2); /* FEAT_NV2 */ - t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */ - t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1); /* FEAT_LSE2 */ - t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */ - t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */ - t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */ - t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* FEAT_BBM at level 2 */ - t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* FEAT_EVT */ - t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* v8.1: FEAT_TTCNP */ + t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); /* v8.1: FEAT_UAO */ + t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* v8.1: FEAT_IESB */ + t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* v8.1: FEAT_LVA */ + t = FIELD_DP64(t, ID_AA64MMFR2, NV, 2); /* v8.3: FEAT_NV2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* v8.3: FEAT_TTST */ + t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1); /* v8.2: FEAT_LSE2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* v8.3: FEAT_IDST */ + t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* v8.3: FEAT_S2FWB */ + t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* v8.3: FEAT_TTL */ + t = FIELD_DP64(t, ID_AA64MMFR2, BBM, 2); /* v8.3: FEAT_BBML2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, EVT, 2); /* v8.2: FEAT_EVT2 */ + t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* v8.4: FEAT_E0PD */ SET_IDREG(isar, ID_AA64MMFR2, t); t = GET_IDREG(isar, ID_AA64MMFR3); - t = FIELD_DP64(t, ID_AA64MMFR3, TCRX, 1); /* FEAT_TCR2 */ - t = FIELD_DP64(t, ID_AA64MMFR3, SCTLRX, 1); /* FEAT_SCTLR2 */ - t = FIELD_DP64(t, ID_AA64MMFR3, MEC, 1); /* FEAT_MEC */ - t = FIELD_DP64(t, ID_AA64MMFR3, SPEC_FPACC, 1); /* FEAT_FPACC_SPEC */ - t = FIELD_DP64(t, ID_AA64MMFR3, S1PIE, 1); /* FEAT_S1PIE */ - t = FIELD_DP64(t, ID_AA64MMFR3, S2PIE, 1); /* FEAT_S2PIE */ - t = FIELD_DP64(t, ID_AA64MMFR3, AIE, 1); /* FEAT_AIE */ + t = FIELD_DP64(t, ID_AA64MMFR3, TCRX, 1); /* v8.0: FEAT_TCR2 */ + t = FIELD_DP64(t, ID_AA64MMFR3, SCTLRX, 1); /* v8.0: FEAT_SCTLR2 */ + t = FIELD_DP64(t, ID_AA64MMFR3, MEC, 1); /* v9.2: FEAT_MEC */ + t = FIELD_DP64(t, ID_AA64MMFR3, SPEC_FPACC, 1); /* v8.2: FEAT_FPACC_SPEC */ + t = FIELD_DP64(t, ID_AA64MMFR3, S1PIE, 1); /* v8.8: FEAT_S1PIE */ + t = FIELD_DP64(t, ID_AA64MMFR3, S2PIE, 1); /* v8.8: FEAT_S2PIE */ + t = FIELD_DP64(t, ID_AA64MMFR3, AIE, 1); /* v8.8: FEAT_AIE */ SET_IDREG(isar, ID_AA64MMFR3, t); t = GET_IDREG(isar, ID_AA64MMFR4); - t = FIELD_DP64(t, ID_AA64MMFR4, ASID2, 1); /* FEAT_ASID2 */ + t = FIELD_DP64(t, ID_AA64MMFR4, ASID2, 1); /* v9.4: FEAT_ASID2 */ SET_IDREG(isar, ID_AA64MMFR4, t); t = GET_IDREG(isar, ID_AA64ZFR0); - t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* FEAT_SVE2p1 */ - t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ - t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ - t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 2); /* FEAT_BF16, FEAT_EBF16 */ - t = FIELD_DP64(t, ID_AA64ZFR0, B16B16, 1); /* FEAT_SVE_B16B16 */ - t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */ - t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */ - t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */ - t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* FEAT_F32MM */ - t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* v9.2: FEAT_SVE2p1 */ + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* v9.0: FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* v9.0: FEAT_SVE_BitPerm */ + t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 2); /* v8.2: FEAT_EBF16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, B16B16, 1); /* v9.2: FEAT_SVE_B16B16 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* v9.0: FEAT_SVE_SHA3 */ + t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* v9.0: FEAT_SVE_SM4 */ + t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* v8.1: FEAT_I8MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F32MM, 1); /* v8.2: FEAT_F32MM */ + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* v8.2: FEAT_F64MM */ SET_IDREG(isar, ID_AA64ZFR0, t); t = GET_IDREG(isar, ID_AA64DFR0); - t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 10); /* FEAT_Debugv8p8 */ - t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ - t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* FEAT_HPMN0 */ + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 10); /* v8.7: FEAT_Debugv8p8 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* v8.4: FEAT_PMUv3p5 */ + t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* v8.5: FEAT_HPMN0 */ SET_IDREG(isar, ID_AA64DFR0, t); t = GET_IDREG(isar, ID_AA64SMFR0); - t = FIELD_DP64(t, ID_AA64SMFR0, SMOP4, 1); /* FEAT_SME_MOP4 */ - t = FIELD_DP64(t, ID_AA64SMFR0, STMOP, 1); /* FEAT_SME_TMOP */ - 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 */ - t = FIELD_DP64(t, ID_AA64SMFR0, SF8FMA, 1); /* FEAT_SSVE_FP8FMA */ - t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, BI32I32, 1); /* FEAT_SME2 */ - t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, I8I32, 0xf); /* FEAT_SME */ - t = FIELD_DP64(t, ID_AA64SMFR0, F8F32, 1); /* FEAT_SME_F8F32 */ - t = FIELD_DP64(t, ID_AA64SMFR0, F8F16, 1); /* FEAT_SME_F8F16 */ - t = FIELD_DP64(t, ID_AA64SMFR0, F16F16, 1); /* FEAT_SME_F16F16 */ - t = FIELD_DP64(t, ID_AA64SMFR0, B16B16, 1); /* FEAT_SME_B16B16 */ - t = FIELD_DP64(t, ID_AA64SMFR0, I16I32, 5); /* FEAT_SME2 */ - t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* FEAT_SME_F64F64 */ - t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */ - t = FIELD_DP64(t, ID_AA64SMFR0, SMEVER, 2); /* FEAT_SME2p1 */ - t = FIELD_DP64(t, ID_AA64SMFR0, LUTv2, 1); /* FEAT_SME_LUTv2 */ - t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, SMOP4, 1); /* v9.4: FEAT_SME_MOP4 */ + t = FIELD_DP64(t, ID_AA64SMFR0, STMOP, 1); /* v9.4: FEAT_SME_TMOP */ + t = FIELD_DP64(t, ID_AA64SMFR0, SFEXPA, 1); /* v9.4: FEAT_SSVE_FEXPA */ + t = FIELD_DP64(t, ID_AA64SMFR0, AES, 1); /* v9.5: FEAT_SSVE_AES */ + t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP2, 1); /* v9.2: FEAT_SSVE_FP8DOT2 */ + t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP4, 1); /* v9.2: FEAT_SSVE_FP8DOT4 */ + t = FIELD_DP64(t, ID_AA64SMFR0, SF8FMA, 1); /* v9.2: FEAT_SSVE_FP8FMA */ + t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* v9.2: FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, BI32I32, 1); /* v9.2: FEAT_SME2 */ + t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* v9.2: FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* v9.2: FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, I8I32, 0xf); /* v9.2: FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F8F32, 1); /* v9.2: FEAT_SME_F8F32 */ + t = FIELD_DP64(t, ID_AA64SMFR0, F8F16, 1); /* v9.2: FEAT_SME_F8F16 */ + t = FIELD_DP64(t, ID_AA64SMFR0, F16F16, 1); /* v9.2: FEAT_SME_F16F16 */ + t = FIELD_DP64(t, ID_AA64SMFR0, B16B16, 1); /* v9.2: FEAT_SME_B16B16 */ + t = FIELD_DP64(t, ID_AA64SMFR0, I16I32, 5); /* v9.2: FEAT_SME2 */ + t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* v9.2: FEAT_SME_F64F64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* v9.2: FEAT_SME_I16I64 */ + t = FIELD_DP64(t, ID_AA64SMFR0, SMEVER, 2); /* v9.2: FEAT_SME2p1 */ + t = FIELD_DP64(t, ID_AA64SMFR0, LUTv2, 1); /* v9.2: FEAT_SME_LUTv2 */ + t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* v9.2: FEAT_SME_FA64 */ SET_IDREG(isar, ID_AA64SMFR0, t); t = GET_IDREG(isar, ID_AA64FPFR0); - t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8MM4, 1); /* FEAT_F8F16MM */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8MM8, 1); /* FEAT_F8F32MM */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8DP2, 1); /* FEAT_FP8DOT2 */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* FEAT_FP8DOT4 */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* FEAT_FP8FMA */ - t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* v9.2: FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* v9.2: FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8MM4, 1); /* v9.2: FEAT_F8F16MM */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8MM8, 1); /* v9.2: FEAT_F8F32MM */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8DP2, 1); /* v9.2: FEAT_FP8DOT2 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* v9.2: FEAT_FP8DOT4 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* v9.2: FEAT_FP8FMA */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* v9.2: FEAT_FP8 */ SET_IDREG(isar, ID_AA64FPFR0, t); /* Replicate the same data to the 32-bit id registers. */ @@ -1432,19 +1435,31 @@ void aarch64_max_tcg_initfn(Object *obj) cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ set_dczid_bs(cpu, 7); /* 512 bytes */ #endif + + /* v8.4: FEAT_MTE2 */ cpu->gm_blocksize = 6; /* 256 bytes */ + /* v8.2: FEAT_SVE */ cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); - cpu->sme_vq.supported = SVE_VQ_POW2_MAP; - - aarch64_add_pauth_properties(obj); aarch64_add_sve_properties(obj); - aarch64_add_sme_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq, NULL, NULL); + + /* v9.2: FEAT_SME */ + cpu->sme_vq.supported = SVE_VQ_POW2_MAP; + aarch64_add_sme_properties(obj); + + /* v8.2: FEAT_PAuth2 */ + aarch64_add_pauth_properties(obj); + + /* v9.1: FEAT_RME */ object_property_add_bool(obj, "x-rme", cpu_arm_get_rme, cpu_arm_set_rme); + + /* v9.4: FEAT_RME_GPC2 */ object_property_add(obj, "x-l0gptsz", "uint32", cpu_max_get_l0gptsz, cpu_max_set_l0gptsz, NULL, NULL); + + /* v8.6: FEAT_LPA2 */ qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); } From 4b263689baafeb3976a0cdeef35deaea8f0190e9 Mon Sep 17 00:00:00 2001 From: Simon Xu Date: Tue, 18 Aug 2026 10:39:08 +0100 Subject: [PATCH 443/627] hw/misc/iotkit-secctl.c: fix AHB secure read Fix AHB secure privilege to read AHB instead of APB. Fixes: b3717c23e1c0 ("hw/misc/iotkit-secctl: Add handling for PPCs") Reviewed-by: Owen Giles Reviewed-by: Robert Elliott Signed-off-by: Simon Xu Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/misc/iotkit-secctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 54bfe1ba59..93753c2ced 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -195,7 +195,7 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, case A_AHBSPPPCEXP1: case A_AHBSPPPCEXP2: case A_AHBSPPPCEXP3: - r = s->apbexp[offset_to_ppc_idx(offset)].sp; + r = s->ahbexp[offset_to_ppc_idx(offset)].sp; break; case A_APBSPPPC0: case A_APBSPPPC1: From b4f6f672a3e100706ddc249c26c2c149cdac1636 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 12:15:38 -0700 Subject: [PATCH 444/627] tcg: Export tcg_gen_ussub_i{32,64,tl} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move from tcg-op-gvec.c to tcg-op.c. Use a temporary, to cover the possibility of operand overlap. (Cc for stable as this is a prerequisite for the bug fix in the next commit.) Cc: qemu-stable@nongnu.org Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260811191540.79882-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- include/tcg/tcg-op-common.h | 2 ++ include/tcg/tcg-op.h | 2 ++ tcg/tcg-op-gvec.c | 14 -------------- tcg/tcg-op.c | 20 ++++++++++++++++++++ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index f7b6aadb50..9b321f959c 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -163,6 +163,7 @@ void tcg_gen_smin_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_smax_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_umin_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_umax_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); +void tcg_gen_ussub_i32(TCGv_i32, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_abs_i32(TCGv_i32, TCGv_i32); void tcg_gen_revbit8_i32(TCGv_i32 ret, TCGv_i32 arg); void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg); @@ -276,6 +277,7 @@ void tcg_gen_smin_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_smax_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_umin_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_umax_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); +void tcg_gen_ussub_i64(TCGv_i64, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_abs_i64(TCGv_i64, TCGv_i64); void tcg_gen_revbit8_i64(TCGv_i64 ret, TCGv_i64 arg); void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 568b78fe81..3721164236 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -153,6 +153,7 @@ typedef TCGv_i64 TCGv; #define tcg_gen_umin_tl tcg_gen_umin_i64 #define tcg_gen_smax_tl tcg_gen_smax_i64 #define tcg_gen_umax_tl tcg_gen_umax_i64 +#define tcg_gen_ussub_tl tcg_gen_ussub_i64 #define tcg_gen_atomic_cmpxchg_tl tcg_gen_atomic_cmpxchg_i64 #define tcg_gen_atomic_xchg_tl tcg_gen_atomic_xchg_i64 #define tcg_gen_atomic_fetch_add_tl tcg_gen_atomic_fetch_add_i64 @@ -275,6 +276,7 @@ typedef TCGv_i64 TCGv; #define tcg_gen_umin_tl tcg_gen_umin_i32 #define tcg_gen_smax_tl tcg_gen_smax_i32 #define tcg_gen_umax_tl tcg_gen_umax_i32 +#define tcg_gen_ussub_tl tcg_gen_ussub_i32 #define tcg_gen_atomic_cmpxchg_tl tcg_gen_atomic_cmpxchg_i32 #define tcg_gen_atomic_xchg_tl tcg_gen_atomic_xchg_i32 #define tcg_gen_atomic_fetch_add_tl tcg_gen_atomic_fetch_add_i32 diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index bc323e2500..27f3807b00 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2399,20 +2399,6 @@ void tcg_gen_gvec_usadd(unsigned vece, uint32_t dofs, uint32_t aofs, tcg_gen_gvec_3(dofs, aofs, bofs, oprsz, maxsz, &g[vece]); } -static void tcg_gen_ussub_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) -{ - TCGv_i32 min = tcg_constant_i32(0); - tcg_gen_sub_i32(d, a, b); - tcg_gen_movcond_i32(TCG_COND_LTU, d, a, b, min, d); -} - -static void tcg_gen_ussub_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) -{ - TCGv_i64 min = tcg_constant_i64(0); - tcg_gen_sub_i64(d, a, b); - tcg_gen_movcond_i64(TCG_COND_LTU, d, a, b, min, d); -} - void tcg_gen_gvec_ussub(unsigned vece, uint32_t dofs, uint32_t aofs, uint32_t bofs, uint32_t oprsz, uint32_t maxsz) { diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index e28944cf72..28d3b2a847 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1328,6 +1328,16 @@ void tcg_gen_umax_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) } } +void tcg_gen_ussub_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i32 t = tcg_temp_ebb_new_i32(); + TCGv_i32 z = tcg_constant_i32(0); + + tcg_gen_sub_i32(t, a, b); + tcg_gen_movcond_i32(TCG_COND_LTU, ret, a, b, z, t); + tcg_temp_free_i32(t); +} + void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) { TCGv_i32 t = tcg_temp_ebb_new_i32(); @@ -2523,6 +2533,16 @@ void tcg_gen_umax_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) } } +void tcg_gen_ussub_i64(TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) +{ + TCGv_i64 t = tcg_temp_ebb_new_i64(); + TCGv_i64 z = tcg_constant_i64(0); + + tcg_gen_sub_i64(t, a, b); + tcg_gen_movcond_i64(TCG_COND_LTU, ret, a, b, z, t); + tcg_temp_free_i64(t); +} + void tcg_gen_abs_i64(TCGv_i64 ret, TCGv_i64 a) { TCGv_i64 t = tcg_temp_ebb_new_i64(); From bab972a2b0e34b889fbe8deb1e41cbea47e797f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 12:15:39 -0700 Subject: [PATCH 445/627] target/arm: Fix SVE2 WHILEWR/WHILERW zero diff boundary case The trans_WHILE_ptr function incorrectly handles the case where the address difference divided by ESIZE results in zero. This happens when the address difference is less than ESIZE but greater than zero. Fix by dropping direct comparisons of op0 vs op1, and instead testing the scaled diff vs 0. Merge with the bounding to the maximum vector length via wrapping arithmetic. Cc: qemu-stable@nongnu.org Fixes: 14f6dad168e ("target/arm: Implement SVE2 WHILERW, WHILEWR") Reported-by: YanjunYang Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260811191540.79882-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/translate-sve.c | 38 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index fc4cc8c479..0becef16a9 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -3697,7 +3697,7 @@ TRANS_FEAT(WHILE_gt_cnt4, aa64_sme2_or_sve2p1, do_WHILE, static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) { - TCGv_i64 op0, op1, diff, t1, tmax; + TCGv_i64 op0, op1, diff, t1; TCGv_i32 t2; TCGv_ptr ptr; unsigned vsz = vec_full_reg_size(s); @@ -3713,7 +3713,6 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) op0 = read_cpu_reg(s, a->rn, 1); op1 = read_cpu_reg(s, a->rm, 1); - tmax = tcg_constant_i64(vsz >> a->esz); diff = tcg_temp_new_i64(); if (a->rw) { @@ -3723,25 +3722,36 @@ static bool trans_WHILE_ptr(DisasContext *s, arg_WHILE_ptr *a) tcg_gen_sub_i64(diff, op0, op1); tcg_gen_sub_i64(t1, op1, op0); tcg_gen_movcond_i64(TCG_COND_GEU, diff, op0, op1, diff, t1); - /* Divide, rounding down, by ESIZE. */ - tcg_gen_shri_i64(diff, diff, a->esz); - /* If op1 == op0, diff == 0, and the condition is always true. */ - tcg_gen_movcond_i64(TCG_COND_EQ, diff, op0, op1, tmax, diff); } else { /* WHILEWR */ - tcg_gen_sub_i64(diff, op1, op0); - /* Divide, rounding down, by ESIZE. */ - tcg_gen_shri_i64(diff, diff, a->esz); - /* If op0 >= op1, diff <= 0, the condition is always true. */ - tcg_gen_movcond_i64(TCG_COND_GEU, diff, op0, op1, tmax, diff); + /* Saturating subtraction maps diff <= 0 to diff == 0. */ + tcg_gen_ussub_i64(diff, op1, op0); } - /* Bound to the maximum. */ - tcg_gen_umin_i64(diff, diff, tmax); + /* Divide, rounding down, by ESIZE. */ + tcg_gen_shri_i64(diff, diff, a->esz); - /* Since we're bounded, pass as a 32-bit type. */ + /* + * If diff == 0, the condition is always true. Also, bound to max. + * Simplify + * diff = diff ? diff : max; + * diff = umin(diff, max); + * via + * diff -= 1; + * diff = umin(diff, max - 1); + * diff += 1; + * via 0 - 1 == UINT64_MAX. + */ + tcg_gen_addi_i64(diff, diff, -1); + tcg_gen_umin_i64(diff, diff, tcg_constant_i64((vsz >> a->esz) - 1)); + + /* + * Since we're bounded, pass as a 32-bit type. + * Sink the diff += 1 from above into the 32-bit type. + */ t2 = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(t2, diff); + tcg_gen_addi_i32(t2, t2, 1); desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz / 8); desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz); From 32953700108cc3305f27b591d66b5fb73806266a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Aug 2026 12:15:40 -0700 Subject: [PATCH 446/627] tests/tcg/aarch64: Add regression test for whilewr/whilerw Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20260811191540.79882-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- tests/tcg/aarch64/Makefile.target | 5 +++-- tests/tcg/aarch64/sve-while-ptr.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/aarch64/sve-while-ptr.c diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 32f2689273..6cc81bf854 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -203,8 +203,9 @@ endif endif ifneq ($(CROSS_CC_HAS_SVE2),) -AARCH64_TESTS += test-826 -test-826: CFLAGS += $(CROSS_CC_HAS_SVE2) +SVE2_TESTS = test-826 sve-while-ptr +$(SVE2_TESTS): CFLAGS += $(CROSS_CC_HAS_SVE2) +AARCH64_TESTS += $(SVE2_TESTS) endif TESTS += $(AARCH64_TESTS) diff --git a/tests/tcg/aarch64/sve-while-ptr.c b/tests/tcg/aarch64/sve-while-ptr.c new file mode 100644 index 0000000000..7db3b9cc03 --- /dev/null +++ b/tests/tcg/aarch64/sve-while-ptr.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* WHILEWR / WHILERW regression test */ + +#include +#include + +int main(int argc, char **argv) +{ + unsigned short p; + int set_vl_ret; + + set_vl_ret = prctl(PR_SVE_SET_VL, 16, 0, 0, 0, 0); + assert(set_vl_ret == 16); + + p = 0xdead; + asm("whilewr p0.s, %0, %1\n\t" + "str p0, [%2]" + : : "r"(8), "r"(11), "r"(&p) : "memory", "p0"); + assert(p == 0x1111); + + p = 0xdead; + asm("whilerw p0.s, %0, %1\n\t" + "str p0, [%2]" + : : "r"(8), "r"(11), "r"(&p) : "memory", "p0"); + assert(p == 0x1111); + + return 0; +} From 4f50d637e23770872a997ed2de0729fbacc2c002 Mon Sep 17 00:00:00 2001 From: Doug Cook Date: Mon, 17 Aug 2026 19:09:06 +0000 Subject: [PATCH 447/627] hw/arm/ax3000-soc: fix heap overflow from missing class_size TYPE_AX3000_SOC declares an Ax3000SoCClass via OBJECT_DECLARE_TYPE() and ax3000_class_init() writes to it: Ax3000SoCClass *sc = AX3000_SOC_CLASS(oc); sc->num_cpus = AX3000_NUM_CPUS; but its TypeInfo omits .class_size, so type_initialize() only allocates class_size inherited from the parent, i.e. sizeof(SysBusDeviceClass). The store to sc->num_cpus therefore writes 4 bytes of the value 4 just past the end of the class allocation, corrupting whatever heap block follows it. Fix by setting class_size. Fixes: 33a71a68c6e1 ("hw/arm: Add Axiado SoC AX3000") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4197 Signed-off-by: Doug Cook Message-id: LVXPR21MB70090B04FF7397B0F2A201C8ADA72@LVXPR21MB7009.namprd21.prod.outlook.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/ax3000-soc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/ax3000-soc.c b/hw/arm/ax3000-soc.c index 71e31c6fb4..ebe174fb97 100644 --- a/hw/arm/ax3000-soc.c +++ b/hw/arm/ax3000-soc.c @@ -236,6 +236,7 @@ static const TypeInfo axiado_soc_types[] = { .instance_size = sizeof(Ax3000SoCState), .instance_init = ax3000_init, .class_init = ax3000_class_init, + .class_size = sizeof(Ax3000SoCClass), } }; From b3f00f492f8a9e6a750554cb6dcb21bdcfd80db9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:31 +0100 Subject: [PATCH 448/627] target/arm: Handle NSACR.NSASEDIS in CPACR accesses In cpacr_read() and cpacr_write() we have code that implements the "CPACR.{cp10,cp11} behave as RAZ/WI from NonSecure when NSACR.cp10 is 0" behaviour. There is a similar requirement for CPACR.ASEDIS: if NSACR.NSASEDIS is 1 then CPACR.ASEDIS behaves as RAO/WI in NS. This doesn't matter to us yet because we don't currently implement ASEDIS or NSASEDIS. But we're about to do that, so add the handling to cpacr_read() and cpacr_write(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-2-peter.maydell@linaro.org --- target/arm/helper.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index adae2b2b8e..6a707b80cf 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -588,11 +588,19 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* * For A-profile AArch32 EL3 (but not M-profile secure mode), if NSACR.CP10 * is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00. + * Similarly, if NSACR.NSASEDIS is 1 then CPACR.ASEDIS ignores writes + * and reads as 1. */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !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); + !arm_is_secure(env)) { + if (!FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { + mask = R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; + value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); + } + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { + mask = R_CPACR_ASEDIS_MASK; + value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); + } } env->cp15.cpacr_el1 = value; @@ -603,12 +611,18 @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) /* * For A-profile AArch32 EL3 (but not M-profile secure mode), if NSACR.CP10 * is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00. + * Similarly NSACR.NSASEDIS makes CPACR.ASEDIS read as 1. */ uint64_t value = env->cp15.cpacr_el1; if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !arm_is_secure(env) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { - value = ~(R_CPACR_CP11_MASK | R_CPACR_CP10_MASK); + !arm_is_secure(env)) { + if (!FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { + value = ~(R_CPACR_CP11_MASK | R_CPACR_CP10_MASK); + } + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { + value |= R_CPACR_ASEDIS_MASK; + } } return value; } From 653311eecdcbeae672bace9039b8c65745d1693c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:32 +0100 Subject: [PATCH 449/627] target/arm: Handle NSACR.NSASEDIS in HCPTR accesses In cptr_el2_read() and cptr_el2_write() we have code that implements the "HCPTR.{TCP10,TCP11} behave as RAO/WI from NonSecure when NSACR.cp10 is 0" behaviour. There is a similar requirement for HCPTR.TASE: if NSACR.NSASEDIS is 1 then CPACR.ASEDIS behaves as RAO/WI in NS. This doesn't matter to us yet because we don't currently implement ASEDIS or NSASEDIS. But we're about to do that, so add the handling to cptr_el2_read() and cptr_el2_write(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-3-peter.maydell@linaro.org --- target/arm/helper.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6a707b80cf..d582eeba57 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4117,11 +4117,18 @@ static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, /* * For A-profile AArch32 EL3, if NSACR.CP10 * is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1. + * Similarly, if NSACR.NSASEDIS is 1 then HCPTR.TASE behaves as RAO/WI. */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && - !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); + !arm_is_secure(env)) { + if (!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); + } + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { + uint64_t mask = R_HCPTR_TASE_MASK; + value = (value & ~mask) | (env->cp15.cptr_el[2] & mask); + } } env->cp15.cptr_el[2] = value; } @@ -4131,12 +4138,18 @@ static uint64_t cptr_el2_read(CPUARMState *env, const ARMCPRegInfo *ri) /* * For A-profile AArch32 EL3, if NSACR.CP10 * is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1. + * Similarly, if NSACR.NSASEDIS is 1 then HCPTR.TASE behaves as RAO/WI. */ 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) && !FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { - value |= R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; + !arm_is_secure(env)) { + if (!FIELD_EX32(env->cp15.nsacr, NSACR, CP10)) { + value |= R_HCPTR_TCP11_MASK | R_HCPTR_TCP10_MASK; + } + if (!FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { + value |= R_HCPTR_TASE_MASK; + } } return value; } From 11dacc5b839bd5661153b5855b423c4098c0e124 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:33 +0100 Subject: [PATCH 450/627] target/arm: Update confusing comment in cpacr_write() In cpacr_write() a comment says "In ARMv8 most bits of CPACR_EL1 are RES0", and the mask value is left at 0, implying that we enforce those RES0 bits. In fact we only enforce RES0 when ARM_FEATURE_V8 is not implemented, and for v8 and up we allow the guest to write any bits. The addition of architectural features in v8 and v9 has also resulted in the addition of new bits to CPACR_EL1, so "most bits are RES0" isn't really true any more. Update the comment to be a bit clearer. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-4-peter.maydell@linaro.org --- target/arm/helper.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d582eeba57..7de38d8201 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -554,7 +554,17 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, { uint32_t mask = 0; - /* In ARMv8 most bits of CPACR_EL1 are RES0. */ + /* + * The AArch64 view of CPACR_EL1 has a different layout to the old + * AArch32 one. We also need to permit the old AArch32 bits to be + * read and written so that an AArch64 EL2 hypervisor can set up + * the register for an AArch32 EL1 guest. So we choose not to + * enforce any RAZ/WI or RAO/WI bits for v8 based on feature + * presence/absence. + * + * For v7 the situation is a bit simpler and there we do choose to + * enforce RAZ/WI and RAO/WI. + */ if (!arm_feature(env, ARM_FEATURE_V8)) { /* * ARMv7 defines bits for unimplemented coprocessors as RAZ/WI. From fdf3c577a966e06e03ede48f17fa905f1ee07c40 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:34 +0100 Subject: [PATCH 451/627] target/arm: Add new feature ARM_FEATURE_NEON_TRAPS The traps configurable via CPACR.ASEDIS and HCPTR.TASE that trap only Neon instructions are unfortunately IMPDEF about whether they are implemented or not, and there is no ID register field that identifies whether they are present. In practice, they are present on every implementation I have checked except for the Cortex-A8 (which was the first CPU with Neon). Add a new feature ARM_FEATURE_NEON_TRAPS which we set on every ARM_FEATURE_NEON CPU except the Cortex-A8, and make the CPACR.ASEDIS and HCPTR.TASE bits RAZ/WI unless the CPU has ARM_FEATURE_NEON and ARM_FEATURE_NEON_TRAPS. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-5-peter.maydell@linaro.org --- target/arm/cpu-max.c | 1 + target/arm/cpu.h | 7 +++++++ target/arm/cpu64.c | 1 + target/arm/helper.c | 17 +++++++++++++++-- target/arm/tcg/cpu32.c | 8 ++++++++ target/arm/tcg/cpu64.c | 10 ++++++++++ 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu-max.c b/target/arm/cpu-max.c index 8d968336a8..4df52bcb08 100644 --- a/target/arm/cpu-max.c +++ b/target/arm/cpu-max.c @@ -23,6 +23,7 @@ void aarch64_aa32_a57_init(ARMCPU *cpu, bool aarch64_enabled) cpu->dtb_compatible = "arm,cortex-a57"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); if (aarch64_enabled) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c0492c8dfb..4f07332543 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2177,6 +2177,13 @@ enum arm_features { * CPU types added in future. */ ARM_FEATURE_BACKCOMPAT_CNTFRQ, /* 62.5MHz timer default */ + /* + * ARM_FEATURE_NEON_TRAPS should be set if the CPU implements the + * CPACR.ASEDIS and HCPTR.TASE bits for trapping A32 Neon. This + * is architecturally IMPDEF, but seems to be implemented by all + * ARM_FEATURE_NEON CPUs except the Cortex-A8. + */ + ARM_FEATURE_NEON_TRAPS, }; static inline int arm_feature(const CPUARMState *env, int feature) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index faaf3ab879..4e8c472530 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -699,6 +699,7 @@ static void aarch64_a53_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a53"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); diff --git a/target/arm/helper.c b/target/arm/helper.c index 7de38d8201..2dfbeae0ef 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -573,14 +573,20 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* VFP coprocessor: cp10 & cp11 [23:20] */ - mask |= R_CPACR_ASEDIS_MASK | - R_CPACR_D32DIS_MASK | + mask |= R_CPACR_D32DIS_MASK | R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; if (!arm_feature(env, ARM_FEATURE_NEON)) { /* ASEDIS [31] bit is RAO/WI */ value |= R_CPACR_ASEDIS_MASK; + mask |= R_CPACR_ASEDIS_MASK; + } else if (arm_feature(env, ARM_FEATURE_NEON_TRAPS)) { + /* + * bit is present unless CPU doesn't implement ASEDIS + * (in which case it is RAZ/WI; this is the Cortex-A8) + */ + mask |= R_CPACR_ASEDIS_MASK; } /* @@ -4124,6 +4130,13 @@ uint64_t arm_hcrx_el2_eff(CPUARMState *env) static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + if (!arm_feature(env, ARM_FEATURE_NEON_TRAPS)) { + /* + * If CPU doesn't implement HCPTR.TASE it's RAZ/WI. Note that + * NSACR.NSASEDIS being 1 overrides this. + */ + value &= ~R_HCPTR_TASE_MASK; + } /* * For A-profile AArch32 EL3, if NSACR.CP10 * is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1. diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index d5dd236152..724a954934 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -251,6 +251,10 @@ static void cortex_a8_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a8"; set_feature(&cpu->env, ARM_FEATURE_V7); set_feature(&cpu->env, ARM_FEATURE_NEON); + /* + * The Cortex-A8 doesn't have CPACR.ASEDIS and HCPTR.TASE, + * so don't set ARM_FEATURE_NEON_TRAPS. + */ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_EL3); @@ -321,6 +325,7 @@ static void cortex_a9_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a9"; set_feature(&cpu->env, ARM_FEATURE_V7); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_EL3); set_feature(&cpu->env, ARM_FEATURE_PMU); @@ -389,6 +394,7 @@ static void cortex_a7_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a7"; set_feature(&cpu->env, ARM_FEATURE_V7VE); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); @@ -439,6 +445,7 @@ static void cortex_a15_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a15"; set_feature(&cpu->env, ARM_FEATURE_V7VE); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); @@ -634,6 +641,7 @@ static void cortex_r52_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_PMSA); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 9ce514dda8..b38c61ba62 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -37,6 +37,7 @@ static void aarch64_a35_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a35"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -208,6 +209,7 @@ static void aarch64_a55_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a55"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -281,6 +283,7 @@ static void aarch64_a72_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a72"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -341,6 +344,7 @@ static void aarch64_a76_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a76"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -415,6 +419,7 @@ static void aarch64_a78ae_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a78ae"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_AARCH64); set_feature(&cpu->env, ARM_FEATURE_EL2); @@ -488,6 +493,7 @@ static void aarch64_a64fx_initfn(Object *obj) cpu->dtb_compatible = "arm,a64fx"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -662,6 +668,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) cpu->dtb_compatible = "arm,neoverse-n1"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -738,6 +745,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj) cpu->dtb_compatible = "arm,neoverse-v1"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -965,6 +973,7 @@ static void aarch64_a710_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a710"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -1067,6 +1076,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj) cpu->dtb_compatible = "arm,neoverse-n2"; set_feature(&cpu->env, ARM_FEATURE_V8); set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_NEON_TRAPS); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_BACKCOMPAT_CNTFRQ); set_feature(&cpu->env, ARM_FEATURE_AARCH64); From 284a3c29246097ce8d0afd8676371c97cd796188 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:35 +0100 Subject: [PATCH 452/627] target/arm: Implement CPACR.ASEDIS and HCPTR.TASE When executing at AArch32, there are optional trap bits for Neon instructions in CPACR and HCPTR. We don't currently implement these. Now we have a separate code path for access checks for Neon insns, we can straightforwardly add the check there. We need to track the target EL for Neon-specific trapping in a new TB flag. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1499 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-6-peter.maydell@linaro.org --- target/arm/cpu.h | 6 +++ target/arm/tcg/hflags.c | 82 ++++++++++++++++++++++++++++++++++ target/arm/tcg/translate-vfp.c | 16 +++++-- target/arm/tcg/translate.c | 1 + target/arm/tcg/translate.h | 1 + 5 files changed, 103 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 4f07332543..afc3fda3b8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2506,6 +2506,12 @@ FIELD(TBFLAG_A32, NS, 10, 1) * This requires an SME trap from AArch32 mode when using NEON. */ FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1) +/* + * Target EL for a Neon-disabled exception via CPACR.ASEDIS, HCPTR.TASE. + * If FPEXC_EL indicates a trap to a lower EL than this, that will + * take precedence. + */ +FIELD(TBFLAG_A32, NEONEXC_EL, 12, 2) /* * Bit usage when in AArch32 state, for M-profile only. diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index 0716ca98fd..14824e3dff 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -164,6 +164,86 @@ static bool sme_fa64(CPUARMState *env, int el) return true; } +static int neon_exception_el(CPUARMState *env, int cur_el) +{ + /* + * Return the EL to trap to for A32 Neon specific traps + * (CPACR.ASEDIS and HCPTR.TASE). In the pseudocode these are + * checked in the same function as the more general trap bits that + * we handle in fp_exception_el(). Fortunately it is always the + * case that if the trap/enable bits specify taking an exception + * to different ELs for the Neon-specific insns and the general fp + * insns then the trap to the lower of the two ELs has priority, + * so we can calculate the two target ELs separately and pick the + * right destination later. Compare AArch32_CheckAdvSIMDOrFPEnabled(). + * + * CPACR doesn't exist before v6, but neither does Neon, so we can + * assume that if we're here testing this then the register exists. + * HCPTR always exists if EL2 is present. + */ + uint64_t hcr_el2 = arm_hcr_el2_eff(env); + bool cpacr_asedis = FIELD_EX64(env->cp15.cpacr_el1, CPACR, ASEDIS); + bool hcptr_tase = FIELD_EX64(env->cp15.cptr_el[2], HCPTR, TASE); + bool have_aarch32_el3 = + arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3); + + if (!arm_feature(env, ARM_FEATURE_NEON_TRAPS)) { + /* This CPU doesn't implement the trap bits (Cortex-A8) */ + return 0; + } + + if (arm_feature(env, ARM_FEATURE_EL2) && arm_el_is_aa64(env, 2)) { + /* + * The AArch64 CPTR_EL2 has no equivalent to HCPTR.TASE; only + * an AArch32 EL2 can trap Neon specifically. + */ + hcptr_tase = false; + } + + /* + * We know we're in AArch32, but if this is EL0 and EL1 is AArch64 + * then CPACR_EL1 applies rather than CPACR, and it doesn't have + * ASEDIS (instead using the same bit for TCPAC). + */ + if (cur_el == 0 && arm_el_is_aa64(env, 1)) { + cpacr_asedis = false; + } + + /* CPACR is ignored if E2H+TGE are both set */ + if ((hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) { + cpacr_asedis = false; + } + + /* + * NSACR.NSASEDIS makes the effective values of HCPTR.TASE and + * CPACR.ASEDIS be 1 in NonSecure state. NSACR has no + * effect unless EL3 exists and is AArch32. + */ + if (have_aarch32_el3 && cur_el <= 2 && !arm_is_secure_below_el3(env)) { + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { + cpacr_asedis = true; + hcptr_tase = true; + } + } + + if (cpacr_asedis) { + if (have_aarch32_el3 && (cur_el == 3 || arm_is_secure_below_el3(env))) { + /* Trap from Secure PL0 or PL1 to Secure PL1 */ + return 3; + } + if (cur_el <= 1) { + /* trap from EL0 or EL1 to EL1 */ + return 1; + } + } + + /* HCPTR.TASE traps to EL2, including for execution at EL2 */ + if (hcptr_tase && cur_el <= 2) { + return 2; + } + return 0; +} + static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx) { @@ -209,6 +289,8 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1); } + DP_TBFLAG_A32(flags, NEONEXC_EL, neon_exception_el(env, el)); + return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index 6e944a0322..4db4b14841 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -306,15 +306,25 @@ 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. + * trapped by CPACR.ASEDIS and HCPTR.TASE. */ bool neon_access_check(DisasContext *s) { if (arm_dc_feature(s, ARM_FEATURE_M)) { return vfp_access_check_m(s, false); } else { + /* + * If the Neon-specific trap bits request a trap to a lower EL + * than the general FP trap bits, the trap to the lower EL + * has priority. + */ + if (s->neon_excp_el && + (!s->fp_excp_el || s->neon_excp_el < s->fp_excp_el)) { + uint32_t syn = syn_a32_fp_access_trap(1, 0xe, 1, 0); + + gen_exception_insn_el(s, 0, EXCP_UDEF, syn, s->neon_excp_el); + return false; + } return vfp_access_check_a(s, false, true); } } diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 1770428d3c..7306a1389c 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -6403,6 +6403,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->vec_stride = EX_TBFLAG_A32(tb_flags, VECSTRIDE); dc->sme_trap_nonstreaming = EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING); + dc->neon_excp_el = EX_TBFLAG_A32(tb_flags, NEONEXC_EL); } dc->lse2 = false; /* applies only to aarch64 */ dc->cp_regs = cpu->cp_regs; diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index a3d03159ad..cce84f29c4 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -88,6 +88,7 @@ typedef struct DisasContext { int sve_excp_el; /* SVE exception EL or 0 if enabled */ int sme_excp_el; /* SME exception EL or 0 if enabled */ int zt0_excp_el; /* ZT0 exception EL or 0 if enabled */ + int neon_excp_el; /* A32 Neon exception EL or 0 if enabled */ int vl; /* current vector length in bytes */ int svl; /* current streaming vector length in bytes */ int max_svl; /* maximum implemented streaming vector length */ From 975a1bd4399b0a00f89996e838f418c256fa0b56 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:36 +0100 Subject: [PATCH 453/627] target/arm: Pull VFP dregs checks out into a function Currently we directly call dc_isar_feature(aa32_simd_r32, s) for VFP insns that use D16-D31 to see if they should UNDEF. For some v7A CPUs (Cortex-A7, Cortex-A9) there is also a CPACR.D32DIS trap bit that will make VFP (and only VFP, not Neon) insns using D16-D31 UNDEF. Abstract out the register check for VFP insns into a new function which will provide us a place where we can make this check. Since D32DIS takes precedence over traps to EL2 and EL3 and simply makes the insns UNDEF, we are OK to check it at the same point when we do the CPU feature check, rather than having to wait until vfp_access_check(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-7-peter.maydell@linaro.org --- target/arm/tcg/translate-vfp.c | 70 ++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index 4db4b14841..a8d470ec49 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -207,6 +207,23 @@ static void gen_update_fp_context(DisasContext *s) } } +/* + * Return true if a VFP insn is OK to access the registers indicated + * by regmask, false if it should UNDEF. This checks whether the + * D16-D31 regs are implemented by the CPU. Eventually we will also check + * CPACR.D32DIS. + * Note that Neon insns accessing D16..D31 do not need to check D32DIS, + * so this function is for VFP insns only. + * + * @regmask should be the logical OR of the VFP Dregs being accessed. + */ +static bool vfp_dregs_ok(DisasContext *s, int dregmask) +{ + int invalid_dreg_mask = dc_isar_feature(aa32_simd_r32, s) ? 0 : 0x10; + + return !(dregmask & invalid_dreg_mask); +} + /* * Check that VFP access is enabled, A-profile specific version. * @@ -347,8 +364,7 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && - ((a->vm | a->vn | a->vd) & 0x10)) { + if (sz == 3 && !vfp_dregs_ok(s, a->vm | a->vn | a->vd)) { return false; } @@ -473,8 +489,7 @@ static bool trans_VRINT(DisasContext *s, arg_VRINT *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && - ((a->vm | a->vd) & 0x10)) { + if (sz == 3 && !vfp_dregs_ok(s, a->vm | a->vd)) { return false; } @@ -541,7 +556,7 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (sz == 3 && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (sz == 3 && !vfp_dregs_ok(s, a->vm)) { return false; } @@ -662,7 +677,7 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { + if (!vfp_dregs_ok(s, a->vn & 0x10)) { return false; } @@ -709,7 +724,7 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { + if (!vfp_dregs_ok(s, a->vn & 0x10)) { return false; } @@ -745,7 +760,7 @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { + if (!vfp_dregs_ok(s, a->vn)) { return false; } @@ -1030,7 +1045,7 @@ static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!vfp_dregs_ok(s, a->vm)) { return false; } @@ -1132,7 +1147,7 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!vfp_dregs_ok(s, a->vd)) { return false; } @@ -1261,7 +1276,7 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd + n) > 16) { + if (!vfp_dregs_ok(s, a->vd + n - 1)) { return false; } @@ -1513,7 +1528,7 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn, } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) { + if (!vfp_dregs_ok(s, vd | vn | vm)) { return false; } @@ -1685,7 +1700,7 @@ static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm) /* Note that the caller must check the aa32_fpdp_v2 feature. */ /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) { + if (!vfp_dregs_ok(s, vd | vm)) { return false; } @@ -2252,8 +2267,7 @@ static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!vfp_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2380,7 +2394,7 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) { + if (!vfp_dregs_ok(s, vd)) { return false; } @@ -2555,7 +2569,7 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { + if (!vfp_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2621,7 +2635,7 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!vfp_dregs_ok(s, a->vd)) { return false; } @@ -2702,7 +2716,7 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!vfp_dregs_ok(s, a->vm)) { return false; } @@ -2777,7 +2791,7 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { + if (!vfp_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2856,7 +2870,7 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { + if (!vfp_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2930,7 +2944,7 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) { + if (!vfp_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2956,7 +2970,7 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!vfp_dregs_ok(s, a->vd)) { return false; } @@ -2982,7 +2996,7 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!vfp_dregs_ok(s, a->vm)) { return false; } @@ -3063,7 +3077,7 @@ static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!vfp_dregs_ok(s, a->vd)) { return false; } @@ -3100,7 +3114,7 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!vfp_dregs_ok(s, a->vm)) { return false; } @@ -3240,7 +3254,7 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!vfp_dregs_ok(s, a->vd)) { return false; } @@ -3369,7 +3383,7 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!vfp_dregs_ok(s, a->vm)) { return false; } From 282ff9baebba548f8b6bfb63ffd53f40c8a0ce14 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:37 +0100 Subject: [PATCH 454/627] target/arm: Implement CPACR.D32DIS On some v7A CPUs, CPACR.D32DIS is a bit allowing the guest to make VFP instructions that touch registers D16..D31 UNDEF. Whether the CPU implements this or not is IMPDEF, and the only two CPUs we implement which have this are the Cortex-A7 and Cortex-A9. In v8A the bit is no longer defined at all. Since the only kind of trapping that needs to be done is a simple UNDEF, this is straightforward enough to implement. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/1499 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-8-peter.maydell@linaro.org --- target/arm/cpu.h | 4 ++++ target/arm/helper.c | 19 ++++++++++++++++--- target/arm/tcg/cpu32.c | 2 ++ target/arm/tcg/hflags.c | 20 ++++++++++++++++++++ target/arm/tcg/translate-vfp.c | 7 ++----- target/arm/tcg/translate.c | 6 ++++++ target/arm/tcg/translate.h | 1 + 7 files changed, 51 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index afc3fda3b8..e8dfc3179f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2184,6 +2184,8 @@ enum arm_features { * ARM_FEATURE_NEON CPUs except the Cortex-A8. */ ARM_FEATURE_NEON_TRAPS, + /* Does the CPU implement CPACR.D32DIS ? */ + ARM_FEATURE_D32DIS, }; static inline int arm_feature(const CPUARMState *env, int feature) @@ -2512,6 +2514,8 @@ FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1) * take precedence. */ FIELD(TBFLAG_A32, NEONEXC_EL, 12, 2) +/* Should VFP insns touching D16..D31 UNDEF? (CPACR.D32DIS) */ +FIELD(TBFLAG_A32, D32DIS, 14, 1) /* * Bit usage when in AArch32 state, for M-profile only. diff --git a/target/arm/helper.c b/target/arm/helper.c index 2dfbeae0ef..4f30a94ecd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -573,8 +573,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* VFP coprocessor: cp10 & cp11 [23:20] */ - mask |= R_CPACR_D32DIS_MASK | - R_CPACR_CP11_MASK | + mask |= R_CPACR_CP11_MASK | R_CPACR_CP10_MASK; if (!arm_feature(env, ARM_FEATURE_NEON)) { @@ -596,6 +595,13 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, if (!cpu_isar_feature(aa32_simd_r32, env_archcpu(env))) { /* D32DIS [30] is RAO/WI if D16-31 are not implemented. */ value |= R_CPACR_D32DIS_MASK; + mask |= R_CPACR_D32DIS_MASK; + } else if (arm_feature(env, ARM_FEATURE_D32DIS)) { + /* + * Bit is present unless CPU doesn't implement D32DIS, + * in which case it is RAZ/WI. + */ + mask |= R_CPACR_D32DIS_MASK; } } value &= mask; @@ -605,7 +611,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, * For A-profile AArch32 EL3 (but not M-profile secure mode), if NSACR.CP10 * is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00. * Similarly, if NSACR.NSASEDIS is 1 then CPACR.ASEDIS ignores writes - * and reads as 1. + * and reads as 1, and NSACR.NSD32DIS makes CPACR.D32DIS behave as RAO/WI. */ if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && !arm_is_secure(env)) { @@ -617,6 +623,10 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, mask = R_CPACR_ASEDIS_MASK; value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); } + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSD32DIS)) { + mask = R_CPACR_D32DIS_MASK; + value = (value & ~mask) | (env->cp15.cpacr_el1 & mask); + } } env->cp15.cpacr_el1 = value; @@ -639,6 +649,9 @@ static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri) if (FIELD_EX32(env->cp15.nsacr, NSACR, NSASEDIS)) { value |= R_CPACR_ASEDIS_MASK; } + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSD32DIS)) { + value |= R_CPACR_D32DIS_MASK; + } } return value; } diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index 724a954934..bc07e33877 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -336,6 +336,7 @@ static void cortex_a9_initfn(Object *obj) */ set_feature(&cpu->env, ARM_FEATURE_V7MP); set_feature(&cpu->env, ARM_FEATURE_CBAR); + set_feature(&cpu->env, ARM_FEATURE_D32DIS); cpu->midr = 0x410fc090; cpu->reset_fpsid = 0x41033090; cpu->isar.mvfr0 = 0x11110222; @@ -403,6 +404,7 @@ static void cortex_a7_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); set_feature(&cpu->env, ARM_FEATURE_PMU); + set_feature(&cpu->env, ARM_FEATURE_D32DIS); cpu->midr = 0x410fc075; cpu->reset_fpsid = 0x41023075; cpu->isar.mvfr0 = 0x10110222; diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index 14824e3dff..296ec8101a 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -244,6 +244,24 @@ static int neon_exception_el(CPUARMState *env, int cur_el) return 0; } +static bool arm_d32dis(CPUARMState *env, int cur_el) +{ + bool cpacr_d32dis = FIELD_EX64(env->cp15.cpacr_el1, CPACR, D32DIS); + + if (!arm_feature(env, ARM_FEATURE_D32DIS)) { + return false; + } + + /* If NSACR.NSD32DIS is set, CPACR.D32DIS acts as 1 in NonSecure */ + if ((arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) && + cur_el <= 2 && !arm_is_secure_below_el3(env))) { + if (FIELD_EX32(env->cp15.nsacr, NSACR, NSD32DIS)) { + cpacr_d32dis = true; + } + } + return cpacr_d32dis; +} + static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx) { @@ -291,6 +309,8 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, DP_TBFLAG_A32(flags, NEONEXC_EL, neon_exception_el(env, el)); + DP_TBFLAG_A32(flags, D32DIS, arm_d32dis(env, el)); + return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c index a8d470ec49..0a87a0165b 100644 --- a/target/arm/tcg/translate-vfp.c +++ b/target/arm/tcg/translate-vfp.c @@ -210,8 +210,7 @@ static void gen_update_fp_context(DisasContext *s) /* * Return true if a VFP insn is OK to access the registers indicated * by regmask, false if it should UNDEF. This checks whether the - * D16-D31 regs are implemented by the CPU. Eventually we will also check - * CPACR.D32DIS. + * D16-D31 regs are implemented by the CPU and not disabled by CPACR.D32DIS. * Note that Neon insns accessing D16..D31 do not need to check D32DIS, * so this function is for VFP insns only. * @@ -219,9 +218,7 @@ static void gen_update_fp_context(DisasContext *s) */ static bool vfp_dregs_ok(DisasContext *s, int dregmask) { - int invalid_dreg_mask = dc_isar_feature(aa32_simd_r32, s) ? 0 : 0x10; - - return !(dregmask & invalid_dreg_mask); + return !(dregmask & s->invalid_vfp_dreg_mask); } /* diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 7306a1389c..90eb6f3005 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -6342,6 +6342,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ARMCPU *cpu = env_archcpu(env); CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb); uint32_t condexec, core_mmu_idx; + bool d32dis = false; dc->isar = &cpu->isar; dc->condjmp = 0; @@ -6404,7 +6405,12 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->sme_trap_nonstreaming = EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING); dc->neon_excp_el = EX_TBFLAG_A32(tb_flags, NEONEXC_EL); + d32dis = EX_TBFLAG_A32(tb_flags, D32DIS); } + + dc->invalid_vfp_dreg_mask = + (d32dis || !dc_isar_feature(aa32_simd_r32, dc)) ? 0x10 : 0; + dc->lse2 = false; /* applies only to aarch64 */ dc->cp_regs = cpu->cp_regs; dc->features = env->features; diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index cce84f29c4..b08bded398 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -94,6 +94,7 @@ typedef struct DisasContext { int max_svl; /* maximum implemented streaming vector length */ int max_any_vl; /* maximum implemented vector length */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ + int invalid_vfp_dreg_mask; /* mask for whether VFP D16..D31 should UNDEF */ int vec_len; int vec_stride; bool v7m_handler_mode; From 44d5b628fbce1612f3d8529699905e8dc9f57b1b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Aug 2026 13:38:38 +0100 Subject: [PATCH 455/627] target/arm: Pull Neon dregs checks out into a function Abstract out the register check for Neon insns into a new function, similarly to what we have for VFP. We don't have any extra checks that we need to add here, but having a neon_dregs_ok() is cleaner and means the Neon decode isn't oddly different to the VFP decode. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20260817123838.1578060-9-peter.maydell@linaro.org --- target/arm/tcg/translate-neon.c | 118 ++++++++++++++------------------ target/arm/tcg/translate.c | 1 + target/arm/tcg/translate.h | 1 + 3 files changed, 53 insertions(+), 67 deletions(-) diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c index 50a44511d9..f811940f64 100644 --- a/target/arm/tcg/translate-neon.c +++ b/target/arm/tcg/translate-neon.c @@ -118,11 +118,24 @@ static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) } } +/* + * Return true if a Neon insn is OK to access the registers indicated + * by regmask, false if it should UNDEF. This checks whether the + * D16-D31 regs are implemented by the CPU. + * Note that Neon insns accessing D16..D31 do not need to check D32DIS. + * + * @regmask should be the logical OR of the Dregs being accessed. + */ +static bool neon_dregs_ok(DisasContext *s, int dregmask) +{ + return !(dregmask & s->invalid_neon_dreg_mask); +} + static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm, int data, gen_helper_gvec_4 *fn_gvec) { /* UNDEF accesses to D16-D31 if they don't exist. */ - if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { + if (!neon_dregs_ok(s, vd | vn | vm)) { return false; } @@ -152,7 +165,7 @@ static bool do_neon_ddda_env(DisasContext *s, int q, int vd, int vn, int vm, int data, gen_helper_gvec_4_ptr *fn_gvec) { /* UNDEF accesses to D16-D31 if they don't exist. */ - if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { + if (!neon_dregs_ok(s, vd | vn | vm)) { return false; } @@ -184,7 +197,7 @@ static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm, gen_helper_gvec_4_ptr *fn_gvec_ptr) { /* UNDEF accesses to D16-D31 if they don't exist. */ - if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) { + if (!neon_dregs_ok(s, vd | vn | vm)) { return false; } @@ -240,8 +253,7 @@ static bool trans_VCADD(DisasContext *s, arg_VCADD *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -310,8 +322,7 @@ static bool trans_VFML(DisasContext *s, arg_VFML *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - (a->vd & 0x10)) { + if (!neon_dregs_ok(s, a->vd)) { return false; } @@ -398,14 +409,14 @@ static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a) static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a) { int opr_sz; + int dregmask = a->vd | (a->q ? a->vn : 0); if (!dc_isar_feature(aa32_fhm, s)) { return false; } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd & 0x10) || (a->q && (a->vn & 0x10)))) { + if (!neon_dregs_ok(s, dregmask)) { return false; } @@ -478,7 +489,7 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!neon_dregs_ok(s, a->vd)) { return false; } if (a->itype > 10) { @@ -580,7 +591,7 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!neon_dregs_ok(s, a->vd)) { return false; } @@ -672,7 +683,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) } /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!neon_dregs_ok(s, a->vd)) { return false; } @@ -789,8 +800,7 @@ static bool do_3same(DisasContext *s, arg_3same *a, GVecGen3Fn fn) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -1067,8 +1077,7 @@ static bool do_vector_2sh(DisasContext *s, arg_2reg_shift *a, GVecGen2iFn *fn) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -1117,8 +1126,7 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -1168,8 +1176,7 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -1293,8 +1300,7 @@ static bool do_vshll_2sh(DisasContext *s, arg_2reg_shift *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -1383,8 +1389,7 @@ static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -1428,7 +1433,7 @@ static bool do_1reg_imm(DisasContext *s, arg_1reg_imm *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!neon_dregs_ok(s, a->vd)) { return false; } @@ -1485,8 +1490,7 @@ static bool do_prewiden_3d(DisasContext *s, arg_3diff *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -1592,8 +1596,7 @@ static bool do_narrow_3d(DisasContext *s, arg_3diff *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -1682,8 +1685,7 @@ static bool do_long_3d(DisasContext *s, arg_3diff *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -1944,8 +1946,7 @@ static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2027,8 +2028,7 @@ static bool do_2scalar(DisasContext *s, arg_2scalar *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2125,8 +2125,7 @@ static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2222,8 +2221,7 @@ static bool do_vqrdmlah_2sc(DisasContext *s, arg_2scalar *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2293,8 +2291,7 @@ static bool do_2scalar_long(DisasContext *s, arg_2scalar *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2438,8 +2435,7 @@ static bool trans_VEXT(DisasContext *s, arg_VEXT *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2507,8 +2503,7 @@ static bool trans_VTBL(DisasContext *s, arg_VTBL *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vn | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vn | a->vm)) { return false; } @@ -2546,8 +2541,7 @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2577,8 +2571,7 @@ static bool do_zip_uzp(DisasContext *s, arg_2misc *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2647,8 +2640,7 @@ static bool do_vmovn(DisasContext *s, arg_2misc *a, } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2711,8 +2703,7 @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2755,8 +2746,7 @@ static bool trans_VCVT_B16_F32(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2795,8 +2785,7 @@ static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2841,8 +2830,7 @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -2887,8 +2875,7 @@ static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -3015,8 +3002,7 @@ static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -3219,8 +3205,7 @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } @@ -3292,8 +3277,7 @@ static bool trans_VTRN(DisasContext *s, arg_2misc *a) } /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && - ((a->vd | a->vm) & 0x10)) { + if (!neon_dregs_ok(s, a->vd | a->vm)) { return false; } diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 90eb6f3005..c866148383 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -6410,6 +6410,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->invalid_vfp_dreg_mask = (d32dis || !dc_isar_feature(aa32_simd_r32, dc)) ? 0x10 : 0; + dc->invalid_neon_dreg_mask = !dc_isar_feature(aa32_simd_r32, dc) ? 0x10 : 0; dc->lse2 = false; /* applies only to aarch64 */ dc->cp_regs = cpu->cp_regs; diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index b08bded398..31f52a34a6 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -95,6 +95,7 @@ typedef struct DisasContext { int max_any_vl; /* maximum implemented vector length */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int invalid_vfp_dreg_mask; /* mask for whether VFP D16..D31 should UNDEF */ + int invalid_neon_dreg_mask; /* ditto, for Neon */ int vec_len; int vec_stride; bool v7m_handler_mode; From 7a0c61ad4ed53fe84e82283369728629ae9ea380 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:31 +0800 Subject: [PATCH 456/627] hw/arm: aspeed: Store boot info in the machine state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move the boot info into the existing AspeedMachineState. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260816131300.51799-2-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/aspeed.c | 17 +++++++---------- include/hw/arm/aspeed.h | 2 ++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a9238e6217..8fa16b3831 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -24,10 +24,6 @@ #include "hw/core/qdev-clock.h" #include "system/system.h" -static struct arm_boot_info aspeed_board_binfo = { - .board_id = -1, /* device-tree-only board */ -}; - #define AST_SMP_MAILBOX_BASE 0x1e6e2180 #define AST_SMP_MBOX_FIELD_ENTRY (AST_SMP_MAILBOX_BASE + 0x0) #define AST_SMP_MBOX_FIELD_GOSIGN (AST_SMP_MAILBOX_BASE + 0x4) @@ -206,13 +202,14 @@ static void aspeed_machine_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), AST_SMP_MAILBOX_BASE, smpboot); - aspeed_board_binfo.write_secondary_boot = aspeed_write_smpboot; - aspeed_board_binfo.secondary_cpu_reset_hook = aspeed_reset_secondary; - aspeed_board_binfo.smp_loader_start = AST_SMP_MBOX_CODE; + bmc->bootinfo.write_secondary_boot = aspeed_write_smpboot; + bmc->bootinfo.secondary_cpu_reset_hook = aspeed_reset_secondary; + bmc->bootinfo.smp_loader_start = AST_SMP_MBOX_CODE; } - aspeed_board_binfo.ram_size = machine->ram_size; - aspeed_board_binfo.loader_start = sc->memmap[ASPEED_DEV_SDRAM]; + bmc->bootinfo.board_id = -1; /* device-tree-only board */ + bmc->bootinfo.ram_size = machine->ram_size; + bmc->bootinfo.loader_start = sc->memmap[ASPEED_DEV_SDRAM]; if (amc->i2c_init) { amc->i2c_init(bmc); @@ -248,7 +245,7 @@ static void aspeed_machine_init(MachineState *machine) aspeed_load_vbootrom(bmc->soc, bios_name, &error_abort); } - arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); + arm_load_kernel(ARM_CPU(first_cpu), machine, &bmc->bootinfo); } void aspeed_create_pca9552(AspeedSoCState *soc, int bus_id, int addr) diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index a00238ed74..54f0d7643d 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -12,6 +12,7 @@ #include "hw/core/boards.h" #include "qom/object.h" #include "hw/arm/aspeed_soc.h" +#include "hw/arm/boot.h" typedef struct AspeedMachineState AspeedMachineState; @@ -42,6 +43,7 @@ struct AspeedMachineState { char *fmc_model; char *spi_model; uint32_t hw_strap1; + struct arm_boot_info bootinfo; }; struct AspeedMachineClass { From 98caf5918760db50671e3351aecdaabd83317bde Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:32 +0800 Subject: [PATCH 457/627] hw/arm: aspeed_ast27x0-fc: Store boot info in the machine state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move the boot info into the existing Ast2700FCState. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260816131300.51799-3-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/aspeed_ast27x0-fc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 058cea42ed..ceeae336df 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -27,10 +27,6 @@ #define TYPE_AST2700FC MACHINE_TYPE_NAME("ast2700fc") OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700FC); -static struct arm_boot_info ast2700fc_board_info = { - .board_id = -1, /* device-tree-only board */ -}; - struct Ast2700FCState { MachineState parent_obj; @@ -46,6 +42,8 @@ struct Ast2700FCState { Aspeed27x0SoCState ca35; Aspeed27x0CoprocessorState ssp; Aspeed27x0CoprocessorState tsp; + + struct arm_boot_info bootinfo; }; #define AST2700FC_BMC_RAM_SIZE (2 * GiB) @@ -114,8 +112,9 @@ static bool ast2700fc_ca35_init(MachineState *machine, Error **errp) aspeed_board_init_flashes(&soc->fmc, AST2700FC_FMC_MODEL, 2, 0); aspeed_board_init_flashes(&soc->spi[0], AST2700FC_SPI_MODEL, 1, 2); - ast2700fc_board_info.ram_size = machine->ram_size; - ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM]; + s->bootinfo.ram_size = machine->ram_size; + s->bootinfo.loader_start = sc->memmap[ASPEED_DEV_SDRAM]; + s->bootinfo.board_id = -1; /* device-tree-only board */ dev = ssi_get_cs(soc->fmc.spi, 0); fmc0 = dev ? m25p80_get_blk(dev) : NULL; @@ -129,7 +128,7 @@ static bool ast2700fc_ca35_init(MachineState *machine, Error **errp) bios_name = machine->firmware ?: VBOOTROM_FILE_NAME; aspeed_load_vbootrom(soc, bios_name, errp); - arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info); + arm_load_kernel(ARM_CPU(first_cpu), machine, &s->bootinfo); return true; } From 1fa13d2eef9ddbf0191d2c3a5a78e8b9167829a8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:33 +0800 Subject: [PATCH 458/627] hw/arm: bananapi_m2u: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move it into a new Bpim2uMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-4-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/bananapi_m2u.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c index 9b468cd8ac..0079aa1dd2 100644 --- a/hw/arm/bananapi_m2u.c +++ b/hw/arm/bananapi_m2u.c @@ -29,7 +29,14 @@ #include "hw/arm/boot.h" #include "hw/arm/machines-qom.h" -static struct arm_boot_info bpim2u_binfo; +#define TYPE_BPIM2U_MACHINE MACHINE_TYPE_NAME("bpim2u") +OBJECT_DECLARE_SIMPLE_TYPE(Bpim2uMachineState, BPIM2U_MACHINE) + +struct Bpim2uMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +}; /* * R40 can boot from mmc0 and mmc2, and bpim2u has two mmc interface, one is @@ -62,6 +69,7 @@ static void mmc_attach_drive(AwR40State *s, AwSdHostState *mmc, int unit, static void bpim2u_init(MachineState *machine) { + Bpim2uMachineState *bpms = BPIM2U_MACHINE(machine); bool bootroom_loaded = false; AwR40State *r40; I2CBus *i2c; @@ -120,10 +128,10 @@ static void bpim2u_init(MachineState *machine) memory_region_add_subregion(get_system_memory(), r40->memmap[AW_R40_DEV_SDRAM], machine->ram); - bpim2u_binfo.loader_start = r40->memmap[AW_R40_DEV_SDRAM]; - bpim2u_binfo.ram_size = machine->ram_size; - bpim2u_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; - arm_load_kernel(&r40->cpus[0], machine, &bpim2u_binfo); + bpms->bootinfo.loader_start = r40->memmap[AW_R40_DEV_SDRAM]; + bpms->bootinfo.ram_size = machine->ram_size; + bpms->bootinfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; + arm_load_kernel(&r40->cpus[0], machine, &bpms->bootinfo); } static void bpim2u_machine_init(MachineClass *mc) @@ -145,4 +153,5 @@ static void bpim2u_machine_init(MachineClass *mc) mc->auto_create_sdcard = true; } -DEFINE_MACHINE_ARM("bpim2u", bpim2u_machine_init) +DEFINE_MACHINE_EXTENDED("bpim2u", MACHINE, Bpim2uMachineState, + bpim2u_machine_init, false, arm_machine_interfaces) From 9130e284e4e8fdca7994bafe313dc69a03f5f5a5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:34 +0800 Subject: [PATCH 459/627] hw/arm: collie: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move the boot info into the existing CollieMachineState. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-5-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/collie.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 91f0a94b6f..01d74ad38c 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -30,16 +30,12 @@ struct CollieMachineState { MachineState parent; StrongARMState *sa1110; + struct arm_boot_info bootinfo; }; #define TYPE_COLLIE_MACHINE MACHINE_TYPE_NAME("collie") OBJECT_DECLARE_SIMPLE_TYPE(CollieMachineState, COLLIE_MACHINE) -static struct arm_boot_info collie_binfo = { - .loader_start = SA_SDCS0, - .ram_size = RAM_SIZE, -}; - static void collie_init(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); @@ -66,8 +62,10 @@ static void collie_init(MachineState *machine) sysbus_create_simple("scoop", 0x40800000, NULL); - collie_binfo.board_id = 0x208; - arm_load_kernel(cms->sa1110->cpu, machine, &collie_binfo); + cms->bootinfo.loader_start = SA_SDCS0; + cms->bootinfo.ram_size = RAM_SIZE; + cms->bootinfo.board_id = 0x208; + arm_load_kernel(cms->sa1110->cpu, machine, &cms->bootinfo); } static void collie_machine_class_init(ObjectClass *oc, const void *data) From edb0b93a7000e6eb49cb51284555f54db6489f04 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:35 +0800 Subject: [PATCH 460/627] hw/arm: cubieboard: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move it into a new CubieboardMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-6-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/cubieboard.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index a643ae4e27..d59c1ebba7 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -25,13 +25,18 @@ #include "hw/arm/machines-qom.h" #include "hw/i2c/i2c.h" -static struct arm_boot_info cubieboard_binfo = { - .loader_start = AW_A10_SDRAM_BASE, - .board_id = 0x1008, +#define TYPE_CUBIEBOARD_MACHINE MACHINE_TYPE_NAME("cubieboard") +OBJECT_DECLARE_SIMPLE_TYPE(CubieboardMachineState, CUBIEBOARD_MACHINE) + +struct CubieboardMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; }; static void cubieboard_init(MachineState *machine) { + CubieboardMachineState *cbs = CUBIEBOARD_MACHINE(machine); AwA10State *a10; Error *err = NULL; DriveInfo *di; @@ -103,8 +108,10 @@ static void cubieboard_init(MachineState *machine) } /* TODO create and connect IDE devices for ide_drive_get() */ - cubieboard_binfo.ram_size = machine->ram_size; - arm_load_kernel(&a10->cpu, machine, &cubieboard_binfo); + cbs->bootinfo.loader_start = AW_A10_SDRAM_BASE; + cbs->bootinfo.board_id = 0x1008; + cbs->bootinfo.ram_size = machine->ram_size; + arm_load_kernel(&a10->cpu, machine, &cbs->bootinfo); } static void cubieboard_machine_init(MachineClass *mc) @@ -126,4 +133,6 @@ static void cubieboard_machine_init(MachineClass *mc) mc->auto_create_sdcard = true; } -DEFINE_MACHINE_ARM("cubieboard", cubieboard_machine_init) +DEFINE_MACHINE_EXTENDED("cubieboard", MACHINE, CubieboardMachineState, + cubieboard_machine_init, false, + arm_machine_interfaces) From be525becaa224a2386499d045a6b21c59b92c3e2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:36 +0800 Subject: [PATCH 461/627] hw/arm: exynos4_boards: Store boot info in the board state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. The Exynos4BoardState struct is already allocated per machine instance, so move the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260816131300.51799-7-bin.meng@processmission.com Signed-off-by: Peter Maydell --- hw/arm/exynos4_boards.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 1b8c9b618f..b7decdb2c7 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -49,6 +49,7 @@ typedef struct Exynos4BoardState { Exynos4210State soc; MemoryRegion dram0_mem; MemoryRegion dram1_mem; + struct arm_boot_info bootinfo; } Exynos4BoardState; static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { @@ -66,12 +67,6 @@ static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = { [EXYNOS4_BOARD_SMDKC210] = 1 * GiB, }; -static struct arm_boot_info exynos4_board_binfo = { - .loader_start = EXYNOS4210_BASE_BOOT_ADDR, - .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, - .write_secondary_boot = exynos4210_write_secondary, -}; - static void lan9215_init(uint32_t base, qemu_irq irq) { DeviceState *dev; @@ -113,14 +108,15 @@ static Exynos4BoardState * exynos4_boards_init_common(MachineState *machine, Exynos4BoardType board_type) { - Exynos4BoardState *s = g_new(Exynos4BoardState, 1); + Exynos4BoardState *s = g_new0(Exynos4BoardState, 1); - exynos4_board_binfo.ram_size = exynos4_board_ram_size[board_type]; - exynos4_board_binfo.board_id = exynos4_board_id[board_type]; - exynos4_board_binfo.smp_bootreg_addr = - exynos4_board_smp_bootreg_addr[board_type]; - exynos4_board_binfo.gic_cpu_if_addr = - EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; + s->bootinfo.loader_start = EXYNOS4210_BASE_BOOT_ADDR; + s->bootinfo.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR; + s->bootinfo.write_secondary_boot = exynos4210_write_secondary; + s->bootinfo.ram_size = exynos4_board_ram_size[board_type]; + s->bootinfo.board_id = exynos4_board_id[board_type]; + s->bootinfo.smp_bootreg_addr = exynos4_board_smp_bootreg_addr[board_type]; + s->bootinfo.gic_cpu_if_addr = EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100; exynos4_boards_init_ram(s, get_system_memory(), exynos4_board_ram_size[board_type]); @@ -137,7 +133,7 @@ static void nuri_init(MachineState *machine) Exynos4BoardState *s = exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI); - arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo); + arm_load_kernel(s->soc.cpu[0], machine, &s->bootinfo); } static void smdkc210_init(MachineState *machine) @@ -147,7 +143,7 @@ static void smdkc210_init(MachineState *machine) lan9215_init(SMDK_LAN9118_BASE_ADDR, qemu_irq_invert(s->soc.irq_table[exynos4210_get_irq(37, 1)])); - arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo); + arm_load_kernel(s->soc.cpu[0], machine, &s->bootinfo); } static const char * const valid_cpu_types[] = { From bcdc392396eb3825f273e2c84c9ed7290f0ac283 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:37 +0800 Subject: [PATCH 462/627] hw/arm: imx25_pdk: Store boot info in the board state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. The IMX25PDK struct is already allocated per machine instance, so move the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-8-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/imx25_pdk.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 7ebd6c8eb9..f7a51481af 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -61,10 +61,9 @@ typedef struct IMX25PDK { FslIMX25State soc; MemoryRegion ram_alias; + struct arm_boot_info bootinfo; } IMX25PDK; -static struct arm_boot_info imx25_pdk_binfo; - static void imx25_pdk_init(MachineState *machine) { IMX25PDK *s = g_new0(IMX25PDK, 1); @@ -114,9 +113,9 @@ static void imx25_pdk_init(MachineState *machine) alias_offset += ram[i].size; } - imx25_pdk_binfo.ram_size = machine->ram_size; - imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR; - imx25_pdk_binfo.board_id = 1771; + s->bootinfo.ram_size = machine->ram_size; + s->bootinfo.loader_start = FSL_IMX25_SDRAM0_ADDR; + s->bootinfo.board_id = 1771; for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) { BusState *bus; @@ -138,7 +137,7 @@ static void imx25_pdk_init(MachineState *machine) * fail. */ if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, machine, &imx25_pdk_binfo); + arm_load_kernel(&s->soc.cpu, machine, &s->bootinfo); } } From 3b9cb3dd042c1edc4c7a240e8dcd3252e6d38dd4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:38 +0800 Subject: [PATCH 463/627] hw/arm: imx8mm-evk: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a function scoped static object. Move it into a new Imx8mmEvkMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_AARCH64 macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-9-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/imx8mm-evk.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/hw/arm/imx8mm-evk.c b/hw/arm/imx8mm-evk.c index 6b7774d3e2..019c609c54 100644 --- a/hw/arm/imx8mm-evk.c +++ b/hw/arm/imx8mm-evk.c @@ -20,6 +20,15 @@ #include "qapi/error.h" #include +#define TYPE_IMX8MM_EVK_MACHINE MACHINE_TYPE_NAME("imx8mm-evk") +OBJECT_DECLARE_SIMPLE_TYPE(Imx8mmEvkMachineState, IMX8MM_EVK_MACHINE) + +struct Imx8mmEvkMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +}; + static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt) { int i, offset; @@ -60,7 +69,7 @@ static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt) static void imx8mm_evk_init(MachineState *machine) { - static struct arm_boot_info boot_info; + Imx8mmEvkMachineState *ims = IMX8MM_EVK_MACHINE(machine); FslImx8mmState *s; if (machine->ram_size > FSL_IMX8MM_RAM_SIZE_MAX) { @@ -69,13 +78,11 @@ static void imx8mm_evk_init(MachineState *machine) 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, - }; + ims->bootinfo.loader_start = FSL_IMX8MM_RAM_START; + ims->bootinfo.board_id = -1; + ims->bootinfo.ram_size = machine->ram_size; + ims->bootinfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; + ims->bootinfo.modify_dtb = imx8mm_evk_modify_dtb; s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine), "soc", &error_fatal, NULL)); @@ -103,7 +110,7 @@ static void imx8mm_evk_init(MachineState *machine) } if (!qtest_enabled()) { - arm_load_kernel(&s->cpu[0], machine, &boot_info); + arm_load_kernel(&s->cpu[0], machine, &ims->bootinfo); } } @@ -127,4 +134,6 @@ static void imx8mm_evk_machine_init(MachineClass *mc) mc->get_default_cpu_type = imx8mm_evk_get_default_cpu_type; } -DEFINE_MACHINE_AARCH64("imx8mm-evk", imx8mm_evk_machine_init) +DEFINE_MACHINE_EXTENDED("imx8mm-evk", MACHINE, Imx8mmEvkMachineState, + imx8mm_evk_machine_init, false, + aarch64_machine_interfaces) From 27d4e71757f2e08a1338541fc6e3dd55b55d4977 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:39 +0800 Subject: [PATCH 464/627] hw/arm: integratorcp: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move it into a new IntegratorcpMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-10-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/integratorcp.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index c25bbf3c82..f8bcf42c61 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -581,13 +581,19 @@ static void icp_control_init(Object *obj) /* Board init. */ -static struct arm_boot_info integrator_binfo = { - .loader_start = 0x0, - .board_id = 0x113, +#define TYPE_INTEGRATORCP_MACHINE MACHINE_TYPE_NAME("integratorcp") +OBJECT_DECLARE_SIMPLE_TYPE(IntegratorcpMachineState, + INTEGRATORCP_MACHINE) + +struct IntegratorcpMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; }; static void integratorcp_init(MachineState *machine) { + IntegratorcpMachineState *icms = INTEGRATORCP_MACHINE(machine); ram_addr_t ram_size = machine->ram_size; Object *cpuobj; ARMCPU *cpu; @@ -680,8 +686,10 @@ static void integratorcp_init(MachineState *machine) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xc0000000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[22]); - integrator_binfo.ram_size = ram_size; - arm_load_kernel(cpu, machine, &integrator_binfo); + icms->bootinfo.loader_start = 0x0; + icms->bootinfo.board_id = 0x113; + icms->bootinfo.ram_size = ram_size; + arm_load_kernel(cpu, machine, &icms->bootinfo); } static void integratorcp_machine_init(MachineClass *mc) @@ -696,7 +704,9 @@ static void integratorcp_machine_init(MachineClass *mc) machine_add_audiodev_property(mc); } -DEFINE_MACHINE_ARM("integratorcp", integratorcp_machine_init) +DEFINE_MACHINE_EXTENDED("integratorcp", MACHINE, IntegratorcpMachineState, + integratorcp_machine_init, false, + arm_machine_interfaces) static const Property core_properties[] = { DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), From f139ad829a21407b46beed9d165e84a98b4fa972 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:40 +0800 Subject: [PATCH 465/627] hw/arm: kzm: Store boot info in the board state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. The IMX31KZM struct is already allocated per machine instance, so move the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-11-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/kzm.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 168ecf35d0..1aa5b49de9 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -54,17 +54,13 @@ typedef struct IMX31KZM { FslIMX31State soc; MemoryRegion ram_alias; + struct arm_boot_info bootinfo; } IMX31KZM; #define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR) #define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040) #define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR) -static struct arm_boot_info kzm_binfo = { - .loader_start = KZM_RAM_ADDR, - .board_id = 1722, -}; - static void kzm_init(MachineState *machine) { IMX31KZM *s = g_new0(IMX31KZM, 1); @@ -125,10 +121,12 @@ static void kzm_init(MachineState *machine) 14745600, serial_hd(2), DEVICE_NATIVE_ENDIAN); } - kzm_binfo.ram_size = machine->ram_size; + s->bootinfo.loader_start = KZM_RAM_ADDR; + s->bootinfo.board_id = 1722; + s->bootinfo.ram_size = machine->ram_size; if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu, machine, &kzm_binfo); + arm_load_kernel(&s->soc.cpu, machine, &s->bootinfo); } } From b8939158c37afd88ea252dc2e11ca387ffeb4ce3 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:41 +0800 Subject: [PATCH 466/627] hw/arm: mcimx7d-sabre: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a function scoped static object. Move it into a new Mcimx7dSabreMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-12-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mcimx7d-sabre.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index a0ac647c3d..22fe1fa932 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -22,9 +22,19 @@ #include "qemu/error-report.h" #include "system/qtest.h" +#define TYPE_MCIMX7D_SABRE_MACHINE MACHINE_TYPE_NAME("mcimx7d-sabre") +OBJECT_DECLARE_SIMPLE_TYPE(Mcimx7dSabreMachineState, + MCIMX7D_SABRE_MACHINE) + +struct Mcimx7dSabreMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +}; + static void mcimx7d_sabre_init(MachineState *machine) { - static struct arm_boot_info boot_info; + Mcimx7dSabreMachineState *msms = MCIMX7D_SABRE_MACHINE(machine); FslIMX7State *s; int i; @@ -34,12 +44,10 @@ static void mcimx7d_sabre_init(MachineState *machine) exit(1); } - boot_info = (struct arm_boot_info) { - .loader_start = FSL_IMX7_MMDC_ADDR, - .board_id = -1, - .ram_size = machine->ram_size, - .psci_conduit = QEMU_PSCI_CONDUIT_SMC, - }; + msms->bootinfo.loader_start = FSL_IMX7_MMDC_ADDR; + msms->bootinfo.board_id = -1; + msms->bootinfo.ram_size = machine->ram_size; + msms->bootinfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; s = FSL_IMX7(object_new(TYPE_FSL_IMX7)); object_property_add_child(OBJECT(machine), "soc", OBJECT(s)); @@ -65,7 +73,7 @@ static void mcimx7d_sabre_init(MachineState *machine) } if (!qtest_enabled()) { - arm_load_kernel(&s->cpu[0], machine, &boot_info); + arm_load_kernel(&s->cpu[0], machine, &msms->bootinfo); } } @@ -78,4 +86,6 @@ static void mcimx7d_sabre_machine_init(MachineClass *mc) mc->auto_create_sdcard = true; } -DEFINE_MACHINE_ARM("mcimx7d-sabre", mcimx7d_sabre_machine_init) +DEFINE_MACHINE_EXTENDED("mcimx7d-sabre", MACHINE, Mcimx7dSabreMachineState, + mcimx7d_sabre_machine_init, false, + arm_machine_interfaces) From b8e984eb90f02df57b0b82c464170b693226d565 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:42 +0800 Subject: [PATCH 467/627] hw/arm: musicpal: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move it into a new MusicPalMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-13-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/musicpal.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 69e83bdd97..8a70ed7377 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1200,13 +1200,18 @@ static const TypeInfo musicpal_key_info = { #define FLASH_SECTOR_SIZE (64 * KiB) -static struct arm_boot_info musicpal_binfo = { - .loader_start = 0x0, - .board_id = 0x20e, +#define TYPE_MUSICPAL_MACHINE MACHINE_TYPE_NAME("musicpal") +OBJECT_DECLARE_SIMPLE_TYPE(MusicPalMachineState, MUSICPAL_MACHINE) + +struct MusicPalMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; }; static void musicpal_init(MachineState *machine) { + MusicPalMachineState *mpms = MUSICPAL_MACHINE(machine); ARMCPU *cpu; DeviceState *dev; DeviceState *pic; @@ -1341,8 +1346,10 @@ static void musicpal_init(MachineState *machine) sysbus_mmio_map(s, 0, MP_AUDIO_BASE); sysbus_connect_irq(s, 0, qdev_get_gpio_in(pic, MP_AUDIO_IRQ)); - musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; - arm_load_kernel(cpu, machine, &musicpal_binfo); + mpms->bootinfo.loader_start = 0x0; + mpms->bootinfo.board_id = 0x20e; + mpms->bootinfo.ram_size = MP_RAM_DEFAULT_SIZE; + arm_load_kernel(cpu, machine, &mpms->bootinfo); } static void musicpal_machine_init(MachineClass *mc) @@ -1357,7 +1364,9 @@ static void musicpal_machine_init(MachineClass *mc) machine_add_audiodev_property(mc); } -DEFINE_MACHINE_ARM("musicpal", musicpal_machine_init) +DEFINE_MACHINE_EXTENDED("musicpal", MACHINE, MusicPalMachineState, + musicpal_machine_init, false, + arm_machine_interfaces) static void mv88w8618_wlan_class_init(ObjectClass *klass, const void *data) { From 92fbe79cb0f5d0b72e88513205365448346d4e41 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:43 +0800 Subject: [PATCH 468/627] hw/arm: npcm7xx: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object inside npcm7xx_load_kernel(). Let the caller own the boot info: the boards store it in their NPCM7xxMachine and pass it to npcm7xx_load_kernel(), which only fills in the SoC specific values. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-14-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/npcm7xx.c | 26 ++++++++++++-------------- hw/arm/npcm7xx_boards.c | 10 +++++----- include/hw/arm/npcm7xx.h | 10 ++++++++-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index c27f149c04..695f30a0dc 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -364,22 +364,20 @@ static void npcm7xx_write_secondary_boot(ARMCPU *cpu, NPCM7XX_SMP_LOADER_START); } -static struct arm_boot_info npcm7xx_binfo = { - .loader_start = NPCM7XX_LOADER_START, - .smp_loader_start = NPCM7XX_SMP_LOADER_START, - .smp_bootreg_addr = NPCM7XX_SMP_BOOTREG_ADDR, - .gic_cpu_if_addr = NPCM7XX_GIC_CPU_IF_ADDR, - .write_secondary_boot = npcm7xx_write_secondary_boot, - .board_id = -1, - .board_setup_addr = NPCM7XX_BOARD_SETUP_ADDR, - .write_board_setup = npcm7xx_write_board_setup, -}; - -void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc) +void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc, + struct arm_boot_info *binfo) { - npcm7xx_binfo.ram_size = machine->ram_size; + binfo->loader_start = NPCM7XX_LOADER_START; + binfo->smp_loader_start = NPCM7XX_SMP_LOADER_START; + binfo->smp_bootreg_addr = NPCM7XX_SMP_BOOTREG_ADDR; + binfo->gic_cpu_if_addr = NPCM7XX_GIC_CPU_IF_ADDR; + binfo->write_secondary_boot = npcm7xx_write_secondary_boot; + binfo->board_id = -1; + binfo->board_setup_addr = NPCM7XX_BOARD_SETUP_ADDR; + binfo->write_board_setup = npcm7xx_write_board_setup; + binfo->ram_size = machine->ram_size; - arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo); + arm_load_kernel(&soc->cpu[0], machine, binfo); } static void npcm7xx_init_fuses(NPCM7xxState *s) diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 57a8d3186e..4f14d25746 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -374,7 +374,7 @@ static void npcm750_evb_init(MachineState *machine) npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0)); npcm750_evb_i2c_init(soc); npcm750_evb_fan_init(NPCM7XX_MACHINE(machine), soc); - npcm7xx_load_kernel(machine, soc); + npcm7xx_load_kernel(machine, soc, &NPCM7XX_MACHINE(machine)->bootinfo); } static void quanta_gsj_init(MachineState *machine) @@ -390,7 +390,7 @@ static void quanta_gsj_init(MachineState *machine) drive_get(IF_MTD, 0, 0)); quanta_gsj_i2c_init(soc); quanta_gsj_fan_init(NPCM7XX_MACHINE(machine), soc); - npcm7xx_load_kernel(machine, soc); + npcm7xx_load_kernel(machine, soc, &NPCM7XX_MACHINE(machine)->bootinfo); } static void quanta_gbs_init(MachineState *machine) @@ -408,7 +408,7 @@ static void quanta_gbs_init(MachineState *machine) quanta_gbs_i2c_init(soc); sdhci_attach_drive(&soc->mmc.sdhci, 0); - npcm7xx_load_kernel(machine, soc); + npcm7xx_load_kernel(machine, soc, &NPCM7XX_MACHINE(machine)->bootinfo); } static void kudo_bmc_init(MachineState *machine) @@ -427,7 +427,7 @@ static void kudo_bmc_init(MachineState *machine) kudo_bmc_i2c_init(soc); sdhci_attach_drive(&soc->mmc.sdhci, 0); - npcm7xx_load_kernel(machine, soc); + npcm7xx_load_kernel(machine, soc, &NPCM7XX_MACHINE(machine)->bootinfo); } static void mori_bmc_init(MachineState *machine) @@ -442,7 +442,7 @@ static void mori_bmc_init(MachineState *machine) npcm7xx_connect_flash(&soc->fiu[1], 0, "mx66u51235f", drive_get(IF_MTD, 3, 0)); - npcm7xx_load_kernel(machine, soc); + npcm7xx_load_kernel(machine, soc, &NPCM7XX_MACHINE(machine)->bootinfo); } static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type) diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h index eef7cc5332..9f3dd489ec 100644 --- a/include/hw/arm/npcm7xx.h +++ b/include/hw/arm/npcm7xx.h @@ -19,6 +19,7 @@ #include "hw/core/boards.h" #include "hw/adc/npcm7xx_adc.h" #include "hw/core/split-irq.h" +#include "hw/arm/boot.h" #include "hw/cpu/a9mpcore.h" #include "hw/gpio/npcm7xx_gpio.h" #include "hw/i2c/npcm7xx_smbus.h" @@ -62,6 +63,7 @@ struct NPCM7xxMachine { */ SplitIRQ fan_splitter[NPCM7XX_NR_PWM_MODULES * NPCM7XX_PWM_PER_MODULE]; + struct arm_boot_info bootinfo; }; #define TYPE_NPCM7XX_MACHINE MACHINE_TYPE_NAME("npcm7xx") @@ -129,11 +131,15 @@ typedef struct NPCM7xxClass { * npcm7xx_load_kernel - Loads memory with everything needed to boot * @machine - The machine containing the SoC to be booted. * @soc - The SoC containing the CPU to be booted. + * @binfo - Caller owned boot info structure to be filled in. * * This will set up the ARM boot info structure for the specific NPCM7xx * derivative and call arm_load_kernel() to set up loading of the kernel, etc. - * into memory, if requested by the user. + * into memory, if requested by the user. The boot info is owned by the + * caller because arm_load_kernel() keeps a pointer to it for the lifetime + * of the CPUs. */ -void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc); +void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc, + struct arm_boot_info *binfo); #endif /* NPCM7XX_H */ From 244b54269530468b93b4bc3676f044f3da46ea15 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:44 +0800 Subject: [PATCH 469/627] hw/arm: npcm8xx: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object inside npcm8xx_load_kernel(). Let the caller own the boot info: the board stores it in its NPCM8xxMachine and passes it to npcm8xx_load_kernel(), which only fills in the SoC specific values. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-15-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/npcm8xx.c | 26 ++++++++++++-------------- hw/arm/npcm8xx_boards.c | 2 +- include/hw/arm/npcm8xx.h | 10 ++++++++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c index 9ce6ea52d9..7d707a09b4 100644 --- a/hw/arm/npcm8xx.c +++ b/hw/arm/npcm8xx.c @@ -357,22 +357,20 @@ static const struct { }, }; -static struct arm_boot_info npcm8xx_binfo = { - .loader_start = NPCM8XX_LOADER_START, - .smp_loader_start = NPCM8XX_SMP_LOADER_START, - .smp_bootreg_addr = NPCM8XX_SMP_BOOTREG_ADDR, - .gic_cpu_if_addr = NPCM8XX_GICC_BA, - .secure_boot = false, - .board_id = -1, - .board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR, - .psci_conduit = QEMU_PSCI_CONDUIT_SMC, -}; - -void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc) +void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc, + struct arm_boot_info *binfo) { - npcm8xx_binfo.ram_size = machine->ram_size; + binfo->loader_start = NPCM8XX_LOADER_START; + binfo->smp_loader_start = NPCM8XX_SMP_LOADER_START; + binfo->smp_bootreg_addr = NPCM8XX_SMP_BOOTREG_ADDR; + binfo->gic_cpu_if_addr = NPCM8XX_GICC_BA; + binfo->secure_boot = false; + binfo->board_id = -1; + binfo->board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR; + binfo->psci_conduit = QEMU_PSCI_CONDUIT_SMC; + binfo->ram_size = machine->ram_size; - arm_load_kernel(&soc->cpu[0], machine, &npcm8xx_binfo); + arm_load_kernel(&soc->cpu[0], machine, binfo); } static void npcm8xx_init_fuses(NPCM8xxState *s) diff --git a/hw/arm/npcm8xx_boards.c b/hw/arm/npcm8xx_boards.c index 042a928857..f462369bea 100644 --- a/hw/arm/npcm8xx_boards.c +++ b/hw/arm/npcm8xx_boards.c @@ -198,7 +198,7 @@ static void npcm845_evb_init(MachineState *machine) npcm8xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0)); npcm845_evb_i2c_init(soc); npcm845_evb_fan_init(NPCM8XX_MACHINE(machine), soc); - npcm8xx_load_kernel(machine, soc); + npcm8xx_load_kernel(machine, soc, &NPCM8XX_MACHINE(machine)->bootinfo); } static void npcm8xx_set_soc_type(NPCM8xxMachineClass *nmc, const char *type) diff --git a/include/hw/arm/npcm8xx.h b/include/hw/arm/npcm8xx.h index a8377db490..676c82150d 100644 --- a/include/hw/arm/npcm8xx.h +++ b/include/hw/arm/npcm8xx.h @@ -23,6 +23,7 @@ #include "hw/i2c/npcm7xx_smbus.h" #include "hw/intc/arm_gic_common.h" #include "hw/mem/npcm7xx_mc.h" +#include "hw/arm/boot.h" #include "hw/misc/npcm_clk.h" #include "hw/misc/npcm_gcr.h" #include "hw/misc/npcm7xx_mft.h" @@ -62,6 +63,7 @@ struct NPCM8xxMachine { */ SplitIRQ fan_splitter[NPCM8XX_NR_PWM_MODULES * NPCM7XX_PWM_PER_MODULE]; + struct arm_boot_info bootinfo; }; @@ -122,11 +124,15 @@ OBJECT_DECLARE_TYPE(NPCM8xxState, NPCM8xxClass, NPCM8XX) * npcm8xx_load_kernel - Loads memory with everything needed to boot * @machine - The machine containing the SoC to be booted. * @soc - The SoC containing the CPU to be booted. + * @binfo - Caller owned boot info structure to be filled in. * * This will set up the ARM boot info structure for the specific NPCM8xx * derivative and call arm_load_kernel() to set up loading of the kernel, etc. - * into memory, if requested by the user. + * into memory, if requested by the user. The boot info is owned by the + * caller because arm_load_kernel() keeps a pointer to it for the lifetime + * of the CPUs. */ -void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc); +void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc, + struct arm_boot_info *binfo); #endif /* NPCM8XX_H */ From 53fad63eeb954200b667255b87e6d74b52720863 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:45 +0800 Subject: [PATCH 470/627] hw/arm: omap_sx1: Store boot info in the machine state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Give both the sx1 and sx1-v1 machine types the same Sx1MachineState instance struct and store the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260816131300.51799-16-bin.meng@processmission.com Signed-off-by: Peter Maydell --- hw/arm/omap_sx1.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index bcb7105323..3b628d13cb 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -91,14 +91,16 @@ static const MemoryRegionOps static_ops = { #define FLASH1_SIZE (8 * MiB) #define FLASH2_SIZE (32 * MiB) -static struct arm_boot_info sx1_binfo = { - .loader_start = OMAP_EMIFF_BASE, - .ram_size = SDRAM_SIZE, - .board_id = 0x265, -}; +typedef struct Sx1MachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +} Sx1MachineState; static void sx1_init(MachineState *machine, const int version) { + /* Both sx1 and sx1-v1 embed the same state as their first member */ + Sx1MachineState *sms = (Sx1MachineState *)machine; struct omap_mpu_state_s *mpu; MachineClass *mc = MACHINE_GET_CLASS(machine); MemoryRegion *address_space = get_system_memory(); @@ -187,7 +189,10 @@ static void sx1_init(MachineState *machine, const int version) } /* Load the kernel. */ - arm_load_kernel(mpu->cpu, machine, &sx1_binfo); + sms->bootinfo.loader_start = OMAP_EMIFF_BASE; + sms->bootinfo.ram_size = SDRAM_SIZE; + sms->bootinfo.board_id = 0x265; + arm_load_kernel(mpu->cpu, machine, &sms->bootinfo); /* TODO: fix next line */ //~ qemu_console_resize(ds, 640, 480); @@ -220,6 +225,7 @@ static const TypeInfo sx1_machine_v2_type = { .name = MACHINE_TYPE_NAME("sx1"), .parent = TYPE_MACHINE, .class_init = sx1_machine_v2_class_init, + .instance_size = sizeof(Sx1MachineState), .interfaces = arm_machine_interfaces, }; @@ -240,6 +246,7 @@ static const TypeInfo sx1_machine_v1_type = { .name = MACHINE_TYPE_NAME("sx1-v1"), .parent = TYPE_MACHINE, .class_init = sx1_machine_v1_class_init, + .instance_size = sizeof(Sx1MachineState), .interfaces = arm_machine_interfaces, }; From ab7794550fd24d1caca87e86f16d542195a02ce2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:46 +0800 Subject: [PATCH 471/627] hw/arm: orangepi: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move it into a new OrangePiMachineState and register the machine type explicitly instead of through the DEFINE_MACHINE_ARM macro. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Niek Linnenbank Message-id: 20260816131300.51799-17-bin.meng@processmission.com Signed-off-by: Peter Maydell --- hw/arm/orangepi.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index d84443bb7b..0e149ed6c9 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -28,10 +28,18 @@ #include "hw/arm/boot.h" #include "hw/arm/machines-qom.h" -static struct arm_boot_info orangepi_binfo; +#define TYPE_ORANGEPI_MACHINE MACHINE_TYPE_NAME("orangepi-pc") +OBJECT_DECLARE_SIMPLE_TYPE(OrangePiMachineState, ORANGEPI_MACHINE) + +struct OrangePiMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +}; static void orangepi_init(MachineState *machine) { + OrangePiMachineState *opms = ORANGEPI_MACHINE(machine); AwH3State *h3; DriveInfo *di; BlockBackend *blk; @@ -98,10 +106,10 @@ static void orangepi_init(MachineState *machine) /* Use Boot ROM to copy data from SD card to SRAM */ allwinner_h3_bootrom_setup(h3, blk); } - orangepi_binfo.loader_start = h3->memmap[AW_H3_DEV_SDRAM]; - orangepi_binfo.ram_size = machine->ram_size; - orangepi_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; - arm_load_kernel(&h3->cpus[0], machine, &orangepi_binfo); + opms->bootinfo.loader_start = h3->memmap[AW_H3_DEV_SDRAM]; + opms->bootinfo.ram_size = machine->ram_size; + opms->bootinfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC; + arm_load_kernel(&h3->cpus[0], machine, &opms->bootinfo); } static void orangepi_machine_init(MachineClass *mc) @@ -125,4 +133,6 @@ static void orangepi_machine_init(MachineClass *mc) mc->auto_create_sdcard = true; } -DEFINE_MACHINE_ARM("orangepi-pc", orangepi_machine_init) +DEFINE_MACHINE_EXTENDED("orangepi-pc", MACHINE, OrangePiMachineState, + orangepi_machine_init, false, + arm_machine_interfaces) From 42a64af521af89eac0272d6705b251c1b3fbf719 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:47 +0800 Subject: [PATCH 472/627] hw/arm: realview: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Give all four realview machine types the same RealViewMachineState instance struct and store the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-18-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/realview.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 2b9f3271d6..0c2daf5c01 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -39,10 +39,11 @@ /* Board init. */ -static struct arm_boot_info realview_binfo = { - .smp_loader_start = SMP_BOOT_ADDR, - .smp_bootreg_addr = SMP_BOOTREG_ADDR, -}; +typedef struct RealViewMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +} RealViewMachineState; /* The following two lists must be consistent. */ enum realview_board_type { @@ -76,6 +77,8 @@ static void split_irq_from_named(DeviceState *src, const char* outname, static void realview_init(MachineState *machine, enum realview_board_type board_type) { + /* All realview-* machines embed the same state as their first member */ + RealViewMachineState *rvms = (RealViewMachineState *)machine; ARMCPU *cpu = NULL; CPUARMState *env; MemoryRegion *sysmem = get_system_memory(); @@ -202,7 +205,7 @@ static void realview_init(MachineState *machine, } sysbus_create_varargs("l2x0", periphbase + 0x2000, NULL); /* Both A9 and 11MPCore put the GIC CPU i/f at base + 0x100 */ - realview_binfo.gic_cpu_if_addr = periphbase + 0x100; + rvms->bootinfo.gic_cpu_if_addr = periphbase + 0x100; } else { uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; /* For now just create the nIRQ GIC, and ignore the others. */ @@ -387,10 +390,12 @@ static void realview_init(MachineState *machine, &error_fatal); memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack); - realview_binfo.ram_size = ram_size; - realview_binfo.board_id = realview_board_id[board_type]; - realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0); - arm_load_kernel(cpu, machine, &realview_binfo); + rvms->bootinfo.smp_loader_start = SMP_BOOT_ADDR; + rvms->bootinfo.smp_bootreg_addr = SMP_BOOTREG_ADDR; + rvms->bootinfo.ram_size = ram_size; + rvms->bootinfo.board_id = realview_board_id[board_type]; + rvms->bootinfo.loader_start = board_type == BOARD_PB_A8 ? 0x70000000 : 0; + arm_load_kernel(cpu, machine, &rvms->bootinfo); } static void realview_eb_init(MachineState *machine) @@ -431,6 +436,7 @@ static const TypeInfo realview_eb_type = { .name = MACHINE_TYPE_NAME("realview-eb"), .parent = TYPE_MACHINE, .class_init = realview_eb_class_init, + .instance_size = sizeof(RealViewMachineState), .interfaces = arm_machine_interfaces, }; @@ -453,6 +459,7 @@ static const TypeInfo realview_eb_mpcore_type = { .name = MACHINE_TYPE_NAME("realview-eb-mpcore"), .parent = TYPE_MACHINE, .class_init = realview_eb_mpcore_class_init, + .instance_size = sizeof(RealViewMachineState), .interfaces = arm_machine_interfaces, }; @@ -473,6 +480,7 @@ static const TypeInfo realview_pb_a8_type = { .name = MACHINE_TYPE_NAME("realview-pb-a8"), .parent = TYPE_MACHINE, .class_init = realview_pb_a8_class_init, + .instance_size = sizeof(RealViewMachineState), .interfaces = arm_machine_interfaces, }; @@ -494,6 +502,7 @@ static const TypeInfo realview_pbx_a9_type = { .name = MACHINE_TYPE_NAME("realview-pbx-a9"), .parent = TYPE_MACHINE, .class_init = realview_pbx_a9_class_init, + .instance_size = sizeof(RealViewMachineState), .interfaces = arm_machine_interfaces, }; From 4a421f0a7b9a6ee8221480fb026a2da9ebad3572 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:48 +0800 Subject: [PATCH 473/627] hw/arm: sabrelite: Store boot info in the machine state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move the boot info into the existing SabreliteMachineState. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Message-id: 20260816131300.51799-19-bin.meng@processmission.com Signed-off-by: Peter Maydell --- hw/arm/sabrelite.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index 84bbc2f979..140b2ecb9e 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -25,18 +25,12 @@ struct SabreliteMachineState { FslIMX6State soc; CanBusState *canbus[FSL_IMX6_NUM_CANS]; + struct arm_boot_info bootinfo; }; #define TYPE_SABRELITE_MACHINE MACHINE_TYPE_NAME("sabrelite") OBJECT_DECLARE_SIMPLE_TYPE(SabreliteMachineState, SABRELITE_MACHINE) -static struct arm_boot_info sabrelite_binfo = { - /* DDR memory start */ - .loader_start = FSL_IMX6_MMDC_ADDR, - /* No board ID, we boot from DT tree */ - .board_id = -1, -}; - /* No need to do any particular setup for secondary boot */ static void sabrelite_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info) @@ -110,13 +104,17 @@ static void sabrelite_init(MachineState *machine) } } - sabrelite_binfo.ram_size = machine->ram_size; - sabrelite_binfo.secure_boot = true; - sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary; - sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; + /* DDR memory start */ + s->bootinfo.loader_start = FSL_IMX6_MMDC_ADDR; + /* No board ID, we boot from DT tree */ + s->bootinfo.board_id = -1; + s->bootinfo.ram_size = machine->ram_size; + s->bootinfo.secure_boot = true; + s->bootinfo.write_secondary_boot = sabrelite_write_secondary; + s->bootinfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu[0], machine, &sabrelite_binfo); + arm_load_kernel(&s->soc.cpu[0], machine, &s->bootinfo); } } From 4477c1448252fc33c978db30e96d1787ebd4df80 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:49 +0800 Subject: [PATCH 474/627] hw/arm: versatilepb: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Give both machine types the same VersatileMachineState instance struct and store the boot info there. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Message-id: 20260816131300.51799-20-bin.meng@processmission.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/versatilepb.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index c6991a52e6..520af79c80 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -182,10 +182,16 @@ static void vpb_sic_init(Object *obj) peripherals and expansion busses. For now we emulate a subset of the PB peripherals and just change the board ID. */ -static struct arm_boot_info versatile_binfo; +typedef struct VersatileMachineState { + MachineState parent; + + struct arm_boot_info bootinfo; +} VersatileMachineState; static void versatile_init(MachineState *machine, int board_id) { + /* versatilepb and versatileab embed the same state as first member */ + VersatileMachineState *vms = (VersatileMachineState *)machine; Object *cpuobj; ARMCPU *cpu; MemoryRegion *sysmem = get_system_memory(); @@ -397,9 +403,9 @@ static void versatile_init(MachineState *machine, int board_id) VERSATILE_FLASH_SECT_SIZE, 4, 0x0089, 0x0018, 0x0000, 0x0, 0); - versatile_binfo.ram_size = machine->ram_size; - versatile_binfo.board_id = board_id; - arm_load_kernel(cpu, machine, &versatile_binfo); + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.board_id = board_id; + arm_load_kernel(cpu, machine, &vms->bootinfo); } static void vpb_init(MachineState *machine) @@ -431,6 +437,7 @@ static const TypeInfo versatilepb_type = { .name = MACHINE_TYPE_NAME("versatilepb"), .parent = TYPE_MACHINE, .class_init = versatilepb_class_init, + .instance_size = sizeof(VersatileMachineState), .interfaces = arm_machine_interfaces, }; @@ -453,6 +460,7 @@ static const TypeInfo versatileab_type = { .name = MACHINE_TYPE_NAME("versatileab"), .parent = TYPE_MACHINE, .class_init = versatileab_class_init, + .instance_size = sizeof(VersatileMachineState), .interfaces = arm_machine_interfaces, }; From 37c0a0059db0dd6f35945196ddb17684c458886a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 16 Aug 2026 21:12:50 +0800 Subject: [PATCH 475/627] hw/arm: xilinx_zynq: Store boot info in the machine state arm_load_kernel() keeps a pointer to the boot info struct for the lifetime of the VM, so the struct logically belongs to the machine rather than to a file scoped static object. Move the boot info into the existing ZynqMachineState. As in the xlnx-zcu102 and raspi machines, the boot info belongs to the machine rather than to a static object: 4d1ac883a7 ("hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102") 0f15c6e338 ("hw/arm/raspi: Move arm_boot_info structure to RaspiMachineState") Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20260816131300.51799-21-bin.meng@processmission.com Signed-off-by: Peter Maydell --- hw/arm/xilinx_zynq.c | 17 ++++++++--------- include/hw/arm/xilinx_zynq.h | 2 ++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 6c83439017..f314897540 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -103,8 +103,6 @@ static void zynq_write_board_setup(ARMCPU *cpu, sizeof(board_setup_blob), BOARD_SETUP_ADDR); } -static struct arm_boot_info zynq_binfo = {}; - static void gem_init(uint32_t base, qemu_irq irq) { DeviceState *dev; @@ -268,7 +266,7 @@ static void zynq_init(MachineState *machine) busdev = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE); - zynq_binfo.gic_cpu_if_addr = MPCORE_PERIPHBASE + 0x100; + zynq_machine->bootinfo.gic_cpu_if_addr = MPCORE_PERIPHBASE + 0x100; sysbus_create_varargs("l2x0", MPCORE_PERIPHBASE + 0x2000, NULL); for (n = 0; n < smp_cpus; n++) { /* See "hw/intc/arm_gic.h" for the IRQ line association */ @@ -444,13 +442,14 @@ static void zynq_init(MachineState *machine) create_unimplemented_device("zynq.qos301_dmac", 0xF8947000, 0x130); create_unimplemented_device("zynq.qos301_iou", 0xF8948000, 0x130); - zynq_binfo.ram_size = machine->ram_size; - zynq_binfo.board_id = 0xd32; - zynq_binfo.loader_start = 0; - zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR; - zynq_binfo.write_board_setup = zynq_write_board_setup; + zynq_machine->bootinfo.ram_size = machine->ram_size; + zynq_machine->bootinfo.board_id = 0xd32; + zynq_machine->bootinfo.loader_start = 0; + zynq_machine->bootinfo.board_setup_addr = BOARD_SETUP_ADDR; + zynq_machine->bootinfo.write_board_setup = zynq_write_board_setup; - arm_load_kernel(zynq_machine->cpu[0], machine, &zynq_binfo); + arm_load_kernel(zynq_machine->cpu[0], machine, + &zynq_machine->bootinfo); } static void zynq_machine_class_init(ObjectClass *oc, const void *data) diff --git a/include/hw/arm/xilinx_zynq.h b/include/hw/arm/xilinx_zynq.h index cefb7789ff..669c516ad1 100644 --- a/include/hw/arm/xilinx_zynq.h +++ b/include/hw/arm/xilinx_zynq.h @@ -14,6 +14,7 @@ #include "target/arm/cpu-qom.h" #include "hw/core/qdev-clock.h" +#include "hw/arm/boot.h" #define TYPE_ZYNQ_MACHINE MACHINE_TYPE_NAME("xilinx-zynq-a9") OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE) @@ -25,6 +26,7 @@ struct ZynqMachineState { Clock *ps_clk; ARMCPU *cpu[ZYNQ_MAX_CPUS]; uint8_t boot_mode; + struct arm_boot_info bootinfo; }; #endif /* QEMU_ARM_ZYNQ_H */ From fa6a91fd8cb917fbe08b701f861d8ece9d571b4e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 20 Jul 2026 19:24:03 +0000 Subject: [PATCH 476/627] target/ppc/cpu_init: make cpu listing deterministic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing compare function only make sure that we list cpus with PVR order. However, we never compare cpu names. As a result, while cpus are grouped per PVR, the order within a group is non deterministic. Depending on QOM type initialization order, we get different results for -cpu help. For instance, previous output could be: Available CPUs: 755_v1.0 PVR 00083100 745_v1.0 PVR 00083100 755_v1.1 PVR 00083101 745_v1.1 PVR 00083101 While a sorted output should be: Available CPUs: 745_v1.0 PVR 00083100 755_v1.0 PVR 00083100 745_v1.1 PVR 00083101 755_v1.1 PVR 00083101 Fix it by comparing cpu names to have a stable result. This allows us to record and compare various command line results across versions to make sure we didn't break anything while working on single-binary. Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Amit Machhiwal Tested-by: Amit Machhiwal Link: https://lore.kernel.org/qemu-devel/20260720192403.66694-1-pierrick.bouvier@oss.qualcomm.com Signed-off-by: Harsh Prateek Bora --- target/ppc/cpu_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index e3a1075aad..e2533481d8 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7130,7 +7130,7 @@ static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b, gpointer d) } else if (pcc_a->pvr > pcc_b->pvr) { return 1; } else { - return 0; + return strcmp(name_a, name_b); } } } From e2bbc72a66674315a8e13c77f5ecaffd7edc398a Mon Sep 17 00:00:00 2001 From: Minhang Zhang Date: Fri, 14 Aug 2026 17:26:32 +0800 Subject: [PATCH 477/627] target/ppc: Validate HTABMASK and reserved bits in SDR1 for 32-bit mode ppc_store_sdr1() had validation for 64-bit SDR1 values but lacked corresponding checks for the 32-bit case. According to the Power ISA, in 32-bit mode SDR1 bits 16-22 are reserved (must be zero) and HTABMASK (bits 23-31) must consist of a consecutive string of 1-bits starting from the LSB, i.e., be of the form 2^n-1. Add checks to reject invalid HTABMASK values and log a guest error for non-zero reserved bits, following the same pattern used by the existing 64-bit validation. Reviewed-by: Chinmay Rath Signed-off-by: Minhang Zhang Link: https://lore.kernel.org/qemu-devel/tencent_8388D4B38DC5172F5EEE70436D3AD6D02006@qq.com Signed-off-by: Harsh Prateek Bora --- target/ppc/mmu_common.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 2499e619f8..2a36817181 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -42,24 +42,39 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) PowerPCCPU *cpu = env_archcpu(env); qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); assert(!cpu->env.has_hv_mode || !cpu->vhyp); -#if defined(TARGET_PPC64) if (mmu_is_64bit(env->mmu_model)) { +#if defined(TARGET_PPC64) target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE; target_ulong htabsize = value & SDR_64_HTABSIZE; if (value & ~sdr_mask) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid bits 0x"TARGET_FMT_lx - " set in SDR1", value & ~sdr_mask); + " set in SDR1\n", value & ~sdr_mask); value &= sdr_mask; } if (htabsize > 28) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid HTABSIZE 0x" TARGET_FMT_lx - " stored in SDR1", htabsize); + " stored in SDR1\n", htabsize); + return; + } +#endif /* defined(TARGET_PPC64) */ + } else { + target_ulong sdr_mask = SDR_32_HTABORG | SDR_32_HTABMASK; + target_ulong htabmask = value & SDR_32_HTABMASK; + + if (value & ~sdr_mask) { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid bits 0x" TARGET_FMT_lx + " set in SDR1\n", value & ~sdr_mask); + value &= sdr_mask; + } + if ((htabmask & (htabmask + 1)) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "Invalid HTABMASK 0x" TARGET_FMT_lx + " in SDR1 (must be of form 2^n-1)\n", htabmask); return; } } -#endif /* defined(TARGET_PPC64) */ - /* FIXME: Should check for valid HTABMASK values in 32-bit case */ env->spr[SPR_SDR1] = value; } From ac6a32a106666e8b75e83d1a9e14fa653c1e3dae Mon Sep 17 00:00:00 2001 From: Amit Machhiwal Date: Wed, 19 Aug 2026 10:35:45 +0530 Subject: [PATCH 478/627] MAINTAINERS: Add myself as a reviewer for PPC KVM and sPAPR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have been contributing to PPC KVM and sPAPR (pseries) for some time now and would like to get notified of incoming changes to help with code reviews. Signed-off-by: Amit Machhiwal Acked-by: Gautam Menghani Acked-by: Chinmay Rath Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20260819050545.21232-1-amachhiw@linux.ibm.com Signed-off-by: Harsh Prateek Bora --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 08017f4786..79e6c8e0b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -497,6 +497,7 @@ F: tests/functional/aarch64/test_kvm.py PPC KVM CPUs M: Nicholas Piggin R: Harsh Prateek Bora +R: Amit Machhiwal S: Odd Fixes F: target/ppc/kvm.c @@ -1662,6 +1663,7 @@ F: tests/functional/ppc/test_40p.py sPAPR (pseries) M: Nicholas Piggin M: Harsh Prateek Bora +R: Amit Machhiwal L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/*/spapr* From eea4de1bd8e8bdaa9a69b130a1a154f7c113979f Mon Sep 17 00:00:00 2001 From: Chinmay Rath Date: Tue, 18 Aug 2026 16:15:51 +0530 Subject: [PATCH 479/627] hw/watchdog: Add lower bound check for watchdogNumber Add missing lower bound check for H_WATCHDOG H_CALL's watchdogNumber parameter as per PAPR documentation ver 12.10.00 section 14.15.5 'H_WATCHDOG'. Closes : https://gitlab.com/qemu-project/qemu/-/work_items/3600 Reviewed-by: Amit Machhiwal Reported-by: huntr bubble Signed-off-by: Chinmay Rath Link: https://lore.kernel.org/qemu-devel/20260818104551.76023-1-rathc@linux.ibm.com [harshpb: corrected title prefix to hw/watchdog] Signed-off-by: Harsh Prateek Bora --- hw/watchdog/spapr_watchdog.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/watchdog/spapr_watchdog.c b/hw/watchdog/spapr_watchdog.c index 5b3f50de3a..5a72896066 100644 --- a/hw/watchdog/spapr_watchdog.c +++ b/hw/watchdog/spapr_watchdog.c @@ -127,6 +127,12 @@ static void watchdog_expired(void *pw) } } +static inline bool watchdog_number_valid(target_ulong watchdogNumber, + SpaprMachineState *spapr) +{ + return watchdogNumber >= 1 && watchdogNumber <= ARRAY_SIZE(spapr->wds); +} + static target_ulong h_watchdog(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) @@ -145,7 +151,7 @@ static target_ulong h_watchdog(PowerPCCPU *cpu, switch (operation) { case PSERIES_WDTF_OP_START: - if (watchdogNumber > ARRAY_SIZE(spapr->wds)) { + if (!watchdog_number_valid(watchdogNumber, spapr)) { return H_P2; } if (timeoutInMs <= WDT_MIN_TIMEOUT) { @@ -170,11 +176,11 @@ static target_ulong h_watchdog(PowerPCCPU *cpu, case PSERIES_WDTF_OP_STOP: if (watchdogNumber == PSERIES_WDT_STOP_ALL) { ret = watchdog_stop_all(spapr); - } else if (watchdogNumber <= ARRAY_SIZE(spapr->wds)) { + } else if (!watchdog_number_valid(watchdogNumber, spapr)) { + return H_P2; + } else { ret = watchdog_stop(watchdogNumber, &spapr->wds[watchdogNumber - 1]); - } else { - return H_P2; } break; case PSERIES_WDTF_OP_QUERY: @@ -184,7 +190,7 @@ static target_ulong h_watchdog(PowerPCCPU *cpu, trace_spapr_watchdog_query(args[0]); break; case PSERIES_WDTF_OP_QUERY_LPM: - if (watchdogNumber > ARRAY_SIZE(spapr->wds)) { + if (!watchdog_number_valid(watchdogNumber, spapr)) { return H_P2; } args[0] = PSERIES_WDTQL_QUERY_NOT_STOPPED; From 504810bbdfd9c65a808b4684b2b0f6871f2d8c1c Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 19 Jul 2026 16:55:07 +0200 Subject: [PATCH 480/627] powernv: boot OpenBSD on POWER9 The POWER9 Processor User's Manual, section 4.9.4, specifies that POWER9 ignores PTCR[PATS] and only supports a 64 KiB partition table. Use an effective PATS value of 4 on POWER9; other processors keep the existing ISA v3.0 interpretation. The PSI model now exposes POWER9 IRQ level and pending status registers, and keeps both updated while delivering through the existing XIVE LSI source. This lets guests that select the POWER9 PSI LSI IRQ method continue to receive LPC interrupts. The blast radius is probably minimal: the PTCR change is limited to POWER9, while the PSI change only touches POWER9 PSI state and reuses the existing delivery path. Acked-by: Chinmay Rath Signed-off-by: Kirill A. Korinsky Reviewed-by: Aditya Gupta Link: https://lore.kernel.org/qemu-devel/20260719145559.94342-1-kirill@korins.ky Signed-off-by: Harsh Prateek Bora --- hw/ppc/pnv_psi.c | 11 ++++-- target/ppc/mmu-book3s-v3.c | 21 +++++++++-- tests/functional/ppc64/meson.build | 2 + tests/functional/ppc64/test_openbsd.py | 52 ++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) create mode 100755 tests/functional/ppc64/test_openbsd.py diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index e8701c6100..39ec448f3c 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -688,6 +688,8 @@ static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size) case PSIHB9_ESB_CI_BASE: case PSIHB9_ESB_NOTIF_ADDR: case PSIHB9_IVT_OFFSET: + case PSIHB9_IRQ_LEVEL: + case PSIHB9_IRQ_STAT: val = psi->regs[reg]; break; default: @@ -818,17 +820,20 @@ static void pnv_psi_power9_set_irq(void *opaque, int irq, int state) { PnvPsi *psi = opaque; uint64_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)]; + uint64_t irq_bit = PPC_BIT(irq); if (irq_method & PSIHB9_IRQ_METHOD) { qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n"); return; } - /* Update LSI levels */ + /* Update LSI levels and pending status */ if (state) { - psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq); + psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= irq_bit; + psi->regs[PSIHB_REG(PSIHB9_IRQ_STAT)] |= irq_bit; } else { - psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq); + psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~irq_bit; + psi->regs[PSIHB_REG(PSIHB9_IRQ_STAT)] &= ~irq_bit; } qemu_set_irq(psi->qirqs[irq], state); diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c index 3865556310..f329a7a0f2 100644 --- a/target/ppc/mmu-book3s-v3.c +++ b/target/ppc/mmu-book3s-v3.c @@ -23,24 +23,37 @@ #include "mmu-hash64.h" #include "mmu-book3s-v3.h" +#define PPC64_V3_PATE_SIZE 16 /* two 64-bit words */ + bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry) { uint64_t patb = cpu->env.spr[SPR_PTCR] & PTCR_PATB; uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS; + uint64_t table_size; + uint64_t entries; + + /* + * The POWER9 Processor User's Manual, section 4.9.4, specifies that + * POWER9 ignores PTCR[PATS] and only supports a 64 KiB partition table. + */ + if (cpu->env.excp_model == POWERPC_EXCP_POWER9) { + pats = 4; + } + table_size = 1ULL << (pats + 12); /* Check if partition table is properly aligned */ - if (patb & MAKE_64BIT_MASK(0, pats + 12)) { + if (patb & (table_size - 1)) { return false; } /* Calculate number of entries */ - pats = 1ull << (pats + 12 - 4); - if (pats <= lpid) { + entries = table_size / PPC64_V3_PATE_SIZE; + if (entries <= lpid) { return false; } /* Grab entry */ - patb += 16 * lpid; + patb += PPC64_V3_PATE_SIZE * lpid; entry->dw0 = ldq_phys(CPU(cpu)->as, patb); entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8); return true; diff --git a/tests/functional/ppc64/meson.build b/tests/functional/ppc64/meson.build index f0f8ab8f61..cb3c745624 100644 --- a/tests/functional/ppc64/meson.build +++ b/tests/functional/ppc64/meson.build @@ -4,6 +4,7 @@ test_ppc64_timeouts = { 'fadump' : 480, 'hv' : 1000, 'mac99' : 120, + 'openbsd' : 240, 'powernv' : 480, 'pseries' : 480, 'replay' : 210, @@ -20,6 +21,7 @@ tests_ppc64_system_thorough = [ 'fadump', 'hv', 'mac99', + 'openbsd', 'powernv', 'pseries', 'replay', diff --git a/tests/functional/ppc64/test_openbsd.py b/tests/functional/ppc64/test_openbsd.py new file mode 100755 index 0000000000..bdbef6bf82 --- /dev/null +++ b/tests/functional/ppc64/test_openbsd.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# +# Test that OpenBSD boots on a ppc powernv machine and reaches the installer. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern + + +class OpenBSDPowerNV(QemuSystemTest): + + ASSET_MINIROOT = Asset( + 'https://kirill.korins.ky/pub/qemu-powerpc64-openbsd/miniroot79.img', + '7829e42b75d81cafd732038b9d63228b79c1f5828d8375872a4bb655e1d6b13c') + + ASSET_BOOTKERNEL = Asset( + 'https://kirill.korins.ky/pub/qemu-powerpc64-openbsd/pnor.BOOTKERNEL', + '397ce43ce61910e1a2c4f13d301f957e61513a9ec5371bc3e87d3095411fae7b') + + def test_powernv9_openbsd_installer(self): + self.set_machine('powernv9') + self.require_accelerator('tcg') + + miniroot_path = self.ASSET_MINIROOT.fetch() + bootkernel_path = self.ASSET_BOOTKERNEL.fetch() + + self.vm.set_console() + self.vm.add_args('-cpu', 'power9', + '-accel', 'tcg,thread=single', + '-smp', '1,cores=1,threads=1', + '-m', '2g', + '-kernel', bootkernel_path, + '-device', + 'ich9-ahci,id=sata0,bus=pcie.0,addr=0x0', + '-drive', + f'file={miniroot_path},format=raw,if=none,' + 'id=bootdisk,snapshot=on', + '-device', + 'ide-hd,bus=sata0.0,unit=0,drive=bootdisk,' + 'bootindex=1') + self.vm.launch() + + wait_for_console_pattern(self, 'OpenBSD 7.9 (RAMDISK)', 'panic:') + wait_for_console_pattern( + self, + '(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?', + 'panic:') + + +if __name__ == '__main__': + QemuSystemTest.main() From 3e182317a65a217fc319fa88f2697d220781270b Mon Sep 17 00:00:00 2001 From: Shivang Upadhyay Date: Thu, 20 Aug 2026 01:07:54 +0530 Subject: [PATCH 481/627] MAINTAINERS: add dedicated PowerPC RAS section Introduce a new "PowerPC RAS (Reliability, Availability and Serviceability)" entry in the PowerPC Machines block, replacing the existing Fadump/MPIPL sections. Retaining the maintainer and reviewer entries from Fadump/MPIPL sections for this broader umbrella. Currently most of RAS related code sits in spapr_rtas.c, So Adding it to PowerPC RAS section. Additionally adding spapr_events.c, as it implements RTAS error logging infrastructure and spapr_pci_vfio.c, since its all EEH related code. Acked-by: Sourabh Jain Acked-by: Aditya Gupta Signed-off-by: Shivang Upadhyay Acked-by: Hari Bathini Link: https://lore.kernel.org/qemu-devel/20260819193757.1072909-2-shivangu@linux.ibm.com Signed-off-by: Harsh Prateek Bora --- MAINTAINERS | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 79e6c8e0b2..c47e0790ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1765,6 +1765,21 @@ F: include/hw/ppc/vof* F: pc-bios/vof/* F: pc-bios/vof* +PowerPC RAS (Reliability, Availability and Serviceability) +M: Aditya Gupta +R: Sourabh Jain +R: Hari Bathini +L: qemu-ppc@nongnu.org +S: Maintained +F: hw/ppc/spapr_events.c +F: hw/ppc/spapr_fadump.c +F: hw/ppc/spapr_pci_vfio.c +F: hw/ppc/spapr_rtas.c +F: hw/ppc/pnv_mpipl.c +F: include/hw/ppc/spapr_fadump.h +F: include/hw/ppc/pnv_mpipl.h +F: tests/functional/ppc64/test_fadump.py + RISC-V Machines --------------- OpenTitan @@ -3402,23 +3417,6 @@ F: scripts/coccinelle/remove_local_err.cocci F: scripts/coccinelle/use-error_fatal.cocci F: scripts/coccinelle/errp-guard.cocci -Firmware Assisted Dump (fadump) for sPAPR (pseries) -M: Aditya Gupta -R: Sourabh Jain -S: Maintained -F: include/hw/ppc/spapr_fadump.h -F: hw/ppc/spapr_fadump.c -F: tests/functional/ppc64/test_fadump.py - -Memory-Preserving Initial Program Load (MPIPL) for PowerNV -M: Aditya Gupta -R: Hari Bathini -R: Sourabh -S: Maintained -F: include/hw/ppc/pnv_mpipl.h -F: hw/ppc/pnv_mpipl.c -F: tests/functional/ppc64/test_fadump.py - GDB stub M: Alex Bennée R: Philippe Mathieu-Daudé From 45caf67b9a6a446629e1c133b76a3d9a3cebdcf1 Mon Sep 17 00:00:00 2001 From: Shivang Upadhyay Date: Thu, 20 Aug 2026 01:07:55 +0530 Subject: [PATCH 482/627] MAINTAINERS: add self as reviewer for PowerPC RAS I have been contributing to Fadump, MPIPL as well as PowerNV for quite some time, and my daily work responsibilities includes taking care of PowerPC RAS features. I, therefore would like to step up as a reviewer to get notified of incoming changes in this area and help reviewing them. Acked-by: Aditya Gupta Signed-off-by: Shivang Upadhyay Link: https://lore.kernel.org/qemu-devel/20260819193757.1072909-3-shivangu@linux.ibm.com Signed-off-by: Harsh Prateek Bora --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c47e0790ba..60c7f51c23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1769,6 +1769,7 @@ PowerPC RAS (Reliability, Availability and Serviceability) M: Aditya Gupta R: Sourabh Jain R: Hari Bathini +R: Shivang Upadhyay L: qemu-ppc@nongnu.org S: Maintained F: hw/ppc/spapr_events.c From 798eddba103250385a3b2973890e0b757704b584 Mon Sep 17 00:00:00 2001 From: Junze Cao Date: Fri, 7 Aug 2026 18:21:16 +0800 Subject: [PATCH 483/627] hw/misc: Add K230 DDR controller and PHY models The K230 SDK U-Boot SPL programs K230 DDRC CFG and K230 DDR PHY registers before DRAM can be used. Add separate SysBus devices for both register ranges. Model controller reset values, DFI and software-update handshakes. For the PHY, model register ownership, the training mailbox, and DFI completion. Include migration state for both devices. Signed-off-by: Junze Cao Suggested-by: Chao Liu Reviewed-by: Daniel Henrique Barboza Message-ID: <20260807-k230-ddr-v2-v2-1-c531308ae819@gmail.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 2 + hw/misc/k230_ddr.c | 556 +++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + include/hw/misc/k230_ddr.h | 59 ++++ 4 files changed, 618 insertions(+) create mode 100644 hw/misc/k230_ddr.c create mode 100644 include/hw/misc/k230_ddr.h diff --git a/MAINTAINERS b/MAINTAINERS index 08017f4786..cc0879c868 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1844,8 +1844,10 @@ M: Chao Liu L: qemu-riscv@nongnu.org S: Maintained F: docs/system/riscv/k230.rst +F: hw/misc/k230_ddr.c F: hw/riscv/k230.c F: hw/watchdog/k230_wdt.c +F: include/hw/misc/k230_ddr.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: tests/functional/riscv64/test_k230.py diff --git a/hw/misc/k230_ddr.c b/hw/misc/k230_ddr.c new file mode 100644 index 0000000000..dac700b201 --- /dev/null +++ b/hw/misc/k230_ddr.c @@ -0,0 +1,556 @@ +/* + * Kendryte K230 DDR controller and PHY models + * + * Models the K230 DDRC CFG registers and K230 DDR PHY registers exercised + * by the K230 SDK U-Boot SPL. + * + * Copyright (c) 2026 Junze Cao + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "migration/vmstate.h" +#include "hw/core/registerfields.h" +#include "hw/core/resettable.h" +#include "hw/misc/k230_ddr.h" + +/* DDRC CFG registers */ + +enum K230DDRCOperatingMode { + K230_DDRC_MODE_INIT = 0, + K230_DDRC_MODE_NORMAL = 1, +}; + +REG32(K230_DDRC_MSTR, 0x000) + +REG32(K230_DDRC_STAT, 0x004) + FIELD(K230_DDRC_STAT, OPERATING_MODE, 0, 3) + +REG32(K230_DDRC_PWRCTL, 0x030) + +REG32(K230_DDRC_RFSHCTL0, 0x050) + +REG32(K230_DDRC_RFSHTMG, 0x064) + +REG32(K230_DDRC_RFSHTMG1, 0x068) + +REG32(K230_DDRC_INIT0, 0x0d0) + +REG32(K230_DDRC_INIT2, 0x0d8) + +REG32(K230_DDRC_INIT3, 0x0dc) + +REG32(K230_DDRC_INIT5, 0x0e4) + +REG32(K230_DDRC_DRAMTMG0, 0x100) +#define R_K230_DDRC_DRAMTMG(index) \ + (R_K230_DDRC_DRAMTMG0 + (index)) + +REG32(K230_DDRC_ZQCTL0, 0x180) + +REG32(K230_DDRC_ZQCTL1, 0x184) + +REG32(K230_DDRC_ZQCTL2, 0x188) + +REG32(K230_DDRC_ZQSTAT, 0x18c) + +REG32(K230_DDRC_DFITMG0, 0x190) + +REG32(K230_DDRC_DFITMG1, 0x194) + +REG32(K230_DDRC_DFIUPD0, 0x1a0) + +REG32(K230_DDRC_DFIUPD1, 0x1a4) + +REG32(K230_DDRC_DFIUPD2, 0x1a8) + +REG32(K230_DDRC_DFIMISC, 0x1b0) + FIELD(K230_DDRC_DFIMISC, DFI_INIT_COMPLETE_EN, 0, 1) + FIELD(K230_DDRC_DFIMISC, DFI_INIT_START, 5, 1) + +REG32(K230_DDRC_DFITMG2, 0x1b4) + +REG32(K230_DDRC_DFISTAT, 0x1bc) + FIELD(K230_DDRC_DFISTAT, DFI_INIT_COMPLETE, 0, 1) + +REG32(K230_DDRC_ODTCFG, 0x240) + +REG32(K230_DDRC_SWCTL, 0x320) + FIELD(K230_DDRC_SWCTL, SW_DONE, 0, 1) + +REG32(K230_DDRC_SWSTAT, 0x324) + FIELD(K230_DDRC_SWSTAT, SW_DONE_ACK, 0, 1) + +static const uint32_t k230_ddrc_reset_values[K230_DDRC_REG_COUNT] = { + [R_K230_DDRC_MSTR] = 0x01040000, + [R_K230_DDRC_RFSHCTL0] = 0x00210000, + [R_K230_DDRC_RFSHTMG] = 0x0062008c, + [R_K230_DDRC_RFSHTMG1] = 0x0000008c, + [R_K230_DDRC_INIT0] = 0x0002004e, + [R_K230_DDRC_INIT3] = 0x00000510, + [R_K230_DDRC_INIT5] = 0x00100000, + [R_K230_DDRC_DRAMTMG(0)] = 0x0f101b0f, + [R_K230_DDRC_DRAMTMG(1)] = 0x00080414, + [R_K230_DDRC_DRAMTMG(2)] = 0x0305060d, + [R_K230_DDRC_DRAMTMG(3)] = 0x00004000, + [R_K230_DDRC_DRAMTMG(4)] = 0x05040405, + [R_K230_DDRC_DRAMTMG(5)] = 0x05050403, + [R_K230_DDRC_DRAMTMG(6)] = 0x02020005, + [R_K230_DDRC_DRAMTMG(7)] = 0x00000202, + [R_K230_DDRC_DRAMTMG(8)] = 0x03034405, + [R_K230_DDRC_DRAMTMG(9)] = 0x0004040d, + [R_K230_DDRC_DRAMTMG(10)] = 0x001c180a, + [R_K230_DDRC_DRAMTMG(11)] = 0x440c021c, + [R_K230_DDRC_DRAMTMG(12)] = 0x00020610, + [R_K230_DDRC_DRAMTMG(13)] = 0x1c200004, + [R_K230_DDRC_DRAMTMG(14)] = 0x000000a0, + [R_K230_DDRC_DRAMTMG(16)] = 0x05100404, + [R_K230_DDRC_ZQCTL0] = 0x02000040, + [R_K230_DDRC_ZQCTL1] = 0x02000100, + [R_K230_DDRC_DFITMG0] = 0x07020002, + [R_K230_DDRC_DFITMG1] = 0x00000404, + [R_K230_DDRC_DFIUPD0] = 0x00400003, + [R_K230_DDRC_DFIUPD1] = 0x00010001, + [R_K230_DDRC_DFIUPD2] = 0x80000000, + [R_K230_DDRC_DFIMISC] = 0x00000001, + [R_K230_DDRC_DFITMG2] = 0x00000202, + [R_K230_DDRC_ODTCFG] = 0x04000400, + [R_K230_DDRC_SWCTL] = 0x00000001, + [R_K230_DDRC_SWSTAT] = 0x00000001, +}; + +/* K230 DDR PHY CSRs use byte offset = CSR index * 4. */ +#define K230_DDR_PHY_CSR_OFFSET(index) ((index) * 4) +#define K230_DDR_PHY_MASTER_CSR(reg) \ + K230_DDR_PHY_CSR_OFFSET(0x20000 + (reg)) +#define K230_DDR_PHY_APBONLY_CSR(reg) \ + K230_DDR_PHY_CSR_OFFSET(0xd0000 + (reg)) + +#define K230_DDR_PHY_ATX_IMPEDANCE_RESET UINT32_C(0x03ff) + +REG32(K230_DDR_PHY_MICRO_CONT_MUX_SEL, + K230_DDR_PHY_APBONLY_CSR(0x000)) + FIELD(K230_DDR_PHY_MICRO_CONT_MUX_SEL, MICRO_CONT_MUX_SEL, 0, 1) + +REG32(K230_DDR_PHY_TRAINING_STATUS, + K230_DDR_PHY_APBONLY_CSR(0x004)) + FIELD(K230_DDR_PHY_TRAINING_STATUS, MAILBOX_EMPTY, 0, 1) + +REG32(K230_DDR_PHY_TRAINING_ACK, + K230_DDR_PHY_APBONLY_CSR(0x031)) + +REG32(K230_DDR_PHY_TRAINING_MESSAGE, + K230_DDR_PHY_APBONLY_CSR(0x032)) + +REG32(K230_DDR_PHY_TRAINING_TRIGGER, + K230_DDR_PHY_APBONLY_CSR(0x099)) + +#define K230_DDR_PHY_TX_IMPEDANCE_CTRL1_RESET UINT32_C(0x0fff) + +REG32(K230_DDR_PHY_DFI_INIT_COMPLETE, + K230_DDR_PHY_MASTER_CSR(0x0f9)) + FIELD(K230_DDR_PHY_DFI_INIT_COMPLETE, DFI_INIT_COMPLETE, 0, 1) + +REG32(K230_DDR_PHY_VREF_IN_GLOBAL, + K230_DDR_PHY_MASTER_CSR(0x0b2)) +#define K230_DDR_PHY_VREF_IN_GLOBAL_RESET UINT32_C(0x0200) + +static void k230_ddr_cfg_update_state(K230DDRCfgState *s) +{ + bool dfi_complete = false; + unsigned int operating_mode = K230_DDRC_MODE_INIT; + + if (s->phy) { + dfi_complete = FIELD_EX32(s->phy->dfi_init_complete, + K230_DDR_PHY_DFI_INIT_COMPLETE, + DFI_INIT_COMPLETE); + } + + ARRAY_FIELD_DP32(s->regs, K230_DDRC_DFISTAT, + DFI_INIT_COMPLETE, dfi_complete); + ARRAY_FIELD_DP32(s->regs, K230_DDRC_SWSTAT, SW_DONE_ACK, + ARRAY_FIELD_EX32(s->regs, K230_DDRC_SWCTL, SW_DONE)); + + if (dfi_complete && + ARRAY_FIELD_EX32(s->regs, K230_DDRC_DFIMISC, + DFI_INIT_COMPLETE_EN)) { + s->initialized = true; + } + + if (s->initialized) { + operating_mode = K230_DDRC_MODE_NORMAL; + } + + ARRAY_FIELD_DP32(s->regs, K230_DDRC_STAT, + OPERATING_MODE, operating_mode); +} + +static uint64_t k230_ddr_cfg_read(void *opaque, hwaddr addr, unsigned int size) +{ + K230DDRCfgState *s = opaque; + uint64_t value = 0; + + if (addr < K230_DDRC_REG_SIZE) { + k230_ddr_cfg_update_state(s); + value = s->regs[addr / sizeof(uint32_t)]; + } + + return value; +} + +static void k230_ddr_cfg_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + K230DDRCfgState *s = opaque; + uint32_t val = value; + + if (addr >= K230_DDRC_REG_SIZE) { + return; + } + + switch (addr) { + case A_K230_DDRC_STAT: + case A_K230_DDRC_DFISTAT: + case A_K230_DDRC_ZQSTAT: + case A_K230_DDRC_SWSTAT: + return; + case A_K230_DDRC_PWRCTL: + s->regs[R_K230_DDRC_PWRCTL] = val & MAKE_64BIT_MASK(0, 9); + break; + case A_K230_DDRC_ZQCTL2: + /* ZQ reset completes immediately and the W1S bit self-clears. */ + s->regs[R_K230_DDRC_ZQCTL2] = 0; + s->regs[R_K230_DDRC_ZQSTAT] = 0; + break; + case A_K230_DDRC_DFIMISC: + s->regs[R_K230_DDRC_DFIMISC] = + val & (MAKE_64BIT_MASK(0, 6) | MAKE_64BIT_MASK(8, 5)); + if (s->phy && s->phy->training_complete && + FIELD_EX32(val, K230_DDRC_DFIMISC, DFI_INIT_START)) { + s->phy->dfi_init_complete = FIELD_DP32( + s->phy->dfi_init_complete, + K230_DDR_PHY_DFI_INIT_COMPLETE, DFI_INIT_COMPLETE, 1); + } + break; + case A_K230_DDRC_SWCTL: + s->regs[R_K230_DDRC_SWCTL] = + val & R_K230_DDRC_SWCTL_SW_DONE_MASK; + break; + default: + s->regs[addr / sizeof(uint32_t)] = val; + break; + } + + k230_ddr_cfg_update_state(s); +} + +static bool k230_ddr_phy_decode_anib(hwaddr addr, unsigned int *anib) +{ + uint32_t csr = addr / sizeof(uint32_t); + + if ((csr & 0xfff) != 0x043) { + return false; + } + + *anib = csr >> 12; + return *anib < K230_DDR_PHY_ANIB_COUNT; +} + +static bool k230_ddr_phy_decode_dbyte(hwaddr addr, uint32_t reg, + unsigned int *dbyte, + unsigned int *nibble) +{ + uint32_t csr = addr / sizeof(uint32_t); + uint32_t block_offset; + + if (csr < 0x10000) { + return false; + } + + csr -= 0x10000; + *dbyte = csr >> 12; + if (*dbyte >= K230_DDR_PHY_DBYTE_COUNT) { + return false; + } + + block_offset = csr & 0xfff; + *nibble = block_offset >> 8; + return *nibble < K230_DDR_PHY_NIBBLES_PER_DBYTE && + (block_offset & 0xff) == reg; +} + +static uint64_t k230_ddr_phy_read(void *opaque, hwaddr addr, + unsigned int size) +{ + K230DDRPhyState *s = opaque; + unsigned int dbyte; + unsigned int nibble; + unsigned int anib; + uint64_t value = 0; + + switch (addr) { + case A_K230_DDR_PHY_MICRO_CONT_MUX_SEL: + value = s->micro_cont_mux_sel; + break; + case A_K230_DDR_PHY_TRAINING_STATUS: + value = s->mailbox_message_pending ? 0 : + R_K230_DDR_PHY_TRAINING_STATUS_MAILBOX_EMPTY_MASK; + break; + case A_K230_DDR_PHY_TRAINING_MESSAGE: + value = s->training_complete ? 0x07 : 0; + break; + case A_K230_DDR_PHY_TRAINING_ACK: + case A_K230_DDR_PHY_TRAINING_TRIGGER: + break; + case A_K230_DDR_PHY_DFI_INIT_COMPLETE: + value = s->dfi_init_complete; + break; + case A_K230_DDR_PHY_VREF_IN_GLOBAL: + value = s->vref_in_global; + break; + default: + if (k230_ddr_phy_decode_anib(addr, &anib)) { + value = s->atx_impedance[anib]; + } else if (k230_ddr_phy_decode_dbyte(addr, 0x049, + &dbyte, &nibble)) { + value = s->tx_impedance_ctrl1[dbyte][nibble]; + } else if (k230_ddr_phy_decode_dbyte(addr, 0x04d, + &dbyte, &nibble)) { + value = s->tx_odt_drv_stren[dbyte][nibble]; + } else { + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented DDR PHY read at offset 0x%" + HWADDR_PRIx ", returning 0\n", + __func__, addr); + } + break; + } + + return value; +} + +static void k230_ddr_phy_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + K230DDRPhyState *s = opaque; + uint16_t val = value; + unsigned int dbyte; + unsigned int nibble; + unsigned int anib; + + switch (addr) { + case A_K230_DDR_PHY_MICRO_CONT_MUX_SEL: + s->micro_cont_mux_sel = + val & R_K230_DDR_PHY_MICRO_CONT_MUX_SEL_MICRO_CONT_MUX_SEL_MASK; + return; + case A_K230_DDR_PHY_TRAINING_STATUS: + case A_K230_DDR_PHY_TRAINING_MESSAGE: + return; + case A_K230_DDR_PHY_TRAINING_ACK: + if (val == 0) { + s->mailbox_message_pending = false; + } + return; + case A_K230_DDR_PHY_TRAINING_TRIGGER: + if (val != 0) { + s->training_trigger_seen = true; + } else if (s->training_trigger_seen) { + /* Abstract the loaded firmware run to its final mailbox message. */ + s->training_trigger_seen = false; + s->training_complete = true; + s->mailbox_message_pending = true; + } + return; + default: + break; + } + + if (FIELD_EX32(s->micro_cont_mux_sel, + K230_DDR_PHY_MICRO_CONT_MUX_SEL, + MICRO_CONT_MUX_SEL)) { + return; + } + + switch (addr) { + case A_K230_DDR_PHY_DFI_INIT_COMPLETE: + s->dfi_init_complete = + val & R_K230_DDR_PHY_DFI_INIT_COMPLETE_DFI_INIT_COMPLETE_MASK; + return; + case A_K230_DDR_PHY_VREF_IN_GLOBAL: + s->vref_in_global = val & UINT16_C(0x7fff); + return; + default: + break; + } + + if (k230_ddr_phy_decode_anib(addr, &anib)) { + s->atx_impedance[anib] = val & UINT16_C(0x03ff); + return; + } + + if (k230_ddr_phy_decode_dbyte(addr, 0x049, &dbyte, &nibble)) { + s->tx_impedance_ctrl1[dbyte][nibble] = val & UINT16_C(0x0fff); + return; + } + + if (k230_ddr_phy_decode_dbyte(addr, 0x04d, &dbyte, &nibble)) { + s->tx_odt_drv_stren[dbyte][nibble] = val & UINT16_C(0x0fff); + return; + } + + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented DDR PHY write at offset 0x%" + HWADDR_PRIx ", value 0x%" PRIx64 "\n", + __func__, addr, value); +} + +static const MemoryRegionOps k230_ddr_cfg_ops = { + .read = k230_ddr_cfg_read, + .write = k230_ddr_cfg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static const MemoryRegionOps k230_ddr_phy_ops = { + .read = k230_ddr_phy_read, + .write = k230_ddr_phy_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void k230_ddr_cfg_init(Object *obj) +{ + K230DDRCfgState *s = K230_DDR_CFG(obj); + + memory_region_init_io(&s->mmio, obj, &k230_ddr_cfg_ops, s, + "k230-ddr-cfg", K230_DDRC_MMIO_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void k230_ddr_phy_init(Object *obj) +{ + K230DDRPhyState *s = K230_DDR_PHY(obj); + + memory_region_init_io(&s->mmio, obj, &k230_ddr_phy_ops, s, + "k230-ddr-phy", K230_DDR_PHY_MMIO_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static void k230_ddr_cfg_reset_enter(Object *obj, ResetType type) +{ + K230DDRCfgState *s = K230_DDR_CFG(obj); + + s->initialized = false; + memcpy(s->regs, k230_ddrc_reset_values, sizeof(s->regs)); +} + +static void k230_ddr_phy_reset_enter(Object *obj, ResetType type) +{ + K230DDRPhyState *s = K230_DDR_PHY(obj); + unsigned int dbyte; + unsigned int nibble; + unsigned int anib; + + memset(s->tx_odt_drv_stren, 0, sizeof(s->tx_odt_drv_stren)); + + for (anib = 0; anib < ARRAY_SIZE(s->atx_impedance); anib++) { + s->atx_impedance[anib] = K230_DDR_PHY_ATX_IMPEDANCE_RESET; + } + + for (dbyte = 0; dbyte < ARRAY_SIZE(s->tx_impedance_ctrl1); dbyte++) { + for (nibble = 0; + nibble < ARRAY_SIZE(s->tx_impedance_ctrl1[dbyte]); nibble++) { + s->tx_impedance_ctrl1[dbyte][nibble] = + K230_DDR_PHY_TX_IMPEDANCE_CTRL1_RESET; + } + } + + s->dfi_init_complete = 0; + s->vref_in_global = K230_DDR_PHY_VREF_IN_GLOBAL_RESET; + s->micro_cont_mux_sel = 0; + s->training_trigger_seen = false; + s->training_complete = false; + s->mailbox_message_pending = false; +} + +static const VMStateDescription vmstate_k230_ddr_cfg = { + .name = "k230-ddr-cfg", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, K230DDRCfgState, K230_DDRC_REG_COUNT), + VMSTATE_BOOL(initialized, K230DDRCfgState), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_k230_ddr_phy = { + .name = "k230-ddr-phy", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT16_ARRAY(atx_impedance, K230DDRPhyState, + K230_DDR_PHY_ANIB_COUNT), + VMSTATE_UINT16_2DARRAY(tx_impedance_ctrl1, K230DDRPhyState, + K230_DDR_PHY_DBYTE_COUNT, + K230_DDR_PHY_NIBBLES_PER_DBYTE), + VMSTATE_UINT16_2DARRAY(tx_odt_drv_stren, K230DDRPhyState, + K230_DDR_PHY_DBYTE_COUNT, + K230_DDR_PHY_NIBBLES_PER_DBYTE), + VMSTATE_UINT16(dfi_init_complete, K230DDRPhyState), + VMSTATE_UINT16(vref_in_global, K230DDRPhyState), + VMSTATE_UINT16(micro_cont_mux_sel, K230DDRPhyState), + VMSTATE_BOOL(training_trigger_seen, K230DDRPhyState), + VMSTATE_BOOL(training_complete, K230DDRPhyState), + VMSTATE_BOOL(mailbox_message_pending, K230DDRPhyState), + VMSTATE_END_OF_LIST() + }, +}; + +static void k230_ddr_cfg_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = k230_ddr_cfg_reset_enter; + dc->vmsd = &vmstate_k230_ddr_cfg; +} + +static void k230_ddr_phy_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.enter = k230_ddr_phy_reset_enter; + dc->vmsd = &vmstate_k230_ddr_phy; +} + +static const TypeInfo k230_ddr_types[] = { + { + .name = TYPE_K230_DDR_CFG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(K230DDRCfgState), + .instance_init = k230_ddr_cfg_init, + .class_init = k230_ddr_cfg_class_init, + }, + { + .name = TYPE_K230_DDR_PHY, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(K230DDRPhyState), + .instance_init = k230_ddr_phy_init, + .class_init = k230_ddr_phy_class_init, + }, +}; + +DEFINE_TYPES(k230_ddr_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 858ca845a2..cbeecbf1e0 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -29,6 +29,7 @@ system_ss.add(when: 'CONFIG_IOSB', if_true: files('iosb.c')) system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c')) # RISC-V devices +system_ss.add(when: 'CONFIG_K230', if_true: files('k230_ddr.c')) system_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c')) system_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c')) system_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c')) diff --git a/include/hw/misc/k230_ddr.h b/include/hw/misc/k230_ddr.h new file mode 100644 index 0000000000..d912e8e1b0 --- /dev/null +++ b/include/hw/misc/k230_ddr.h @@ -0,0 +1,59 @@ +/* + * Kendryte K230 DDR controller and PHY models + * + * Device state and type declarations for the K230 DDRC CFG and K230 DDR PHY + * registers. + * + * Copyright (c) 2026 Junze Cao + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_K230_DDR_H +#define HW_MISC_K230_DDR_H + +#include "hw/core/sysbus.h" + +#define K230_DDRC_MMIO_SIZE 0x02000000 +#define K230_DDR_PHY_MMIO_SIZE 0x00400000 + +#define K230_DDRC_REG_SIZE 0x328 +#define K230_DDRC_REG_COUNT (K230_DDRC_REG_SIZE / sizeof(uint32_t)) + +#define K230_DDR_PHY_ANIB_COUNT 10 +#define K230_DDR_PHY_DBYTE_COUNT 4 +#define K230_DDR_PHY_NIBBLES_PER_DBYTE 2 + +#define TYPE_K230_DDR_CFG "riscv.k230.ddr-cfg" +OBJECT_DECLARE_SIMPLE_TYPE(K230DDRCfgState, K230_DDR_CFG) + +#define TYPE_K230_DDR_PHY "riscv.k230.ddr-phy" +OBJECT_DECLARE_SIMPLE_TYPE(K230DDRPhyState, K230_DDR_PHY) + +struct K230DDRCfgState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + K230DDRPhyState *phy; + uint32_t regs[K230_DDRC_REG_COUNT]; + bool initialized; +}; + +struct K230DDRPhyState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + uint16_t atx_impedance[K230_DDR_PHY_ANIB_COUNT]; + uint16_t tx_impedance_ctrl1[K230_DDR_PHY_DBYTE_COUNT] + [K230_DDR_PHY_NIBBLES_PER_DBYTE]; + uint16_t tx_odt_drv_stren[K230_DDR_PHY_DBYTE_COUNT] + [K230_DDR_PHY_NIBBLES_PER_DBYTE]; + uint16_t dfi_init_complete; + uint16_t vref_in_global; + uint16_t micro_cont_mux_sel; + bool training_trigger_seen; + bool training_complete; + bool mailbox_message_pending; +}; + +#endif From 4309ee8e915d37763813ad4406d7f67a0fd08324 Mon Sep 17 00:00:00 2001 From: Junze Cao Date: Fri, 7 Aug 2026 18:21:17 +0800 Subject: [PATCH 484/627] hw/riscv: Connect K230 DDR controller and PHY models Replace the unimplemented K230 DDR configuration region with the DDRC model and map the PHY model at 0x9a000000. Connect the controller to the PHY so DFI status reflects PHY training and initialization state. Suggested-by: Chao Liu Reviewed-by: Daniel Henrique Barboza Signed-off-by: Junze Cao Message-ID: <20260807-k230-ddr-v2-v2-2-c531308ae819@gmail.com> Signed-off-by: Alistair Francis --- docs/system/riscv/k230.rst | 4 ++++ hw/riscv/k230.c | 19 ++++++++++++++++--- include/hw/riscv/k230.h | 4 ++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst index cea8202e55..06a819fbdb 100644 --- a/docs/system/riscv/k230.rst +++ b/docs/system/riscv/k230.rst @@ -20,12 +20,16 @@ The ``k230`` machine supports the following devices: * Platform-Level Interrupt Controller (PLIC) * 2 K230 Watchdog Timer * 5 UART +* K230 DDRC CFG and DDR PHY Boot options ------------ The ``k230`` machine supports K230 SDK boot through M-mode U-Boot, which then starts OpenSBI/Linux with ``bootm``. It also supports direct Linux boot. +The DDRC CFG and DDR PHY models allow the K230 SDK U-Boot SPL to complete DDR +initialization before loading the next boot stage. + K230 SDK Linux kernels use T-HEAD C9xx private MAEE page table attributes. QEMU does not implement MAEE in the generic RISC-V MMU, so such kernels need to be built with standard RISC-V PTE bits before they can boot under QEMU. diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 656f28190c..627150b463 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -97,6 +97,7 @@ static const MemMapEntry memmap[] = { [K230_DEV_SPI] = { 0x91584000, 0x00001000 }, [K230_DEV_HI_SYS_CFG] = { 0x91585000, 0x00000400 }, [K230_DEV_DDRC_CFG] = { 0x98000000, 0x02000000 }, + [K230_DEV_DDR_PHY] = { 0x9A000000, 0x00400000 }, [K230_DEV_FLASH] = { 0xC0000000, 0x08000000 }, [K230_DEV_PLIC] = { 0xF00000000, 0x00400000 }, [K230_DEV_CLINT] = { 0xF04000000, 0x00400000 }, @@ -108,6 +109,11 @@ static void k230_soc_init(Object *obj) RISCVHartArrayState *cpu0 = &s->c908_cpu; object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "ddr-cfg", &s->ddr_cfg, + TYPE_K230_DDR_CFG); + object_initialize_child(obj, "ddr-phy", &s->ddr_phy, + TYPE_K230_DDR_PHY); + s->ddr_cfg.phy = &s->ddr_phy; object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT); object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT); @@ -158,6 +164,16 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) int c908_cpus; sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ddr_cfg), errp)) { + return; + } + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ddr_phy), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_cfg), 0, + memmap[K230_DEV_DDRC_CFG].base); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->ddr_phy), 0, + memmap[K230_DEV_DDR_PHY].base); c908_cpus = s->c908_cpu.num_harts; @@ -361,9 +377,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base, memmap[K230_DEV_HI_SYS_CFG].size); - create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base, - memmap[K230_DEV_DDRC_CFG].size); - create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base, memmap[K230_DEV_FLASH].size); } diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index 592e1c26bf..80ca16338c 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -16,6 +16,7 @@ #define HW_K230_H #include "hw/core/boards.h" +#include "hw/misc/k230_ddr.h" #include "hw/riscv/riscv_hart.h" #include "hw/watchdog/k230_wdt.h" @@ -32,6 +33,8 @@ typedef struct K230SoCState { /*< public >*/ RISCVHartArrayState c908_cpu; /* Small core */ + K230DDRCfgState ddr_cfg; + K230DDRPhyState ddr_phy; K230WdtState wdt[2]; MemoryRegion sram; MemoryRegion bootrom; @@ -112,6 +115,7 @@ enum { K230_DEV_SPI, K230_DEV_HI_SYS_CFG, K230_DEV_DDRC_CFG, + K230_DEV_DDR_PHY, K230_DEV_FLASH, K230_DEV_PLIC, K230_DEV_CLINT, From 98911b604bcd881276202c4e2dd51c68b69ed4dd Mon Sep 17 00:00:00 2001 From: Junze Cao Date: Fri, 7 Aug 2026 18:21:18 +0800 Subject: [PATCH 485/627] tests/qtest: Add K230 DDR controller tests Add qtests for DDRC and PHY reset values, register access policy, the software-update handshake, and PHY register ownership. Exercise PHY training and mailbox acknowledgement through the DFI initialization sequence. Include negative coverage to ensure DFI cannot complete before PHY training or enter Normal mode before completion is enabled. Reviewed-by: Daniel Henrique Barboza Suggested-by: Chao Liu Signed-off-by: Junze Cao Message-ID: <20260807-k230-ddr-v2-v2-3-c531308ae819@gmail.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 1 + tests/qtest/k230-ddr-test.c | 226 ++++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 3 +- 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/k230-ddr-test.c diff --git a/MAINTAINERS b/MAINTAINERS index cc0879c868..2190bc706b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1851,6 +1851,7 @@ F: include/hw/misc/k230_ddr.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: tests/functional/riscv64/test_k230.py +F: tests/qtest/k230-ddr-test.c F: tests/qtest/k230-wdt-test.c RX Machines diff --git a/tests/qtest/k230-ddr-test.c b/tests/qtest/k230-ddr-test.c new file mode 100644 index 0000000000..72362929bc --- /dev/null +++ b/tests/qtest/k230-ddr-test.c @@ -0,0 +1,226 @@ +/* + * QTest testcase for the K230 DDR controller and PHY + * + * Exercises register access, reset, PHY ownership, training mailbox, and DFI + * initialization. + * + * Copyright (c) 2026 Junze Cao + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" + +#define K230_DDRC_BASE UINT64_C(0x98000000) +#define K230_DDR_PHY_BASE UINT64_C(0x9a000000) + +#define K230_DDRC_MSTR 0x000 +#define K230_DDRC_STAT 0x004 +#define K230_DDRC_DRAMTMG4 0x110 +#define K230_DDRC_DFIMISC 0x1b0 +#define K230_DDRC_DFISTAT 0x1bc +#define K230_DDRC_SWCTL 0x320 +#define K230_DDRC_SWSTAT 0x324 + +#define K230_DDRC_STAT_OPERATING_MODE_MASK 0x7 +#define K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK 0x1 + +#define K230_DDR_PHY_CSR(index) \ + (K230_DDR_PHY_BASE + (uint64_t)(index) * sizeof(uint32_t)) + +#define K230_DDR_PHY_ATX_IMPEDANCE 0x00043 +#define K230_DDR_PHY_TX_IMPEDANCE_CTRL1 0x10049 +#define K230_DDR_PHY_VREF_IN_GLOBAL 0x200b2 +#define K230_DDR_PHY_MICRO_CONT_MUX_SEL 0xd0000 +#define K230_DDR_PHY_TRAINING_STATUS 0xd0004 +#define K230_DDR_PHY_TRAINING_ACK 0xd0031 +#define K230_DDR_PHY_TRAINING_MESSAGE 0xd0032 +#define K230_DDR_PHY_TRAINING_TRIGGER 0xd0099 + +static void complete_phy_training(QTestState *qts) +{ + qtest_writel(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL), 1); + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 9); + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 1); + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_TRIGGER), 0); +} + +static void test_reset_and_register_access(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR), + ==, 0x01040000); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT), + ==, 0x00000000); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4), + ==, 0x05040405); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC), + ==, 0x00000001); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWCTL), + ==, 0x00000001); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT), + ==, 0x00000001); + + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE)), + ==, 0x03ff); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_TX_IMPEDANCE_CTRL1)), + ==, 0x0fff); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)), + ==, 0x0200); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_MSTR, 0x01040008); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR), + ==, 0x01040008); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_STAT, 0xffffffff); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT), + ==, 0x00000000); + + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL), + 0xffffffff); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)), + ==, 0x7fff); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4, 0); + + qtest_system_reset(qts); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_MSTR), + ==, 0x01040000); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DRAMTMG4), + ==, 0x05040405); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_VREF_IN_GLOBAL)), + ==, 0x0200); + + qtest_quit(qts); +} + +static void test_software_update_handshake(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 0); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT), + ==, 0); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWCTL, 1); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT), + ==, 1); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT, 0); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_SWSTAT), + ==, 1); + + qtest_quit(qts); +} + +static void test_phy_ownership(void) +{ + QTestState *qts = qtest_init("-machine k230"); + uint64_t atx = K230_DDR_PHY_CSR(K230_DDR_PHY_ATX_IMPEDANCE); + uint64_t mux = K230_DDR_PHY_CSR(K230_DDR_PHY_MICRO_CONT_MUX_SEL); + + qtest_writel(qts, atx, 0x155); + g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155); + + qtest_writel(qts, mux, 1); + qtest_writel(qts, atx, 0x2aa); + g_assert_cmphex(qtest_readl(qts, atx), ==, 0x155); + + qtest_writel(qts, mux, 0); + qtest_writel(qts, atx, 0x2aa); + g_assert_cmphex(qtest_readl(qts, atx), ==, 0x2aa); + + qtest_quit(qts); +} + +static void test_dfi_prerequisites(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20); + + g_assert_cmphex(qtest_readl(qts, + K230_DDRC_BASE + K230_DDRC_DFISTAT) & + K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK, + ==, 0); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) & + K230_DDRC_STAT_OPERATING_MODE_MASK, + ==, 0); + + qtest_quit(qts); +} + +static void test_dfi_complete_enable(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + complete_phy_training(qts); + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20); + + g_assert_cmphex(qtest_readl(qts, + K230_DDRC_BASE + K230_DDRC_DFISTAT) & + K230_DDRC_DFISTAT_DFI_INIT_COMPLETE_MASK, + ==, 1); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) & + K230_DDRC_STAT_OPERATING_MODE_MASK, + ==, 0); + + qtest_quit(qts); +} + +static void test_training_and_dfi_handshake(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + complete_phy_training(qts); + + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)), + ==, 0); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_MESSAGE)), + ==, 0x07); + + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 0); + g_assert_cmphex(qtest_readl(qts, + K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_STATUS)), + ==, 1); + qtest_writel(qts, K230_DDR_PHY_CSR(K230_DDR_PHY_TRAINING_ACK), 1); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0x20); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_DFISTAT), + ==, 1); + + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 0); + qtest_writel(qts, K230_DDRC_BASE + K230_DDRC_DFIMISC, 1); + g_assert_cmphex(qtest_readl(qts, K230_DDRC_BASE + K230_DDRC_STAT) & 0x7, + ==, 1); + + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/k230-ddr/reset-and-register-access", + test_reset_and_register_access); + qtest_add_func("/k230-ddr/software-update-handshake", + test_software_update_handshake); + qtest_add_func("/k230-ddr/phy-ownership", test_phy_ownership); + qtest_add_func("/k230-ddr/dfi-prerequisites", test_dfi_prerequisites); + qtest_add_func("/k230-ddr/dfi-complete-enable", + test_dfi_complete_enable); + qtest_add_func("/k230-ddr/training-and-dfi-handshake", + test_training_and_dfi_handshake); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 12ed368997..663a66bded 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -299,7 +299,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \ (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \ - (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) + (config_all_devices.has_key('CONFIG_K230') ? + ['k230-ddr-test', 'k230-wdt-test'] : []) qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test'] From 2a99140258feaf8bd05df5b16698dde6aec1148c Mon Sep 17 00:00:00 2001 From: Yanfeng Liu Date: Sat, 18 Jul 2026 10:16:32 +0800 Subject: [PATCH 486/627] riscv/virt: Add optional UART1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds optional UART1 to RiscV virt board if required at runtime to simplify multicore development. Note that UART0 remains default serial_hd(0) and it is: - the lowest address UART - first serial in DTB - behind /aliases/serial0 in DTB - the /chosen/stdout-path in DTB Note that UART1 is placed at different page from UART0 to support page level isolation. Signed-off-by: Yanfeng Liu Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: Signed-off-by: Alistair Francis --- docs/system/riscv/virt.rst | 5 ++++- hw/riscv/virt-acpi-build.c | 12 ++++++++---- hw/riscv/virt.c | 40 ++++++++++++++++++++++++++++---------- include/hw/riscv/virt.h | 3 +++ 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index 60850970ce..3c87246891 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -16,7 +16,7 @@ The ``virt`` machine supports the following devices: * Core Local Interruptor (CLINT) * Platform-Level Interrupt Controller (PLIC) * CFI parallel NOR flash memory -* 1 NS16550 compatible UART +* Either 1 or 2 NS16550 compatible UARTs * 1 Google Goldfish RTC * 1 SiFive Test device * 8 virtio-mmio transport devices @@ -27,6 +27,9 @@ The hypervisor extension has been enabled for the default CPU, so virtual machines with hypervisor extension can simply be used without explicitly declaring. +The second UART only exists if a backend is configured explicitly (e.g. +with a second ``-serial`` command line option). + Hardware configuration information ---------------------------------- diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 59c454f4f9..8e516ec114 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -177,11 +177,11 @@ static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count, static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, - uint32_t uart_irq) + uint32_t uart_irq, int uartidx) { - Aml *dev = aml_device("COM0"); + Aml *dev = aml_device("COM%d", uartidx); aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003"))); - aml_append(dev, aml_name_decl("_UID", aml_int(0))); + aml_append(dev, aml_name_decl("_UID", aml_int(uartidx))); Aml *crs = aml_resource_template(); aml_append(crs, aml_memory32_fixed(uart_memmap->base, @@ -490,7 +490,11 @@ static void build_dsdt(GArray *table_data, memmap[VIRT_APLIC_S].size, "RSCV0002"); } - acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ, 0); + if (s->uart1_present) { + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART1], UART1_IRQ, 1); + } + if (virt_is_iommu_sys_enabled(s)) { acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ); } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 51bac47a91..d58656f70d 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -97,6 +97,8 @@ static const MemMapEntry virt_memmap[] = { [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, + /* UART1 supports page isolation from UART0 */ + [VIRT_UART1] = { 0x1000a000, 0x100 }, [VIRT_FW_CFG] = { 0x10100000, 0x18 }, [VIRT_FLASH] = { 0x20000000, 0x4000000 }, [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, @@ -187,7 +189,8 @@ static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, FDT_MAX_INT_MAP_WIDTH] = {}; uint32_t *irq_map = full_irq_map; - /* This code creates a standard swizzle of interrupts such that + /* + * This code creates a standard swizzle of interrupts such that * each device's first interrupt is based on it's PCI_SLOT number. * (See pci_swizzle_map_irq_fn()) * @@ -805,28 +808,38 @@ static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) } static void create_fdt_uart(RISCVVirtState *s, - uint32_t irq_mmio_phandle) + uint32_t irq_mmio_phandle, int memId, int irqNo) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx, - s->memmap[VIRT_UART0].base); + s->memmap[memId].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", - 2, s->memmap[VIRT_UART0].base, - 2, s->memmap[VIRT_UART0].size); + 2, s->memmap[memId].base, + 2, s->memmap[memId].size); qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", UART0_IRQ); + qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo); } else { - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", UART0_IRQ, 0x4); + qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo, 0x4); } - qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); - qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); + if (VIRT_UART0 == memId) { + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); + } +} + +static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle) +{ + if (s->uart1_present) { + create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ); + } + create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ); } static void create_fdt_rtc(RISCVVirtState *s, @@ -996,7 +1009,7 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_reset(s, &phandle); - create_fdt_uart(s, irq_mmio_phandle); + create_fdt_uarts(s, irq_mmio_phandle); create_fdt_rtc(s, irq_mmio_phandle); } @@ -1486,6 +1499,13 @@ static void virt_machine_init(MachineState *machine) 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); + if (serial_hd(1)) { + serial_mm_init(system_memory, s->memmap[VIRT_UART1].base, + 0, qdev_get_gpio_in(mmio_irqchip, UART1_IRQ), 399193, + serial_hd(1), DEVICE_LITTLE_ENDIAN); + s->uart1_present = true; + } + sysbus_create_simple("goldfish_rtc", s->memmap[VIRT_RTC].base, qdev_get_gpio_in(mmio_irqchip, RTC_IRQ)); diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 36a2def410..7c862b0da2 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -59,6 +59,7 @@ struct RISCVVirtState { int aia_guests; char *oem_id; char *oem_table_id; + bool uart1_present; OnOffAuto acpi; const MemMapEntry *memmap; struct GPEXHost *gpex_host; @@ -79,6 +80,7 @@ enum { VIRT_APLIC_S, VIRT_UART0, VIRT_VIRTIO, + VIRT_UART1, VIRT_FW_CFG, VIRT_IMSIC_M, VIRT_IMSIC_S, @@ -94,6 +96,7 @@ enum { enum { UART0_IRQ = 10, RTC_IRQ = 11, + UART1_IRQ = 12, VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, PCIE_IRQ = 0x20, /* 32 to 35 */ From 54bc6c4f15f91aee9acf43c36cd3d6c91d31320e Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:21 +0800 Subject: [PATCH 487/627] hw/dma: add K230 gsdma K230 GSDMA includes SDMA (System Direct Memory Access) and GDMA (Graphic Direct Memory Access). In this patch, add SDMA for k230 board. The following features have not been implemented: 1. axi protocol related 2. channel arbitration 3. lower power mode SDMA supports transfer data between memory, in which case SDMA is the controller. It also supports transfer data to decomp_gzip and caching it through SRAM. In this case, decomp_gzip is the controller, which controls SDMA through handshake signals. According to "K230 Technical Reference Manual v0.3.1" section 2.5.2. https://download.kendryte.com/developer/k230/HDK/K230%E7%A1%AC%E4%BB%B6%E6%96%87%E6%A1%A3/K230_Technical_Reference_Manual_V0.3.1_20241118.pdf This commit includes: - K230 SDMA (System Direct Memory Access) model (k230_gsdma.c, k230_gsdma.h) - GSDMA trace log (trace-events) - Kconfig and meson.build - update MAINTAINERS Signed-off-by: Tao Ding Reviewed-by: Chao Liu Reviewed-by: Daniel Henrique Barboza Reviewed-by: Junze Cao Message-ID: <20260808062227.66961-2-dingtao0430@163.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 2 + hw/dma/Kconfig | 3 + hw/dma/k230_gsdma.c | 551 ++++++++++++++++++++++++++++++++++++ hw/dma/meson.build | 1 + hw/dma/trace-events | 6 + include/hw/dma/k230_gsdma.h | 130 +++++++++ 6 files changed, 693 insertions(+) create mode 100644 hw/dma/k230_gsdma.c create mode 100644 include/hw/dma/k230_gsdma.h diff --git a/MAINTAINERS b/MAINTAINERS index 2190bc706b..027db78b39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1847,9 +1847,11 @@ F: docs/system/riscv/k230.rst F: hw/misc/k230_ddr.c F: hw/riscv/k230.c F: hw/watchdog/k230_wdt.c +F: hw/dma/k230_gsdma.c F: include/hw/misc/k230_ddr.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h +F: include/hw/dma/k230_gsdma.h F: tests/functional/riscv64/test_k230.py F: tests/qtest/k230-ddr-test.c F: tests/qtest/k230-wdt-test.c diff --git a/hw/dma/Kconfig b/hw/dma/Kconfig index 98fbb1bb04..0a23e7d7b8 100644 --- a/hw/dma/Kconfig +++ b/hw/dma/Kconfig @@ -30,3 +30,6 @@ config SIFIVE_PDMA config XLNX_CSU_DMA bool select REGISTER + +config K230_GSDMA + bool \ No newline at end of file diff --git a/hw/dma/k230_gsdma.c b/hw/dma/k230_gsdma.c new file mode 100644 index 0000000000..7635cd19e8 --- /dev/null +++ b/hw/dma/k230_gsdma.c @@ -0,0 +1,551 @@ +/* + * Kendryte K230 GSDMA + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * GSDMA includes SDMA (System Direct Memory Access, K230 TRM section 10.2) and + * GDMA (Graphic Direct Memory Access, K230 TRM section 2.5.2). + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "migration/vmstate.h" +#include "system/address-spaces.h" +#include "hw/dma/k230_gsdma.h" +#include "hw/core/irq.h" +#include "trace.h" + +static void k230_gsdma_update_irq(K230GSDMAState *s) +{ + qemu_set_irq(s->irq, !!(s->dma_int_stat & ~s->dma_int_mask)); +} + +static bool k230_gsdma_decomp_enabled(K230GSDMAState *s) +{ + /* Only sdma channel 0 has decomp enable flag */ + return !!(s->channels[0].cfg & K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN); +} + +static bool k230_gsdma_read_sdma_llt(hwaddr addr, K230GSDMALLT *llt) +{ + bool ok = address_space_read(&address_space_memory, addr, + MEMTXATTRS_UNSPECIFIED, llt, + sizeof(*llt)) == MEMTX_OK; + + if (ok) { + trace_k230_gsdma_read_sdma_llt(addr, le32_to_cpu(llt->cfg), + le32_to_cpu(llt->src_addr), + le32_to_cpu(llt->line_size), + le32_to_cpu(llt->line_cfg), + le32_to_cpu(llt->dst_addr), + le32_to_cpu(llt->next_llt_addr)); + } else { + trace_k230_gsdma_read_sdma_llt_failed(addr); + } + + return ok; +} + +static unsigned int k230_gsdma_usr_data_size(uint32_t cfg) +{ + /* decode usr_dat_size in CH_CFG register */ + switch (extract32(cfg, K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT, 2)) { + case 0: + return 1; + case 1: + return 2; + default: + return 4; + } +} + +static void k230_gsdma_convert_endian(uint8_t *buf, uint32_t len, uint32_t cfg) +{ + unsigned int mode = extract32(cfg, + K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT, 2); + unsigned int unit_size; + unsigned int offset; + + if (mode == 0) { + return; + } + + unit_size = 1U << mode; + for (offset = 0; offset + unit_size <= len; offset += unit_size) { + unsigned int i; + + for (i = 0; i < unit_size / 2; i++) { + uint8_t tmp = buf[offset + i]; + + buf[offset + i] = buf[offset + unit_size - i - 1]; + buf[offset + unit_size - i - 1] = tmp; + } + } +} + +static bool k230_gsdma_transfer_llt(K230GSDMAChannel *c, const K230GSDMALLT *llt) +{ + uint32_t llt_cfg = le32_to_cpu(llt->cfg); + hwaddr src = le32_to_cpu(llt->src_addr); + hwaddr dst = le32_to_cpu(llt->dst_addr); + uint32_t line_size = le32_to_cpu(llt->line_size); + uint32_t line_cfg = le32_to_cpu(llt->line_cfg); + /* Number of lines required for 2d mode */ + uint32_t line_num = + (llt_cfg & K230_GSDMA_LLT_2D_MODE) ? extract32(line_cfg, 0, 16) : 1; + /* Stride line size required for 2d mode */ + uint32_t line_space = extract32(line_cfg, 16, 16); + + bool dat_mode = c->cfg & K230_GSDMA_CH_CFG_DAT_MODE; + bool src_fixed = c->cfg & K230_GSDMA_CH_CFG_SRC_FIXED; + bool dst_fixed = c->cfg & K230_GSDMA_CH_CFG_DST_FIXED; + + uint8_t buf[8]; /* K230 sdma axi data width is 64-bit */ + uint8_t fill[4]; /* Usr data is 32-bit*/ + unsigned int fill_len = k230_gsdma_usr_data_size(c->cfg); + uint32_t i; + + memcpy(fill, &c->usr_data, sizeof(fill)); + + for (i = 0; i < line_num; i++) { + uint32_t remaining = line_size; + hwaddr line_src = src; + hwaddr line_dst = dst; + + while (remaining) { + uint32_t chunk = MIN(remaining, (uint32_t)sizeof(buf)); + + if (dat_mode) { + uint32_t j; + + for (j = 0; j < chunk; j++) { + buf[j] = fill[j % fill_len]; + } + } else if (address_space_read(&address_space_memory, line_src, + MEMTXATTRS_UNSPECIFIED, buf, + chunk) != MEMTX_OK) { + return false; + } + + k230_gsdma_convert_endian(buf, chunk, c->cfg); + + if (address_space_write(&address_space_memory, line_dst, + MEMTXATTRS_UNSPECIFIED, buf, + chunk) != MEMTX_OK) { + return false; + } + + if (!dat_mode && !src_fixed) { + line_src += chunk; + } + if (!dst_fixed) { + line_dst += chunk; + } + remaining -= chunk; + } + + if (!dat_mode && !src_fixed) { + if (llt_cfg & K230_GSDMA_LLT_2D_MODE) { /* 2d mode */ + src += line_size + line_space; + } else { + src += line_size; + } + } + + if (!dst_fixed) { + dst += line_size; + } + } + + return true; +} + +static void k230_gsdma_sdma_set_idle(K230GSDMAChannel *c) +{ + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY | K230_GSDMA_SDMA_STATUS_PAUSE); + c->next_llt = 0; +} + +static void k230_gsdma_sdma_set_paused(K230GSDMAChannel *c, hwaddr next_llt) +{ + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY; + c->status |= K230_GSDMA_SDMA_STATUS_PAUSE; + c->next_llt = next_llt; +} + +static void k230_gsdma_run_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr) +{ + K230GSDMAChannel *c = &s->channels[ch]; + + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE; + c->status |= K230_GSDMA_SDMA_STATUS_BUSY; + c->next_llt = 0; + c->current_llt = addr; + + while (addr) { + K230GSDMALLT llt; + uint32_t cfg; + hwaddr next; + + if (!k230_gsdma_read_sdma_llt(addr, &llt)) { + k230_gsdma_sdma_set_idle(c); + return; + } + + cfg = le32_to_cpu(llt.cfg); + next = le32_to_cpu(llt.next_llt_addr); + c->current_llt = addr; + + if (!k230_gsdma_transfer_llt(c, &llt)) { + k230_gsdma_sdma_set_idle(c); + return; + } + + if (cfg & K230_GSDMA_LLT_NODE_INTR) { + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch); + } + + if (cfg & K230_GSDMA_LLT_PAUSE) { + s->dma_int_stat |= K230_GSDMA_SDMA_PAUSE_INT(ch); + k230_gsdma_sdma_set_paused(c, next); + k230_gsdma_update_irq(s); + return; + } + + addr = next; + } + + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch); + s->dma_ch_en &= ~BIT(ch); + k230_gsdma_sdma_set_idle(c); + k230_gsdma_update_irq(s); +} + +/* Decomp gzip request step sdma */ +static void k230_gsdma_step_sdma(K230GSDMAState *s, unsigned int ch, hwaddr addr) +{ + K230GSDMAChannel *c = &s->channels[ch]; + K230GSDMALLT llt; + uint32_t cfg; + hwaddr next; + + if (!addr || !k230_gsdma_read_sdma_llt(addr, &llt)) { + k230_gsdma_sdma_set_idle(c); + return; + } + + cfg = le32_to_cpu(llt.cfg); + next = le32_to_cpu(llt.next_llt_addr); + + c->status |= K230_GSDMA_SDMA_STATUS_BUSY; + c->status &= ~K230_GSDMA_SDMA_STATUS_PAUSE; + c->current_llt = addr; + + if (!k230_gsdma_transfer_llt(c, &llt)) { + k230_gsdma_sdma_set_idle(c); + return; + } + + if (cfg & K230_GSDMA_LLT_NODE_INTR) { + s->dma_int_stat |= K230_GSDMA_SDMA_ITEM_INT(ch); + } + + c->status &= ~K230_GSDMA_SDMA_STATUS_BUSY; + c->next_llt = next; + if (next == 0) { + s->dma_int_stat |= K230_GSDMA_SDMA_DONE_INT(ch); + s->dma_ch_en &= ~BIT(ch); + } + + k230_gsdma_update_irq(s); +} + +static const VMStateDescription vmstate_k230_gsdma_channel = { + .name = "k230.gsdma.channel", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(ctl, K230GSDMAChannel), + VMSTATE_UINT32(status, K230GSDMAChannel), + VMSTATE_UINT32(cfg, K230GSDMAChannel), + VMSTATE_UINT32(usr_data, K230GSDMAChannel), + VMSTATE_UINT32(llt_saddr, K230GSDMAChannel), + VMSTATE_UINT32(current_llt, K230GSDMAChannel), + VMSTATE_UINT32(next_llt, K230GSDMAChannel), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_k230_gsdma = { + .name = "k230.gsdma", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(dma_ch_en, K230GSDMAState), + VMSTATE_UINT32(dma_int_mask, K230GSDMAState), + VMSTATE_UINT32(dma_int_stat, K230GSDMAState), + VMSTATE_UINT32(dma_cfg, K230GSDMAState), + VMSTATE_UINT32(dma_weight, K230GSDMAState), + VMSTATE_STRUCT_ARRAY(channels, K230GSDMAState, + K230_GSDMA_NUM_SDMA_CHANNELS, 2, + vmstate_k230_gsdma_channel, K230GSDMAChannel), + VMSTATE_END_OF_LIST() + } +}; + +static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size) +{ + K230GSDMAState *s = K230_GSDMA(opaque); + unsigned int ch; + hwaddr ch_off; + uint64_t ret = 0; + + switch (addr) { + case K230_GSDMA_DMA_CH_EN: + ret = s->dma_ch_en; + break; + case K230_GSDMA_DMA_INT_MASK: + ret = s->dma_int_mask; + break; + case K230_GSDMA_DMA_INT_STAT: + ret = s->dma_int_stat; + break; + case K230_GSDMA_DMA_CFG: + ret = s->dma_cfg; + break; + case K230_GSDMA_DMA_WEIGHT: + ret = s->dma_weight; + break; + default: + if (addr < K230_GSDMA_CH_BASE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: not implement gdma at offset 0x%" HWADDR_PRIx + "\n", __func__, addr); + } + break; + } + + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE; + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE; + if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) { + switch (ch_off) { + case K230_GSDMA_CH_CTL: + break; + case K230_GSDMA_CH_STATUS: + ret = s->channels[ch].status; + break; + case K230_GSDMA_CH_CFG: + ret = s->channels[ch].cfg; + break; + case K230_GSDMA_CH_USR_DATA: + ret = s->channels[ch].usr_data; + break; + case K230_GSDMA_CH_LLT_SADDR: + ret = s->channels[ch].llt_saddr; + break; + case K230_GSDMA_CH_CURRENT_LLT: + ret = s->channels[ch].current_llt; + break; + default: + break; + } + } + + trace_k230_gsdma_read(addr, size, ret); + return ret; +} + +static void k230_gsdma_write_channel(K230GSDMAState *s, unsigned int ch, + hwaddr ch_off, uint32_t value) +{ + K230GSDMAChannel *c = &s->channels[ch]; + bool handshake_mode = ch < 2 && k230_gsdma_decomp_enabled(s); + + switch (ch_off) { + case K230_GSDMA_CH_CTL: + c->ctl = value; + if ((value & K230_GSDMA_CTL_STOP) != 0) { + c->started = false; + k230_gsdma_sdma_set_idle(c); + break; + } + if ((value & K230_GSDMA_CTL_RESUME) != 0 && + (c->status & K230_GSDMA_SDMA_STATUS_PAUSE) && c->next_llt != 0) { + k230_gsdma_run_sdma(s, ch, c->next_llt); + break; + } + if (handshake_mode && (value & K230_GSDMA_CTL_START) != 0) { + c->started = true; + c->status &= ~(K230_GSDMA_SDMA_STATUS_BUSY | + K230_GSDMA_SDMA_STATUS_PAUSE); + c->current_llt = 0; + c->next_llt = 0; + break; + } + if ((value & K230_GSDMA_CTL_START) != 0 && + (s->dma_ch_en & BIT(ch)) && c->llt_saddr != 0) { + c->started = true; + k230_gsdma_run_sdma(s, ch, c->llt_saddr); + } + break; + case K230_GSDMA_CH_CFG: + c->cfg = value; + break; + case K230_GSDMA_CH_USR_DATA: + c->usr_data = value; + break; + case K230_GSDMA_CH_LLT_SADDR: + c->llt_saddr = value; + break; + case K230_GSDMA_CH_CURRENT_LLT: + break; + default: + break; + } +} + +static void k230_gsdma_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + K230GSDMAState *s = K230_GSDMA(opaque); + unsigned int ch; + hwaddr ch_off; + uint32_t v = value; + + trace_k230_gsdma_write(addr, size, value); + + switch (addr) { + case K230_GSDMA_DMA_CH_EN: + s->dma_ch_en = v & K230_GSDMA_DMA_CH_EN_MASK; + return; + case K230_GSDMA_DMA_INT_MASK: + s->dma_int_mask = v; + k230_gsdma_update_irq(s); + return; + case K230_GSDMA_DMA_INT_STAT: + s->dma_int_stat &= ~v; + k230_gsdma_update_irq(s); + return; + case K230_GSDMA_DMA_CFG: + s->dma_cfg = v; + return; + case K230_GSDMA_DMA_WEIGHT: + s->dma_weight = v & 0x00ffffff; + return; + default: + break; + } + + if (addr < K230_GSDMA_CH_BASE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: not implement gdma at offset 0x%" HWADDR_PRIx + "\n", __func__, addr); + return; + } + + ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE; + ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE; + if (ch >= K230_GSDMA_NUM_SDMA_CHANNELS) { + return; + } + + k230_gsdma_write_channel(s, ch, ch_off, v); +} + +static void k230_gsdma_handle_signal(void *opaque, int n, int level) +{ + K230GSDMAState *s = opaque; + K230GSDMAChannel *c; + hwaddr addr; + unsigned int ch; + + if (!level || n == K230_GSDMA_GPIO_DECOMP_CTRL_EN) { + return; + } + + ch = n - 1; + + c = &s->channels[ch]; + if (!k230_gsdma_decomp_enabled(s) || !(s->dma_ch_en & BIT(ch)) || !c->started) { + return; + } + + if (c->current_llt == 0) { + addr = c->llt_saddr; + } else { + addr = c->next_llt; + } + if (!addr) { + return; + } + + k230_gsdma_step_sdma(s, ch, addr); + qemu_set_irq(s->handshake_out[n - 1], 1); + qemu_set_irq(s->handshake_out[n - 1], 0); +} + +static const MemoryRegionOps k230_gsdma_ops = { + .read = k230_gsdma_read, + .write = k230_gsdma_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static void k230_gsdma_reset_hold(Object *obj, ResetType type) +{ + K230GSDMAState *s = K230_GSDMA(obj); + + memset(s->channels, 0, sizeof(s->channels)); + s->dma_ch_en = 0; + s->dma_int_mask = 0; + s->dma_int_stat = 0; + s->dma_cfg = K230_GSDMA_DMA_CFG_RESET; + s->dma_weight = 0; +} + +static void k230_gsdma_realize(DeviceState *dev, Error **errp) +{ + K230GSDMAState *s = K230_GSDMA(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &k230_gsdma_ops, s, + TYPE_K230_GSDMA, K230_GSDMA_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(DEVICE(dev), k230_gsdma_handle_signal, + K230_GSDMA_NUM_GPIOS_IN); + qdev_init_gpio_out(DEVICE(dev), s->handshake_out, + K230_GSDMA_NUM_GPIOS_OUT); +} + +static void k230_gsdma_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + dc->realize = k230_gsdma_realize; + rc->phases.hold = k230_gsdma_reset_hold; + dc->vmsd = &vmstate_k230_gsdma; + dc->desc = "Kendryte K230 GSDMA"; +} + +static const TypeInfo k230_gsdma_info = { + .name = TYPE_K230_GSDMA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(K230GSDMAState), + .class_init = k230_gsdma_class_init, +}; + +static void k230_gsdma_register_types(void) +{ + type_register_static(&k230_gsdma_info); +} + +type_init(k230_gsdma_register_types) diff --git a/hw/dma/meson.build b/hw/dma/meson.build index cc7810beb8..45db5e7357 100644 --- a/hw/dma/meson.build +++ b/hw/dma/meson.build @@ -12,3 +12,4 @@ system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c')) system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c')) system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c')) system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c')) +system_ss.add(when: 'CONFIG_K230_GSDMA', if_true: files('k230_gsdma.c')) diff --git a/hw/dma/trace-events b/hw/dma/trace-events index 4c09790f9a..a494755b5a 100644 --- a/hw/dma/trace-events +++ b/hw/dma/trace-events @@ -47,3 +47,9 @@ pl330_iomem_read(uint32_t addr, uint32_t data) "addr: 0x%08"PRIx32" data: 0x%08" # xilinx_axidma.c xilinx_axidma_loading_desc_fail(uint32_t res) "error:%u" + +# k230_gsdma.c +k230_gsdma_read(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA read: [0x%"PRIx64"] size %u -> 0x%"PRIx64 +k230_gsdma_write(uint64_t addr, unsigned int size, uint64_t data) "K230 GSDMA write: [0x%"PRIx64"] size %u <- 0x%"PRIx64 +k230_gsdma_read_sdma_llt(uint64_t addr, uint32_t cfg, uint32_t src_addr, uint32_t line_size, uint32_t line_cfg, uint32_t dst_addr, uint32_t next_llt_addr) "K230 GSDMA read SDMA LLT: addr=0x%"PRIx64" cfg=0x%"PRIx32" src=0x%"PRIx32" line_size=0x%"PRIx32" line_cfg=0x%"PRIx32" dst=0x%"PRIx32" next=0x%"PRIx32 +k230_gsdma_read_sdma_llt_failed(uint64_t addr) "K230 GSDMA read SDMA LLT failed: addr=0x%"PRIx64 diff --git a/include/hw/dma/k230_gsdma.h b/include/hw/dma/k230_gsdma.h new file mode 100644 index 0000000000..629cce29f8 --- /dev/null +++ b/include/hw/dma/k230_gsdma.h @@ -0,0 +1,130 @@ +/* + * K230 GSDMA + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_DMA_K230_GSDMA_H +#define HW_DMA_K230_GSDMA_H + +#include "hw/core/sysbus.h" + +#define TYPE_K230_GSDMA "riscv.k230.gsdma" +OBJECT_DECLARE_SIMPLE_TYPE(K230GSDMAState, K230_GSDMA) + +#define K230_GSDMA_MMIO_SIZE 0x4000 +#define K230_GSDMA_NUM_SDMA_CHANNELS 4 + +#define K230_GSDMA_CH_STRIDE 0x30 +#define K230_GSDMA_CH_BASE 0x50 + +/* K230 SDMA request input */ +enum { + K230_GSDMA_GPIO_DECOMP_CTRL_EN, + K230_GSDMA_GPIO_DMA_WRITE_REQ, + K230_GSDMA_GPIO_DMA_READ_REQ, + K230_GSDMA_NUM_GPIOS_IN, +}; + +/* K230 SDMA ACK output */ +enum { + K230_GSDMA_GPIO_DMA_WRITE_ACK, + K230_GSDMA_GPIO_DMA_READ_ACK, + K230_GSDMA_NUM_GPIOS_OUT, +}; + +/* K230 GSDMA Registers Map */ +#define K230_GSDMA_DMA_CH_EN 0x00 +#define K230_GSDMA_DMA_INT_MASK 0x04 +#define K230_GSDMA_DMA_INT_STAT 0x08 +#define K230_GSDMA_DMA_CFG 0x0c +#define K230_GSDMA_GDMA_CTRL 0x10 +#define K230_GSDMA_GDMA_LLI_BASE 0x14 +#define K230_GSDMA_GDMA_CH_CNT0 0x18 +#define K230_GSDMA_GDMA_CH_CNT_LAST 0x34 +#define K230_GSDMA_GDMA_CURRENT_LLT 0x38 +#define K230_GSDMA_DMA_WEIGHT 0x48 + +/* K230 GSDMA SDMA Channel Register Map */ +#define K230_GSDMA_CH_CTL 0x00 +#define K230_GSDMA_CH_STATUS 0x04 +#define K230_GSDMA_CH_CFG 0x08 +#define K230_GSDMA_CH_USR_DATA 0x0c +#define K230_GSDMA_CH_LLT_SADDR 0x10 +#define K230_GSDMA_CH_CURRENT_LLT 0x14 + +/* K230 SDMA Control bit */ +#define K230_GSDMA_CTL_START BIT(0) +#define K230_GSDMA_CTL_STOP BIT(1) +#define K230_GSDMA_CTL_RESUME BIT(2) + +/* K230 SDMA States bit */ +#define K230_GSDMA_SDMA_STATUS_BUSY BIT(0) +#define K230_GSDMA_SDMA_STATUS_PAUSE BIT(1) + +/* K230 SDMA Interrupt bit */ +#define K230_GSDMA_SDMA_DONE_INT(ch) BIT(ch) +#define K230_GSDMA_SDMA_ITEM_INT(ch) BIT((ch) + 4) +#define K230_GSDMA_SDMA_PAUSE_INT(ch) BIT((ch) + 8) + + +#define K230_GSDMA_DMA_CH_EN_MASK MAKE_64BIT_MASK(0, 5) +#define K230_GSDMA_DMA_CFG_RESET 0x000007ff + +/* K230 SDMA Linked List bit */ +#define K230_GSDMA_LLT_2D_MODE BIT(28) +#define K230_GSDMA_LLT_PAUSE BIT(29) +#define K230_GSDMA_LLT_NODE_INTR BIT(30) +#define K230_GSDMA_GDMA_LLT_GCH_SHIFT 16 +#define K230_GSDMA_GDMA_LLT_GCH_MASK 0x7 +#define K230_GSDMA_CH_CFG_DAT_MODE BIT(0) +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_SHIFT 1 +#define K230_GSDMA_CH_CFG_USR_DATA_SIZE_MASK 0x3 +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_SHIFT 4 +#define K230_GSDMA_CH_CFG_DAT_ENDIAN_MASK 0x3 +#define K230_GSDMA_CH_CFG_SRC_FIXED BIT(8) +#define K230_GSDMA_CH_CFG_DST_FIXED BIT(9) +#define K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN BIT(10) + +/* K230 SDMA channel state */ +typedef struct K230GSDMAChannel { + uint32_t ctl; + uint32_t status; + uint32_t cfg; + uint32_t usr_data; + uint32_t llt_saddr; + uint32_t current_llt; + uint32_t next_llt; + bool started; +} K230GSDMAChannel; + +/* K230 SDMA Linked List */ +typedef struct K230GSDMALLT { + uint32_t cfg; + uint32_t src_addr; + uint32_t line_size; + uint32_t line_cfg; + uint32_t dst_addr; + uint32_t next_llt_addr; +} K230GSDMALLT; + +/* K230 GSDMA state */ +struct K230GSDMAState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + qemu_irq handshake_out[K230_GSDMA_NUM_GPIOS_OUT]; + + uint32_t dma_ch_en; + uint32_t dma_int_mask; + uint32_t dma_int_stat; + uint32_t dma_cfg; + uint32_t dma_weight; + + K230GSDMAChannel channels[K230_GSDMA_NUM_SDMA_CHANNELS]; +}; + +#endif From dde8fbba19c19d536d323705e9700b552cf29272 Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:22 +0800 Subject: [PATCH 488/627] hw/riscv: k230: add gsdma in K230 board This commit replaces the unimplemented part of GSDMA in K230. And connect the interrupt to plic. Update K230.rst. Signed-off-by: Tao Ding Reviewed-by: Junze Cao Reviewed-by: Daniel Henrique Barboza Message-ID: <20260808062227.66961-3-dingtao0430@163.com> Signed-off-by: Alistair Francis --- docs/system/riscv/k230.rst | 1 + hw/riscv/Kconfig | 1 + hw/riscv/k230.c | 12 +++++++++--- include/hw/riscv/k230.h | 3 +++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst index 06a819fbdb..5cbc0b14bc 100644 --- a/docs/system/riscv/k230.rst +++ b/docs/system/riscv/k230.rst @@ -21,6 +21,7 @@ The ``k230`` machine supports the following devices: * 2 K230 Watchdog Timer * 5 UART * K230 DDRC CFG and DDR PHY +* System Direct Memory Access (SDMA) Boot options ------------ diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index de37c08cae..d28ac06043 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -162,3 +162,4 @@ config K230 select SERIAL_MM select UNIMP select K230_WDT + select K230_GSDMA diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 627150b463..49c3b50c57 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -116,6 +116,7 @@ static void k230_soc_init(Object *obj) s->ddr_cfg.phy = &s->ddr_phy; object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT); object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT); + object_initialize_child(obj, "k230-gsdma", &s->gsdma, TYPE_K230_GSDMA); qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0); qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908); @@ -222,6 +223,14 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0, qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ)); + /* Gsdma */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gsdma), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gsdma), 0, memmap[K230_DEV_GSDMA].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gsdma), 0, + qdev_get_gpio_in(DEVICE(s->c908_plic), K230_GSDMA_IRQ)); + /* unimplemented devices */ create_unimplemented_device("kpu.l2-cache", memmap[K230_DEV_KPU_L2_CACHE].base, @@ -237,9 +246,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) memmap[K230_DEV_AI_2D_ENGINE].base, memmap[K230_DEV_AI_2D_ENGINE].size); - create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base, - memmap[K230_DEV_GSDMA].size); - create_unimplemented_device("dma", memmap[K230_DEV_DMA].base, memmap[K230_DEV_DMA].size); diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index 80ca16338c..8879d56d98 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -19,6 +19,7 @@ #include "hw/misc/k230_ddr.h" #include "hw/riscv/riscv_hart.h" #include "hw/watchdog/k230_wdt.h" +#include "hw/dma/k230_gsdma.h" #define C908_CPU_HARTID (0) @@ -36,6 +37,7 @@ typedef struct K230SoCState { K230DDRCfgState ddr_cfg; K230DDRPhyState ddr_phy; K230WdtState wdt[2]; + K230GSDMAState gsdma; MemoryRegion sram; MemoryRegion bootrom; @@ -133,6 +135,7 @@ enum { K230_UART4_IRQ = 20, K230_WDT0_IRQ = 107, K230_WDT1_IRQ = 108, + K230_GSDMA_IRQ = 140, }; #define K230_UART_COUNT 5 From 8041d173087109d7194cf2d0cf7e76d13460354f Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:23 +0800 Subject: [PATCH 489/627] tests/qtest: add test for K230 gsdma This commit adds test cases for GSDMA. Imitate the behavior of the driver, set LLT and sdma registers. After the data transmission is completed, check the destination address data. Update MAINTAINERS for this test. Run this qtest: $ mkdir build && cd build && ../configure --target-list="riscv64-softmmu" $ QTEST_QEMU_BINARY=./qemu-system-riscv64 tests/qtest/k230-gsdma-test Signed-off-by: Tao Ding Reviewed-by: Daniel Henrique Barboza Reviewed-by: Junze Cao Message-ID: <20260808062227.66961-4-dingtao0430@163.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 3 + docs/system/riscv/k230.rst | 1 + hw/misc/Kconfig | 3 + hw/misc/k230_decomp_gzip.c | 511 +++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 8 +- include/hw/misc/k230_decomp_gzip.h | 92 ++++++ tests/qtest/k230-gsdma-test.c | 201 ++++++++++++ tests/qtest/meson.build | 2 +- 9 files changed, 816 insertions(+), 6 deletions(-) create mode 100644 hw/misc/k230_decomp_gzip.c create mode 100644 include/hw/misc/k230_decomp_gzip.h create mode 100644 tests/qtest/k230-gsdma-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 027db78b39..ff804b3310 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1848,13 +1848,16 @@ F: hw/misc/k230_ddr.c F: hw/riscv/k230.c F: hw/watchdog/k230_wdt.c F: hw/dma/k230_gsdma.c +F: hw/misc/k230_decomp_gzip.c F: include/hw/misc/k230_ddr.h F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: include/hw/dma/k230_gsdma.h +F: include/hw/misc/k230_decomp_gzip.h F: tests/functional/riscv64/test_k230.py F: tests/qtest/k230-ddr-test.c F: tests/qtest/k230-wdt-test.c +F: tests/qtest/k230-gsdma-test.c RX Machines ----------- diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst index 5cbc0b14bc..237611eddf 100644 --- a/docs/system/riscv/k230.rst +++ b/docs/system/riscv/k230.rst @@ -22,6 +22,7 @@ The ``k230`` machine supports the following devices: * 5 UART * K230 DDRC CFG and DDR PHY * System Direct Memory Access (SDMA) +* GZIP Decompress Engine (Decomp_gzip) Boot options ------------ diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index b8860dd3e7..46e3c03cc8 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -260,4 +260,7 @@ config XLNX_ZYNQ_DDRC config AXIADO_CLK bool +config K230_DECOMP_GZIP + bool + source macio/Kconfig diff --git a/hw/misc/k230_decomp_gzip.c b/hw/misc/k230_decomp_gzip.c new file mode 100644 index 0000000000..0d8a3b2d2e --- /dev/null +++ b/hw/misc/k230_decomp_gzip.c @@ -0,0 +1,511 @@ +/* + * Kendryte K230 GZIP decompression engine + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Decompression accelerator is mainly used to implement hardware + * GZIP decompression function. (K230 TRM section 15) + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/core/qdev-properties.h" +#include "migration/vmstate.h" +#include "system/address-spaces.h" +#include "hw/core/irq.h" +#include "hw/misc/k230_decomp_gzip.h" +#include "trace.h" + +#define GZIP_METHOD_DEFLATE 8 +#define GZIP_METHOD_VENDOR_9 9 + +#define DEFLATE_BTYPE_DYNAMIC 2 + +#define K230_DECOMP_GZIP_OUTPUT_SLOTS 4 +#define K230_DECOMP_GZIP_INPUT_SLOTS 2 + +static void k230_decomp_gzip_set_output(K230DecompGzipState *s, int line, + int level) +{ + qemu_set_irq(s->signal_out[line], level); +} + +static bool k230_decomp_gzip_read_mem(K230DecompGzipState *s, hwaddr addr, + void *buf, size_t len) +{ + MemTxResult ret = address_space_read(&address_space_memory, + s->sram_base + addr, + MEMTXATTRS_UNSPECIFIED, buf, len); + + return ret == MEMTX_OK; +} + +static bool k230_decomp_gzip_write_mem(K230DecompGzipState *s, hwaddr addr, + const void *buf, size_t len) +{ + return address_space_write(&address_space_memory, s->sram_base + addr, + MEMTXATTRS_UNSPECIFIED, buf, len) == MEMTX_OK; +} + +static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s) +{ + return K230_DECOMP_GZIP_SRAM_OUT_BASE + + s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE + + s->output.current_offset; +} + +static hwaddr k230_decomp_gzip_input_addr(K230DecompGzipState *s) +{ + return s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE + + K230_DECOMP_GZIP_SRAM_IN_BASE; +} + +static uint32_t k230_decomp_gzip_current_input_size(K230DecompGzipState *s) +{ + if (s->total_requested == 0) { + return 0; + } + + return ((s->total_requested - 1) % K230_DECOMP_GZIP_BLOCK_SIZE) + 1; +} + +static void k230_decomp_gzip_update_ctrl_en(K230DecompGzipState *s) +{ + int level = s->active && !!(s->gzip_src_size & K230_DECOMP_GZIP_CTRL_EN); + + k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DECOMP_CTRL_EN, + level); +} + +static void k230_decomp_gzip_reset_stream(K230DecompGzipState *s) +{ + if (s->zstream_inited) { + inflateEnd(&s->zs); + s->zstream_inited = false; + } + memset(&s->zs, 0, sizeof(s->zs)); +} + +static void k230_decomp_gzip_finish(K230DecompGzipState *s, bool crc_ok) +{ + s->active = false; + k230_decomp_gzip_reset_stream(s); + k230_decomp_gzip_update_ctrl_en(s); + if (crc_ok) { + s->decomp_stat |= K230_DECOMP_GZIP_STAT_CRC_OK; + } else { + s->decomp_stat &= ~K230_DECOMP_GZIP_STAT_CRC_OK; + } +} + +static bool k230_decomp_gzip_load_input(K230DecompGzipState *s, + uint32_t addr, uint32_t size) +{ + s->input.current_offset = 0; + + return k230_decomp_gzip_read_mem(s, addr, s->input_buf, size); +} + +static bool k230_decomp_gzip_request_input(K230DecompGzipState *s) +{ + uint32_t total_requested = s->total_requested; + + k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DMA_WRITE_REQ, 1); + if (s->total_requested == total_requested) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: dma write request not acknowledged\n", + TYPE_K230_DECOMP_GZIP); + return false; + } + return true; +} + +static bool k230_decomp_gzip_request_output(K230DecompGzipState *s) +{ + uint32_t slot = s->output.slot; + uint32_t current_offset = s->output.current_offset; + + k230_decomp_gzip_set_output(s, K230_DECOMP_GZIP_GPIO_DMA_READ_REQ, 1); + if (s->output.slot == slot && + s->output.current_offset == current_offset) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: dma read request not acknowledged\n", + TYPE_K230_DECOMP_GZIP); + return false; + } + return true; +} + +static bool k230_decomp_gzip_init_stream(K230DecompGzipState *s) +{ + uint8_t btype = (s->input_buf[10] >> 1) & 0x3; + if (btype != DEFLATE_BTYPE_DYNAMIC) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: unsupported DEFLATE BTYPE %u\n", + TYPE_K230_DECOMP_GZIP, btype); + return false; + } + + /* The compression script for K230 will modify the third byte to 0x9 */ + if (s->input_buf[2] == GZIP_METHOD_VENDOR_9) { + s->input_buf[2] = GZIP_METHOD_DEFLATE; + } + + if (inflateInit2(&s->zs, 15 + 16) != Z_OK) { + return false; + } + + s->zstream_inited = true; + return true; +} + +static bool k230_decomp_gzip_run_inflate(K230DecompGzipState *s) +{ + uint32_t output_size = s->gzip_out_size; + uint32_t current_input_size = k230_decomp_gzip_current_input_size(s); + uint32_t avail_in; + uint32_t avail_out; + uint32_t consumed; + uint32_t produced; + int ret; + + avail_in = current_input_size - s->input.current_offset; + avail_out = K230_DECOMP_GZIP_BLOCK_SIZE - s->output.current_offset; + + s->zs.next_in = s->input_buf + s->input.current_offset; + s->zs.avail_in = avail_in; + s->zs.next_out = s->output_buf; + s->zs.avail_out = avail_out; + + ret = inflate(&s->zs, Z_NO_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) { + return false; + } + + consumed = avail_in - s->zs.avail_in; + produced = avail_out - s->zs.avail_out; + + if (produced) { + if (s->total_produced + produced > output_size || + !k230_decomp_gzip_write_mem(s, k230_decomp_gzip_output_addr(s), + s->output_buf, produced)) { + return false; + } + s->output.current_offset += produced; + s->total_produced += produced; + } + + if (consumed) { + s->input.current_offset += consumed; + } + + if (ret == Z_STREAM_END) { + s->stream_end = true; + if (s->total_produced != output_size) { + return false; + } + } + + return true; +} + +static void k230_decomp_gzip_kick(K230DecompGzipState *s) +{ + if (!s->active || s->in_kick) { + return; + } + + uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK; + s->in_kick = true; + while (s->active) { + uint32_t current_input_size = k230_decomp_gzip_current_input_size(s); + /* Output is full or last block */ + if (s->output.current_offset == K230_DECOMP_GZIP_BLOCK_SIZE || + (s->stream_end && s->output.current_offset != 0)) { + if (!k230_decomp_gzip_request_output(s)) { + k230_decomp_gzip_finish(s, false); + break; + } + continue; + } + + if (!s->zstream_inited) { + if (!k230_decomp_gzip_request_input(s) || + !k230_decomp_gzip_init_stream(s)) { + k230_decomp_gzip_finish(s, false); + break; + } + continue; + } + + /* Transfer finish */ + if (s->stream_end) { + k230_decomp_gzip_finish(s, + s->total_produced == s->gzip_out_size); + break; + } + + /* Input buf has has been fully decompreed, need request more */ + if (s->input.current_offset == current_input_size) { + if (s->total_requested < input_size) { + if (!k230_decomp_gzip_request_input(s)) { + k230_decomp_gzip_finish(s, false); + break; + } + continue; + } + k230_decomp_gzip_finish(s, false); + break; + } + + /* Decompress the data, input buf or output buf are consumed in one block */ + if (!k230_decomp_gzip_run_inflate(s)) { + k230_decomp_gzip_finish(s, false); + break; + } + } + s->in_kick = false; +} + +static void k230_decomp_gzip_handle_ack(void *opaque, int n, int level) +{ + K230DecompGzipState *s = opaque; + + if (!level || !s->active) { + return; + } + + switch (n) { + case K230_DECOMP_GZIP_GPIO_DMA_WRITE_ACK: + { + uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK; + uint32_t chunk = MIN(K230_DECOMP_GZIP_BLOCK_SIZE, + input_size - s->total_requested); + + if (!k230_decomp_gzip_load_input(s, k230_decomp_gzip_input_addr(s), + chunk)) { + k230_decomp_gzip_finish(s, false); + return; + } + s->total_requested += chunk; + s->input.slot = (s->input.slot + 1) % K230_DECOMP_GZIP_INPUT_SLOTS; + break; + } + case K230_DECOMP_GZIP_GPIO_DMA_READ_ACK: + if (s->output.current_offset == 0) { + k230_decomp_gzip_finish(s, false); + return; + } + s->output.slot = (s->output.slot + 1) % K230_DECOMP_GZIP_OUTPUT_SLOTS; + s->output.current_offset = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid DMA acknowledgment signal %d\n", + TYPE_K230_DECOMP_GZIP, n); + return; + } + + k230_decomp_gzip_kick(s); +} + +static void k230_decomp_gzip_start(K230DecompGzipState *s) +{ + uint32_t input_size = s->gzip_src_size & K230_DECOMP_GZIP_DMA_IN_MASK; + + k230_decomp_gzip_reset_stream(s); + s->decomp_stat &= ~K230_DECOMP_GZIP_STAT_CRC_OK; + s->total_requested = 0; + s->total_produced = 0; + s->stream_end = false; + memset(&s->input, 0, sizeof(s->input)); + memset(&s->output, 0, sizeof(s->output)); + + if (!(s->gzip_src_size & K230_DECOMP_GZIP_CTRL_EN) || + input_size == 0 || s->gzip_out_size == 0) { + k230_decomp_gzip_finish(s, false); + return; + } + + s->active = true; + k230_decomp_gzip_update_ctrl_en(s); + k230_decomp_gzip_kick(s); +} + +static uint64_t k230_decomp_gzip_read(void *opaque, hwaddr offset, + unsigned size) +{ + K230DecompGzipState *s = opaque; + uint64_t value = 0; + + switch (offset) { + case K230_DECOMP_GZIP_DECOMP_START: + value = s->decomp_start & ~K230_DECOMP_GZIP_START; /* start bit is write only */ + break; + case K230_DECOMP_GZIP_GZIP_SRC_SIZE: + value = s->gzip_src_size; + break; + case K230_DECOMP_GZIP_GZIP_OUT_SIZE: + value = s->gzip_out_size; + break; + case K230_DECOMP_GZIP_DECOMP_STAT: + value = s->decomp_stat; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad read offset 0x%" HWADDR_PRIx "\n", + TYPE_K230_DECOMP_GZIP, offset); + break; + } + + trace_k230_decomp_gzip_read(offset, size, value); + return value; +} + +static void k230_decomp_gzip_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + K230DecompGzipState *s = opaque; + + trace_k230_decomp_gzip_write(offset, size, value); + + switch (offset) { + case K230_DECOMP_GZIP_DECOMP_START: + s->decomp_start = value; + if (value & K230_DECOMP_GZIP_START) { + k230_decomp_gzip_start(s); + } + break; + case K230_DECOMP_GZIP_GZIP_SRC_SIZE: + s->gzip_src_size = value; + k230_decomp_gzip_update_ctrl_en(s); + break; + case K230_DECOMP_GZIP_GZIP_OUT_SIZE: + s->gzip_out_size = value; + break; + case K230_DECOMP_GZIP_DECOMP_STAT: + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad write offset 0x%" HWADDR_PRIx "\n", + TYPE_K230_DECOMP_GZIP, offset); + break; + } +} + +static const MemoryRegionOps k230_decomp_gzip_ops = { + .read = k230_decomp_gzip_read, + .write = k230_decomp_gzip_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static const VMStateDescription vmstate_k230_decomp_gzip_slot = { + .name = "k230.decomp-gzip.slot", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(slot, K230DecompGzipSlotState), + VMSTATE_UINT32(current_offset, K230DecompGzipSlotState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_k230_decomp_gzip = { + .name = "k230.decomp-gzip", + .version_id = 1, + .minimum_version_id = 1, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(decomp_start, K230DecompGzipState), + VMSTATE_UINT32(gzip_src_size, K230DecompGzipState), + VMSTATE_UINT32(gzip_out_size, K230DecompGzipState), + VMSTATE_UINT32(decomp_stat, K230DecompGzipState), + VMSTATE_STRUCT(input, K230DecompGzipState, 1, + vmstate_k230_decomp_gzip_slot, + K230DecompGzipSlotState), + VMSTATE_STRUCT(output, K230DecompGzipState, 1, + vmstate_k230_decomp_gzip_slot, + K230DecompGzipSlotState), + VMSTATE_UINT32(total_requested, K230DecompGzipState), + VMSTATE_UINT32(total_produced, K230DecompGzipState), + VMSTATE_BOOL(active, K230DecompGzipState), + VMSTATE_BOOL(in_kick, K230DecompGzipState), + VMSTATE_BOOL(zstream_inited, K230DecompGzipState), + VMSTATE_BOOL(stream_end, K230DecompGzipState), + VMSTATE_UINT8_ARRAY(input_buf, K230DecompGzipState, + K230_DECOMP_GZIP_BLOCK_SIZE), + VMSTATE_UINT8_ARRAY(output_buf, K230DecompGzipState, + K230_DECOMP_GZIP_BLOCK_SIZE), + VMSTATE_END_OF_LIST() + } +}; + +static void k230_decomp_gzip_reset_hold(Object *obj, ResetType type) +{ + K230DecompGzipState *s = K230_DECOMP_GZIP(obj); + + k230_decomp_gzip_reset_stream(s); + memset(&s->zs, 0, sizeof(s->zs)); + s->decomp_start = 0; + s->gzip_src_size = 0; + s->gzip_out_size = 0; + s->decomp_stat = 0; + memset(&s->input, 0, sizeof(s->input)); + memset(&s->output, 0, sizeof(s->output)); + s->total_requested = 0; + s->total_produced = 0; + s->active = false; + s->in_kick = false; + s->stream_end = false; +} + +static void k230_decomp_gzip_realize(DeviceState *dev, Error **errp) +{ + K230DecompGzipState *s = K230_DECOMP_GZIP(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &k230_decomp_gzip_ops, s, + TYPE_K230_DECOMP_GZIP, + K230_DECOMP_GZIP_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_in(dev, k230_decomp_gzip_handle_ack, + K230_DECOMP_GZIP_NUM_GPIOS_IN); + qdev_init_gpio_out(dev, s->signal_out, + K230_DECOMP_GZIP_NUM_GPIOS_OUT); +} + +static const Property k230_decomp_gzip_properties[] = { + DEFINE_PROP_UINT64("sram-base", K230DecompGzipState, sram_base, 0), +}; + +static void k230_decomp_gzip_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + dc->realize = k230_decomp_gzip_realize; + rc->phases.hold = k230_decomp_gzip_reset_hold; + device_class_set_props(dc, k230_decomp_gzip_properties); + dc->vmsd = &vmstate_k230_decomp_gzip; + dc->desc = "Kendryte K230 GZIP decompression engine"; +} + +static const TypeInfo k230_decomp_gzip_info = { + .name = TYPE_K230_DECOMP_GZIP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(K230DecompGzipState), + .class_init = k230_decomp_gzip_class_init, +}; + +static void k230_decomp_gzip_register_types(void) +{ + type_register_static(&k230_decomp_gzip_info); +} + +type_init(k230_decomp_gzip_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index cbeecbf1e0..54e07aacda 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -38,6 +38,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) +system_ss.add(when: 'CONFIG_K230_DECOMP_GZIP', if_true: files('k230_decomp_gzip.c')) subdir('macio') diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 2d6d2238c5..16db4ba0cc 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -443,8 +443,6 @@ iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=0x%x actu iommu_testdev_dma_result(uint32_t result) "DMA completed result=0x%x" iommu_testdev_dma_armed(bool armed) "armed=%d" -# vmlaunchupdate.c -launch_update_write(void) "" -vmlaunch_reset_enter(void) "" -vm_launchupdate_finalize(void) "" -restore_host_x86_igvm(void) "" +# k230_decomp_gzip.c +k230_decomp_gzip_read(uint64_t offset, unsigned int size, uint64_t value) "K230 DECOMP GZIP read: [0x%"PRIx64"] size %u -> 0x%"PRIx64 +k230_decomp_gzip_write(uint64_t offset, unsigned int size, uint64_t value) "K230 DECOMP GZIP write: [0x%"PRIx64"] size %u <- 0x%"PRIx64 diff --git a/include/hw/misc/k230_decomp_gzip.h b/include/hw/misc/k230_decomp_gzip.h new file mode 100644 index 0000000000..9911af0095 --- /dev/null +++ b/include/hw/misc/k230_decomp_gzip.h @@ -0,0 +1,92 @@ +/* + * K230 Decompress Engine + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_MISC_K230_DECOMP_GZIP_H +#define HW_MISC_K230_DECOMP_GZIP_H + +#include +#include "hw/core/sysbus.h" + +#define TYPE_K230_DECOMP_GZIP "riscv.k230.decomp-gzip" +OBJECT_DECLARE_SIMPLE_TYPE(K230DecompGzipState, K230_DECOMP_GZIP) + +/* K230 DECOMP GZIP ACK input */ +enum { + K230_DECOMP_GZIP_GPIO_DMA_WRITE_ACK, + K230_DECOMP_GZIP_GPIO_DMA_READ_ACK, + K230_DECOMP_GZIP_NUM_GPIOS_IN, +}; + +/* K230 DECOMP GZIP REQ output */ +enum { + K230_DECOMP_GZIP_GPIO_DECOMP_CTRL_EN, + K230_DECOMP_GZIP_GPIO_DMA_WRITE_REQ, + K230_DECOMP_GZIP_GPIO_DMA_READ_REQ, + K230_DECOMP_GZIP_NUM_GPIOS_OUT, +}; + +#define K230_DECOMP_GZIP_MMIO_SIZE 0x4000 + +/* K230 DECOMP GZIP Registers map */ +/* Start decompression controller */ +#define K230_DECOMP_GZIP_DECOMP_START 0x00 +/* Source data length register */ +#define K230_DECOMP_GZIP_GZIP_SRC_SIZE 0x04 +/* Output data length register */ +#define K230_DECOMP_GZIP_GZIP_OUT_SIZE 0x08 +/* Decompress status register */ +#define K230_DECOMP_GZIP_DECOMP_STAT 0x0c + +/* Start decompression controller */ +#define K230_DECOMP_GZIP_START (1U << 0) + +#define K230_DECOMP_GZIP_CTRL_EN (1U << 31) +#define K230_DECOMP_GZIP_DMA_IN_MASK 0x7fffffffU + +#define K230_DECOMP_GZIP_STAT_CRC_OK (1U << 10) +#define K230_DECOMP_GZIP_STAT_STATE_MASK 0xfU + +#define K230_DECOMP_GZIP_BLOCK_SIZE 0x00020000 +#define K230_DECOMP_GZIP_SRAM_IN_BASE 0x80000 +#define K230_DECOMP_GZIP_SRAM_OUT_BASE 0 + +typedef struct K230DecompGzipSlotState { + uint32_t slot; /* Slot index */ + /* + * Data offset in current slot. + * First valid data in input buffer. Last valid data in output buffer. + */ + uint32_t current_offset; +} K230DecompGzipSlotState; + +struct K230DecompGzipState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + hwaddr sram_base; + qemu_irq signal_out[K230_DECOMP_GZIP_NUM_GPIOS_OUT]; + uint32_t decomp_start; + uint32_t gzip_src_size; + uint32_t gzip_out_size; + uint32_t decomp_stat; + K230DecompGzipSlotState input; /* decomp gzip ring input */ + K230DecompGzipSlotState output; /* decomp gzip ring output */ + uint32_t total_requested; + uint32_t total_produced; + bool active; + bool in_kick; + bool zstream_inited; + bool stream_end; + /* Read from ring input. */ + uint8_t input_buf[K230_DECOMP_GZIP_BLOCK_SIZE]; + /* Write to ring output. */ + uint8_t output_buf[K230_DECOMP_GZIP_BLOCK_SIZE]; + z_stream zs; +}; + +#endif diff --git a/tests/qtest/k230-gsdma-test.c b/tests/qtest/k230-gsdma-test.c new file mode 100644 index 0000000000..44d4248739 --- /dev/null +++ b/tests/qtest/k230-gsdma-test.c @@ -0,0 +1,201 @@ +/* + * QTest testcase for K230 GSDMA + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "exec/hwaddr.h" +#include "hw/dma/k230_gsdma.h" +#include "libqtest.h" + +#define K230_GSDMA_BASE 0x80800000 +#define TEST_LLT_ADDR0 0x10000 +#define TEST_LLT_ADDR1 0x10040 +#define TEST_LLT_ADDR2 0x10080 + +#define TEST_SRC_ADDR0 0x20000 +#define TEST_SRC_ADDR1 0x22000 +#define TEST_SRC_ADDR2 0x23000 +#define TEST_DST_ADDR0 0x30000 +#define TEST_DST_ADDR1 0x32000 +#define TEST_DST_ADDR2 0x33000 + +static inline uint64_t gsdma_reg(hwaddr off) +{ + return K230_GSDMA_BASE + off; +} + +static inline uint64_t gsdma_ch_reg(unsigned int ch, hwaddr off) +{ + return K230_GSDMA_BASE + K230_GSDMA_CH_BASE + + ch * K230_GSDMA_CH_STRIDE + off; +} + +static void write_sdma_llt_node_full(QTestState *qts, hwaddr addr, + uint32_t cfg, hwaddr src, + uint32_t size, hwaddr dst, + hwaddr next) +{ + qtest_writel(qts, addr + offsetof(K230GSDMALLT, cfg), cfg); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, src_addr), src); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_size), size); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_cfg), 0x1); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, dst_addr), dst); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, next_llt_addr), next); +} + +static void write_sdma_llt_node(QTestState *qts, hwaddr addr, uint32_t cfg, + uint32_t next) +{ + write_sdma_llt_node_full(qts, addr, cfg, 0x11110000, 0x200, + 0x22220000, next); +} + +static void fill_pattern(uint8_t *buf, size_t size, uint8_t seed) +{ + for (size_t i = 0; i < size; i++) { + buf[i] = seed + i * 37; + } +} + +static void test_global_registers(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CFG)), ==, + K230_GSDMA_DMA_CFG_RESET); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), 0xff); + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN)), ==, + K230_GSDMA_DMA_CH_EN_MASK); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_INT_MASK), 0x12345); + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_MASK)), ==, + 0x12345); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CFG), 0xa5a5a5a5); + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CFG)), ==, + 0xa5a5a5a5); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_WEIGHT), 0xff55aa55); + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_WEIGHT)), ==, + 0x55aa55); + + qtest_quit(qts); +} + +static void test_sdma_pause_resume(void) +{ + uint32_t int_stat; + QTestState *qts = qtest_init("-machine k230"); + + write_sdma_llt_node(qts, TEST_LLT_ADDR0, K230_GSDMA_LLT_PAUSE, + TEST_LLT_ADDR1); + write_sdma_llt_node(qts, TEST_LLT_ADDR1, K230_GSDMA_LLT_NODE_INTR, 0); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), BIT(0)); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR), TEST_LLT_ADDR0); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), K230_GSDMA_CTL_START); + + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), ==, + K230_GSDMA_SDMA_STATUS_PAUSE); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CURRENT_LLT)), + ==, TEST_LLT_ADDR0); + + int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_PAUSE_INT(0), ==, + K230_GSDMA_SDMA_PAUSE_INT(0)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==, 0); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT), int_stat); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), K230_GSDMA_CTL_RESUME); + + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), ==, + 0); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CURRENT_LLT)), + ==, TEST_LLT_ADDR1); + + int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==, + K230_GSDMA_SDMA_DONE_INT(0)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_ITEM_INT(0), ==, + K230_GSDMA_SDMA_ITEM_INT(0)); + + qtest_quit(qts); +} + +static void test_sdma_three_llt_copy(void) +{ + uint8_t src0[0x1000]; + uint8_t src1[1]; + uint8_t src2[511]; + uint8_t dst0[sizeof(src0)]; + uint8_t dst1[sizeof(src1)]; + uint8_t dst2[sizeof(src2)]; + uint32_t int_stat; + QTestState *qts = qtest_init("-machine k230"); + + fill_pattern(src0, sizeof(src0), 0x10); + fill_pattern(src1, sizeof(src1), 0x31); + fill_pattern(src2, sizeof(src2), 0x52); + memset(dst0, 0xa5, sizeof(dst0)); + memset(dst1, 0xa5, sizeof(dst1)); + memset(dst2, 0xa5, sizeof(dst2)); + + qtest_memwrite(qts, TEST_SRC_ADDR0, src0, sizeof(src0)); + qtest_memwrite(qts, TEST_SRC_ADDR1, src1, sizeof(src1)); + qtest_memwrite(qts, TEST_SRC_ADDR2, src2, sizeof(src2)); + qtest_memwrite(qts, TEST_DST_ADDR0, dst0, sizeof(dst0)); + qtest_memwrite(qts, TEST_DST_ADDR1, dst1, sizeof(dst1)); + qtest_memwrite(qts, TEST_DST_ADDR2, dst2, sizeof(dst2)); + + write_sdma_llt_node_full(qts, TEST_LLT_ADDR0, 0, TEST_SRC_ADDR0, + sizeof(src0), TEST_DST_ADDR0, TEST_LLT_ADDR1); + write_sdma_llt_node_full(qts, TEST_LLT_ADDR1, 0, TEST_SRC_ADDR1, + sizeof(src1), TEST_DST_ADDR1, TEST_LLT_ADDR2); + write_sdma_llt_node_full(qts, TEST_LLT_ADDR2, 0, TEST_SRC_ADDR2, + sizeof(src2), TEST_DST_ADDR2, 0); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), BIT(0)); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR), TEST_LLT_ADDR0); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), K230_GSDMA_CTL_START); + + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), ==, + 0); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CURRENT_LLT)), + ==, TEST_LLT_ADDR2); + + int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==, + K230_GSDMA_SDMA_DONE_INT(0)); + g_assert_cmphex(int_stat & K230_GSDMA_SDMA_PAUSE_INT(0), ==, 0); + + memset(dst0, 0, sizeof(dst0)); + memset(dst1, 0, sizeof(dst1)); + memset(dst2, 0, sizeof(dst2)); + qtest_memread(qts, TEST_DST_ADDR0, dst0, sizeof(dst0)); + qtest_memread(qts, TEST_DST_ADDR1, dst1, sizeof(dst1)); + qtest_memread(qts, TEST_DST_ADDR2, dst2, sizeof(dst2)); + + g_assert_cmpmem(dst0, sizeof(dst0), src0, sizeof(src0)); + g_assert_cmpmem(dst1, sizeof(dst1), src1, sizeof(src1)); + g_assert_cmpmem(dst2, sizeof(dst2), src2, sizeof(src2)); + + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/k230-gsdma/global-registers", test_global_registers); + qtest_add_func("/k230-gsdma/sdma-pause-resume", test_sdma_pause_resume); + qtest_add_func("/k230-gsdma/sdma-three-llt-copy", + test_sdma_three_llt_copy); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 663a66bded..84756ba823 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -300,7 +300,7 @@ qtests_riscv64 = ['riscv-csr-test'] + \ config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \ (config_all_devices.has_key('CONFIG_K230') ? - ['k230-ddr-test', 'k230-wdt-test'] : []) + ['k230-ddr-test', 'k230-wdt-test', 'k230-gsdma-test'] : []) qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test'] From 096ead3195a6739e6ecf51cc5781018302568e83 Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:25 +0800 Subject: [PATCH 490/627] hw/riscv: k230: add decomp gzip in K230 board This commit replaces the unimplemented part of Decomp_gzip in K230. Connect to the handshake interface of GSDMA. Signed-off-by: Tao Ding Reviewed-by: Junze Cao Reviewed-by: Daniel Henrique Barboza Message-ID: <20260808062227.66961-6-dingtao0430@163.com> Signed-off-by: Alistair Francis --- hw/riscv/Kconfig | 1 + hw/riscv/k230.c | 23 +++++++++++++++++++---- include/hw/riscv/k230.h | 2 ++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index d28ac06043..d06ac26648 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -163,3 +163,4 @@ config K230 select UNIMP select K230_WDT select K230_GSDMA + select K230_DECOMP_GZIP diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 49c3b50c57..5163eaa7ef 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -117,6 +117,8 @@ static void k230_soc_init(Object *obj) object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT); object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT); object_initialize_child(obj, "k230-gsdma", &s->gsdma, TYPE_K230_GSDMA); + object_initialize_child(obj, "k230-decomp-gzip", &s->decomp_gzip, + TYPE_K230_DECOMP_GZIP); qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0); qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908); @@ -231,6 +233,23 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->gsdma), 0, qdev_get_gpio_in(DEVICE(s->c908_plic), K230_GSDMA_IRQ)); + /* Decomp gzip */ + qdev_prop_set_uint64(DEVICE(&s->decomp_gzip), "sram-base", + memmap[K230_DEV_SRAM].base); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->decomp_gzip), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->decomp_gzip), 0, + memmap[K230_DEV_DECOMP_GZIP].base); + for (int i = 0; i < K230_DECOMP_GZIP_NUM_GPIOS_OUT; i++) { + qdev_connect_gpio_out(DEVICE(&s->decomp_gzip), i, + qdev_get_gpio_in(DEVICE(&s->gsdma), i)); + } + for (int i = 0; i < K230_DECOMP_GZIP_NUM_GPIOS_IN; i++) { + qdev_connect_gpio_out(DEVICE(&s->gsdma), i, + qdev_get_gpio_in(DEVICE(&s->decomp_gzip), i)); + } + /* unimplemented devices */ create_unimplemented_device("kpu.l2-cache", memmap[K230_DEV_KPU_L2_CACHE].base, @@ -249,10 +268,6 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("dma", memmap[K230_DEV_DMA].base, memmap[K230_DEV_DMA].size); - create_unimplemented_device("decomp-gzip", - memmap[K230_DEV_DECOMP_GZIP].base, - memmap[K230_DEV_DECOMP_GZIP].size); - create_unimplemented_device("2d-engine.non-ai", memmap[K230_DEV_NON_AI_2D].base, memmap[K230_DEV_NON_AI_2D].size); diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index 8879d56d98..8679d09891 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -20,6 +20,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/watchdog/k230_wdt.h" #include "hw/dma/k230_gsdma.h" +#include "hw/misc/k230_decomp_gzip.h" #define C908_CPU_HARTID (0) @@ -38,6 +39,7 @@ typedef struct K230SoCState { K230DDRPhyState ddr_phy; K230WdtState wdt[2]; K230GSDMAState gsdma; + K230DecompGzipState decomp_gzip; MemoryRegion sram; MemoryRegion bootrom; From 269f5458e078b186ec51edd256e1a1d220637b17 Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:26 +0800 Subject: [PATCH 491/627] tests/qtest: add test for K230 decomp gzip This commit adds test cases for Decomp_gzip. A compressed data segment has been pre-set, configure GSDMA and decomp_gzip. Compare the decompressed data with the original data Update MAINTAINERS for this test. Run this qtest: $ mkdir build && cd build && ../configure --target-list="riscv64-softmmu" $ QTEST_QEMU_BINARY=./qemu-system-riscv64 tests/qtest/k230-decomp-gzip-test Signed-off-by: Tao Ding Reviewed-by: Daniel Henrique Barboza Reviewed-by: Junze Cao Message-ID: <20260808062227.66961-7-dingtao0430@163.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 1 + tests/qtest/k230-decomp-gzip-test.c | 200 ++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 3 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/k230-decomp-gzip-test.c diff --git a/MAINTAINERS b/MAINTAINERS index ff804b3310..c2cc6ae0fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1858,6 +1858,7 @@ F: tests/functional/riscv64/test_k230.py F: tests/qtest/k230-ddr-test.c F: tests/qtest/k230-wdt-test.c F: tests/qtest/k230-gsdma-test.c +F: tests/qtest/k230-decomp-gzip-test.c RX Machines ----------- diff --git a/tests/qtest/k230-decomp-gzip-test.c b/tests/qtest/k230-decomp-gzip-test.c new file mode 100644 index 0000000000..e80113fd28 --- /dev/null +++ b/tests/qtest/k230-decomp-gzip-test.c @@ -0,0 +1,200 @@ +/* + * QTest testcase for K230 GZIP decompression engine + * + * Copyright (c) 2026 Tao Ding + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "libqtest.h" +#include "hw/dma/k230_gsdma.h" +#include "hw/misc/k230_decomp_gzip.h" + +#define K230_DECOMP_GZIP_BASE 0x80808000 +#define K230_GSDMA_BASE 0x80800000 +#define K230_SRAM_BASE 0x80200000 +#define TEST_LLT_ADDR0 0x01000000 +#define TEST_LLT_ADDR1 0x01000040 +#define TEST_SRC_ADDR 0x01100000 +#define TEST_DST_ADDR 0x01200000 + +#define TEST_PAYLOAD_LEN (sizeof(test_payload) - 1) + +static inline uint64_t gzip_reg(hwaddr off) +{ + return K230_DECOMP_GZIP_BASE + off; +} + +static inline uint64_t gsdma_reg(hwaddr off) +{ + return K230_GSDMA_BASE + off; +} + +static inline uint64_t gsdma_ch_reg(unsigned int ch, hwaddr off) +{ + return K230_GSDMA_BASE + K230_GSDMA_CH_BASE + + ch * K230_GSDMA_CH_STRIDE + off; +} + +static inline hwaddr k230_sram_addr(hwaddr off) +{ + return K230_SRAM_BASE + off; +} + +static inline hwaddr k230_sram_input_addr(unsigned int slot) +{ + return k230_sram_addr(K230_DECOMP_GZIP_SRAM_IN_BASE + + slot * K230_DECOMP_GZIP_BLOCK_SIZE); +} + +/* + * test_gzip_data was generated by compressing test_payload in gzip format + * using Dynamic Huffman coding. The compression method byte in the gzip + * header was then changed from the standard value 0x08 to the K230-specific + * value 0x09. + */ +static const uint8_t test_gzip_data[] = { + 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x05, 0xc1, 0xb1, 0x0d, 0x00, 0x20, + 0x08, 0x04, 0xc0, 0x9e, 0x29, 0x7e, 0x04, 0x23, + 0x63, 0x38, 0x85, 0x05, 0x21, 0x14, 0x10, 0x23, + 0x5f, 0x39, 0xbd, 0x77, 0x6b, 0xea, 0x80, 0xbf, + 0x38, 0x68, 0x5e, 0xdb, 0x19, 0xe5, 0xa0, 0x35, + 0x65, 0x4d, 0x1d, 0xf0, 0x17, 0x07, 0xcd, 0x6b, + 0x3b, 0xa3, 0x1c, 0xb4, 0xa6, 0xac, 0xa9, 0x03, + 0xfe, 0xe2, 0xa0, 0x79, 0x6d, 0x67, 0x94, 0x83, + 0xd6, 0x94, 0x35, 0x75, 0xc0, 0x5f, 0x1c, 0x34, + 0xaf, 0xed, 0x8c, 0x72, 0xd0, 0x9a, 0xb2, 0xa6, + 0x0e, 0xf8, 0x8b, 0x83, 0xe6, 0xb5, 0x9d, 0x51, + 0x0e, 0x5a, 0x53, 0xd6, 0xd4, 0x01, 0x7f, 0x71, + 0xd0, 0xbc, 0xb6, 0x33, 0xca, 0x41, 0x6b, 0xca, + 0x9a, 0x3a, 0xe0, 0x2f, 0x0e, 0x9a, 0xd7, 0x76, + 0x46, 0x39, 0x68, 0x4d, 0x59, 0x53, 0x07, 0xfc, + 0xc5, 0x41, 0xf3, 0xda, 0xce, 0x28, 0x07, 0xad, + 0x29, 0x1f, 0xdb, 0x9d, 0xbc, 0xdd, 0xc8, 0x00, + 0x00, 0x00, +}; + +static const uint8_t test_payload[] = + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n" + "K230 gzip streaming test\n"; + +static void write_sdma_llt_node(QTestState *qts, hwaddr addr, uint32_t src, + uint32_t dst, uint32_t len, uint32_t next) +{ + qtest_writel(qts, addr + offsetof(K230GSDMALLT, cfg), 0); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, src_addr), src); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_size), len); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_cfg), 0x1); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, dst_addr), dst); + qtest_writel(qts, addr + offsetof(K230GSDMALLT, next_llt_addr), next); +} + +static void test_reset_and_rw(void) +{ + QTestState *qts = qtest_init("-machine k230"); + + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_DECOMP_START)), + ==, 0); + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_SRC_SIZE)), + ==, 0); + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_OUT_SIZE)), + ==, 0); + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_DECOMP_STAT)), + ==, 0); + + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_DECOMP_START), + K230_DECOMP_GZIP_START); + + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_SRC_SIZE), 0xffffffff); + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_SRC_SIZE)), + ==, 0xffffffff); + + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_OUT_SIZE), 0x12345678); + g_assert_cmphex(qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_OUT_SIZE)), + ==, 0x12345678); + + qtest_quit(qts); +} + +static void test_gsdma_handshake_flow(void) +{ + QTestState *qts = qtest_init("-machine k230"); + uint32_t stat; + uint8_t output[TEST_PAYLOAD_LEN]; + + qtest_memwrite(qts, TEST_SRC_ADDR, test_gzip_data, sizeof(test_gzip_data)); + write_sdma_llt_node(qts, TEST_LLT_ADDR0, TEST_SRC_ADDR, + k230_sram_input_addr(0), + sizeof(test_gzip_data), 0); + write_sdma_llt_node(qts, TEST_LLT_ADDR1, + k230_sram_addr(K230_DECOMP_GZIP_SRAM_OUT_BASE), + TEST_DST_ADDR, TEST_PAYLOAD_LEN, 0); + + qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), BIT(0) | BIT(1)); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CFG), + K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN); + qtest_writel(qts, gsdma_ch_reg(1, K230_GSDMA_CH_CFG), 0); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR), TEST_LLT_ADDR0); + qtest_writel(qts, gsdma_ch_reg(1, K230_GSDMA_CH_LLT_SADDR), TEST_LLT_ADDR1); + qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), K230_GSDMA_CTL_START); + qtest_writel(qts, gsdma_ch_reg(1, K230_GSDMA_CH_CTL), K230_GSDMA_CTL_START); + + g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN)), + ==, BIT(0) | BIT(1)); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CFG)) & + K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN, + ==, K230_GSDMA_CH0_CFG_DECOMP_CTRL_EN); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR)), + ==, TEST_LLT_ADDR0); + g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(1, K230_GSDMA_CH_LLT_SADDR)), + ==, TEST_LLT_ADDR1); + + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_SRC_SIZE), + K230_DECOMP_GZIP_CTRL_EN | sizeof(test_gzip_data)); + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_GZIP_OUT_SIZE), + TEST_PAYLOAD_LEN); + qtest_writel(qts, gzip_reg(K230_DECOMP_GZIP_DECOMP_START), + K230_DECOMP_GZIP_START); + + stat = qtest_readl(qts, gzip_reg(K230_DECOMP_GZIP_DECOMP_STAT)); + g_assert_cmphex(stat & K230_DECOMP_GZIP_STAT_CRC_OK, ==, + K230_DECOMP_GZIP_STAT_CRC_OK); + + g_assert_cmphex(qtest_readl(qts, + gsdma_ch_reg(0, K230_GSDMA_CH_CURRENT_LLT)), + ==, TEST_LLT_ADDR0); + g_assert_cmphex(qtest_readl(qts, + gsdma_ch_reg(1, K230_GSDMA_CH_CURRENT_LLT)), + ==, TEST_LLT_ADDR1); + + stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT)); + g_assert_cmphex(stat & K230_GSDMA_SDMA_DONE_INT(0), ==, + K230_GSDMA_SDMA_DONE_INT(0)); + g_assert_cmphex(stat & K230_GSDMA_SDMA_DONE_INT(1), ==, + K230_GSDMA_SDMA_DONE_INT(1)); + + qtest_memread(qts, TEST_DST_ADDR, output, sizeof(output)); + g_assert_cmpmem(output, sizeof(output), test_payload, TEST_PAYLOAD_LEN); + + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/k230-decomp-gzip/reset-and-rw", test_reset_and_rw); + qtest_add_func("/k230-decomp-gzip/gsdma-handshake-flow", + test_gsdma_handshake_flow); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 84756ba823..739df71d8d 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -300,7 +300,7 @@ qtests_riscv64 = ['riscv-csr-test'] + \ config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \ (config_all_devices.has_key('CONFIG_K230') ? - ['k230-ddr-test', 'k230-wdt-test', 'k230-gsdma-test'] : []) + ['k230-ddr-test', 'k230-wdt-test', 'k230-gsdma-test', 'k230-decomp-gzip-test'] : []) qtests_hexagon = ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test'] From b92d8c60a4cdab8562c132e6256faa930a651c76 Mon Sep 17 00:00:00 2001 From: Tao Ding Date: Sat, 8 Aug 2026 14:22:27 +0800 Subject: [PATCH 492/627] hw/riscv: k230: add a noc stub region in K230 board The NOC address was accessed in the k230_unzip driver, but it is currently not in k230. This commit uses create_unimplemented_device to preset the region. Signed-off-by: Tao Ding Reviewed-by: Junze Cao Reviewed-by: Daniel Henrique Barboza Message-ID: <20260808062227.66961-8-dingtao0430@163.com> Signed-off-by: Alistair Francis --- hw/riscv/k230.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 5163eaa7ef..558f30b97e 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -250,6 +250,9 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->decomp_gzip), i)); } + /* Noc stub, the k230 decomp_gzip driver in uboot will access this region */ + create_unimplemented_device("noc-stub", 0x91302000, 0x1000); + /* unimplemented devices */ create_unimplemented_device("kpu.l2-cache", memmap[K230_DEV_KPU_L2_CACHE].base, From 7df9aa5f6d600584c556776505253e849b3902ee Mon Sep 17 00:00:00 2001 From: Xie Bo Date: Sat, 8 Aug 2026 20:51:56 +0800 Subject: [PATCH 493/627] target/riscv/kvm: Synchronize privilege mode The KVM core register synchronization currently omits the vCPU privilege mode. As a result, env.priv can be stale when the migration stream is saved and the destination can restore the vCPU in the wrong mode. Read and write the KVM core mode register together with the other core registers. The generic RISC-V CPU VMState already carries env.priv, so no migration format change is required. Signed-off-by: Xie Bo Reviewed-by: Daniel Henrique Barboza Message-ID: <20260808125157.1220511-2-xb@ultrarisc.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 97069bf597..f6ddd0db9b 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -603,6 +603,12 @@ static int kvm_riscv_get_regs_core(CPUState *cs) } env->pc = reg; + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(mode), ®); + if (ret) { + return ret; + } + env->priv = reg; + for (i = 1; i < 32; i++) { uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); ret = kvm_get_one_reg(cs, id, ®); @@ -628,6 +634,12 @@ static int kvm_riscv_put_regs_core(CPUState *cs) return ret; } + reg = env->priv; + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(mode), ®); + if (ret) { + return ret; + } + for (i = 1; i < 32; i++) { uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); reg = env->gpr[i]; From ddac7cfb00ad771f6ef3450fff2d09e749fdbaf9 Mon Sep 17 00:00:00 2001 From: Xie Bo Date: Sat, 8 Aug 2026 20:51:57 +0800 Subject: [PATCH 494/627] target/riscv/kvm: Preserve MP state across migration RISC-V KVM initializes secondary vCPUs in KVM_MP_STATE_STOPPED, but QEMU does not save their runtime MP state. A destination therefore retains reset MP state after migration and cannot reliably resume all vCPUs. Save KVM_GET_MP_STATE in a capability-gated KVM VMState subsection and restore it on KVM_PUT_FULL_STATE. Keep the existing reset initialization path unchanged. Track whether the subsection was loaded so streams where the subsection is absent retain the destination reset behavior. Bump the RISC-V CPU VMState version and minimum version to 12 for the new pre_load hook and KVM MP-state subsection. Keep the subsection out of KVM migration streams when the host does not support the MP-state capability. Signed-off-by: Xie Bo Reviewed-by: Daniel Henrique Barboza Message-ID: <20260808125157.1220511-3-xb@ultrarisc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 4 +++ target/riscv/kvm/kvm-cpu.c | 50 ++++++++++++++++++++++++------------ target/riscv/kvm/kvm_riscv.h | 2 +- target/riscv/machine.c | 49 +++++++++++++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 376cff656f..718b66487a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -538,6 +538,10 @@ struct CPUArchState { uint64_t kvm_timer_compare; uint64_t kvm_timer_state; uint64_t kvm_timer_frequency; + + /* KVM multiprocessor state */ + uint32_t kvm_mp_state; + bool kvm_mp_state_loaded; #endif /* CONFIG_KVM */ }; diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index f6ddd0db9b..68e1501b21 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1374,25 +1374,35 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp) return ret; } + if (cap_has_mp_state) { + struct kvm_mp_state mp_state; + + ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); + if (ret) { + return ret; + } + RISCV_CPU(cs)->env.kvm_mp_state = mp_state.mp_state; + } + return ret; } -int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) +bool kvm_riscv_has_mp_state(void) { - if (cap_has_mp_state) { - struct kvm_mp_state mp_state = { - .mp_state = state - }; + return cap_has_mp_state; +} - int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); - if (ret) { - fprintf(stderr, "%s: failed to sync MP_STATE %d/%s\n", - __func__, ret, strerror(-ret)); - return -1; - } +static int kvm_riscv_put_mp_state(CPUState *cs) +{ + struct kvm_mp_state mp_state = { + .mp_state = RISCV_CPU(cs)->env.kvm_mp_state, + }; + + if (!cap_has_mp_state) { + return 0; } - return 0; + return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); } int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) @@ -1431,10 +1441,18 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) } if (KVM_PUT_RESET_STATE == level) { - RISCVCPU *cpu = RISCV_CPU(cs); - int state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE - : KVM_MP_STATE_STOPPED; - ret = kvm_riscv_sync_mpstate_to_kvm(cpu, state); + CPURISCVState *env = &RISCV_CPU(cs)->env; + + env->kvm_mp_state = cs->cpu_index == 0 ? KVM_MP_STATE_RUNNABLE + : KVM_MP_STATE_STOPPED; + env->kvm_mp_state_loaded = false; + ret = kvm_riscv_put_mp_state(cs); + if (ret) { + return ret; + } + } else if (KVM_PUT_FULL_STATE == level && + RISCV_CPU(cs)->env.kvm_mp_state_loaded) { + ret = kvm_riscv_put_mp_state(cs); if (ret) { return ret; } diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h index b2bcd1041f..61eaa12443 100644 --- a/target/riscv/kvm/kvm_riscv.h +++ b/target/riscv/kvm/kvm_riscv.h @@ -28,7 +28,7 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, uint64_t aplic_base, uint64_t imsic_base, uint64_t guest_num); void riscv_kvm_aplic_request(void *opaque, int irq, int level); -int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state); +bool kvm_riscv_has_mp_state(void); void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp); uint64_t kvm_riscv_get_timebase_frequency(RISCVCPU *cpu); diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 0ab613a298..31c49ca3e6 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -25,6 +25,9 @@ #include "exec/icount.h" #include "target/riscv/tcg/debug.h" #include "hw/riscv/machines-qom.h" +#ifdef CONFIG_KVM +#include "kvm/kvm_riscv.h" +#endif static bool pmp_needed(void *opaque) { @@ -222,6 +225,44 @@ static const VMStateDescription vmstate_kvmtimer = { VMSTATE_END_OF_LIST() } }; + +static int riscv_cpu_kvm_pre_load(void *opaque) +{ + RISCVCPU *cpu = opaque; + + cpu->env.kvm_mp_state_loaded = false; + return 0; +} + +static bool kvm_mp_state_needed(void *opaque) +{ + return kvm_enabled() && kvm_riscv_has_mp_state(); +} + +static int kvm_mp_state_post_load(void *opaque, int version_id) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + if (!kvm_enabled() || !kvm_riscv_has_mp_state()) { + return -ENOTSUP; + } + + env->kvm_mp_state_loaded = true; + return 0; +} + +static const VMStateDescription vmstate_kvm_mp_state = { + .name = "cpu/kvm-mp-state", + .version_id = 1, + .minimum_version_id = 1, + .needed = kvm_mp_state_needed, + .post_load = kvm_mp_state_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(env.kvm_mp_state, RISCVCPU), + VMSTATE_END_OF_LIST() + } +}; #endif static bool debug_needed(void *opaque) @@ -457,8 +498,11 @@ static const VMStateDescription vmstate_mseccfg = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 11, - .minimum_version_id = 11, + .version_id = 12, + .minimum_version_id = 12, +#ifdef CONFIG_KVM + .pre_load = riscv_cpu_kvm_pre_load, +#endif .post_load = riscv_cpu_post_load, .fields = (const VMStateField[]) { VMSTATE_UINT64_ARRAY(env.gpr, RISCVCPU, 32), @@ -522,6 +566,7 @@ const VMStateDescription vmstate_riscv_cpu = { &vmstate_rv128, #ifdef CONFIG_KVM &vmstate_kvmtimer, + &vmstate_kvm_mp_state, #endif &vmstate_envcfg, &vmstate_debug, From 4a884ba94b43f5b2a640f4ea882655503f9ae954 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Thu, 30 Jul 2026 21:18:52 +0300 Subject: [PATCH 495/627] target/riscv: Fix PC sync in trans_sspopchk for CFI exception handling Move gen_update_pc call before conditional logic to ensure consistent PC state regardless of execution path. Previously, the host instructions generated to update the cpu_pc were only executed in the failure path when shadow stack validation failed. This created inconsistent PC synchronization. This inconsistency caused issues in CF_PCREL mode where subsequent instructions calculated wrong relative offsets from stale pc_save values, and could lead to incorrect exception return addresses. This fix ensures PC is always synchronized before any helper that might raise an exception, maintaining consistent translator state across all execution paths. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4118 Signed-off-by: Max Chou [ahshehab: rebased on current master; file moved to target/riscv/tcg/insn_trans/ and the ssp load is now 64-bit wide] Tested-by: A-Shehab Signed-off-by: A-Shehab Reviewed-by: Daniel Henrique Barboza Message-ID: <20260730181852.1622-1-ahshehab24@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvzicfiss.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/tcg/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/tcg/insn_trans/trans_rvzicfiss.c.inc index a813232887..d47a9f9c7d 100644 --- a/target/riscv/tcg/insn_trans/trans_rvzicfiss.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvzicfiss.c.inc @@ -32,6 +32,7 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a) TCGLabel *skip = gen_new_label(); uint32_t tmp = (get_xl(ctx) == MXL_RV64) ? 8 : 4; TCGv data = tcg_temp_new(); + gen_update_pc(ctx, 0); TCGv_i64 wide_addr = tcg_temp_new_i64(); tcg_gen_ld_i64(wide_addr, tcg_env, offsetof(CPURISCVState, ssp)); tcg_gen_trunc_i64_tl(addr, wide_addr); @@ -42,7 +43,6 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a) tcg_gen_brcond_tl(TCG_COND_EQ, data, rs1, skip); tcg_gen_st8_i32(tcg_constant_i32(RISCV_EXCP_SW_CHECK_BCFI_TVAL), tcg_env, offsetof(CPURISCVState, sw_check_code)); - gen_update_pc(ctx, 0); gen_helper_raise_exception(tcg_env, tcg_constant_i32(RISCV_EXCP_SW_CHECK)); gen_set_label(skip); From ebef6685a1a29b0b106b6ff3931ffc22c489e0ae Mon Sep 17 00:00:00 2001 From: Abhigyan Kumar <314abh@gmail.com> Date: Thu, 23 Jul 2026 19:52:54 +0530 Subject: [PATCH 496/627] target/riscv: use SXL instead of MXL for read_sstatus According to the RISC-V spec, a 64-bit system can have M-mode in 64-bit with S-mode being 32-bit (SXL bits or mstatus[35:34] being 1). In this case, read_sstatus should use SXL. QEMU doesn't allow changing the SXL bits in mstatus in M-mode. This was because of the missing MSTATUS64_SXL mask in write_mstatus. Now, both the SXL field in mstatus can be safely modified in M-mode and read_sstatus correctly uses SXL not MXL. Fixes: b550f89457 ("target/riscv: Compute mstatus.sd on demand") Signed-off-by: Abhigyan Kumar <314abh@gmail.com> Reviewed-by: Daniel Henrique Barboza Message-ID: <20260723142254.1683113-1-314abh@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/csr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 36f2004bc5..a90449b87f 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -2067,6 +2067,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, } if (xl != MXL_RV32 || env->debugger) { + if ((val & MSTATUS64_SXL) != 0) { + mask |= MSTATUS64_SXL; + val = riscv_write_uxl(env, val, MSTATUS64_SXL); + } + if ((val & MSTATUS64_UXL) != 0) { mask |= MSTATUS64_UXL; val = riscv_write_uxl(env, val, MSTATUS64_UXL); @@ -4014,8 +4019,8 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, if (riscv_cpu_cfg(env)->ext_ssdbltrp) { mask |= SSTATUS_SDT; } - /* TODO: Use SXL not MXL. */ - *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask); + + *val = add_status_sd(riscv_cpu_sxl(env), env->mstatus & mask); return RISCV_EXCP_NONE; } From d5ab0bdefe418593a744fd0c625add607117c972 Mon Sep 17 00:00:00 2001 From: Zeng Chi Date: Fri, 24 Jul 2026 14:39:27 +0800 Subject: [PATCH 497/627] target/riscv: Fix memory leak in riscv_trigger_unrealize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In riscv_trigger_unrealize(), the per-trigger QEMUTimer objects are created in riscv_trigger_realize() using timer_new_ns(). However, unrealize only calls timer_del() to cancel them, but never frees the timer objects themselves. This results in a memory leak every time a CPU instance is unrealized (e.g., during hot-unplug or machine teardown). Fix it by replacing timer_del() with timer_free(), which internally cancels the timer and frees its memory. The separate timer_del() call is no longer needed. Fixes: 820552a92e32 ("target/riscv: dynamic alloc of debug trigger arrays") Signed-off-by: Zeng Chi Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20260724063927.3360599-1-zeng_chi911@163.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/tcg/debug.c b/target/riscv/tcg/debug.c index 3c0fe70101..5ab29f6945 100644 --- a/target/riscv/tcg/debug.c +++ b/target/riscv/tcg/debug.c @@ -1080,7 +1080,7 @@ void riscv_trigger_unrealize(CPURISCVState *env) g_free(env->cpu_watchpoint); for (int i = 0; i < env->num_triggers; i++) { - timer_del(env->itrigger_timer[i]); + timer_free(env->itrigger_timer[i]); } g_free(env->itrigger_timer); } From fbc151a66ff16153a96af8a836cd64015277972c Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:12 +0800 Subject: [PATCH 498/627] target/riscv: Add Zicclsm CPU option and enable it for the eligible CPUs Add Zicclsm CPU option and enable it for the following eligible CPUs: - Base 32 CPU (to be backward compatible) - Base 64 CPU (to be backward compatible) - XuanTie (T-Head) C908 - Tenstorrent Ascalon - Ventana Veyron V1 - XiangShan Kunminghu - MIPS P8700 (ISA doesn't include Zicclsm, but their datasheet claims that it has unaligned load/store support in hardware) Signed-off-by: Frank Chang Reviewed-by: Max Chou Acked-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20260810055618.1175500-2-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 7 +++++++ target/riscv/cpu_cfg_fields.h.inc | 2 ++ 2 files changed, 9 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e73ff53159..b2693f4c20 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -3347,6 +3347,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zicbom = true, .cfg.ext_zicbop = true, .cfg.ext_zicboz = true, + .cfg.ext_zicclsm = true, .cfg.ext_zicntr = true, .cfg.ext_zicsr = true, .cfg.ext_zifencei = true, @@ -3419,6 +3420,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zicbom = true, .cfg.ext_zicbop = true, .cfg.ext_zicboz = true, + .cfg.ext_zicclsm = true, .cfg.ext_zicntr = true, .cfg.ext_zicsr = true, .cfg.ext_zifencei = true, @@ -3505,6 +3507,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zbs = true, .cfg.ext_zkt = true, .cfg.ext_zbkc = true, + .cfg.ext_zicclsm = true, .cfg.ext_zicsr = true, .cfg.ext_zifencei = true, .cfg.ext_zihintpause = true, @@ -3548,6 +3551,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.ext_zicbom = true, .cfg.ext_zicbop = true, .cfg.ext_zicboz = true, + .cfg.ext_zicclsm = true, .cfg.ext_zicntr = true, .cfg.ext_zicond = true, .cfg.ext_zicsr = true, @@ -3597,6 +3601,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { /* ISA extensions */ .cfg.mmu = true, + .cfg.ext_zicclsm = true, .cfg.ext_zifencei = true, .cfg.ext_zicsr = true, .cfg.pmp = true, @@ -3656,6 +3661,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { * The RISC-V Instruction Set Manual: Volume I * Unprivileged Architecture */ + .cfg.ext_zicclsm = true, .cfg.ext_zicntr = true, .cfg.ext_zihpm = true, .cfg.ext_zihintntl = true, @@ -3712,6 +3718,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU, .priv_spec = PRIV_VERSION_1_12_0, .cfg.max_satp_mode = VM_1_10_SV48, + .cfg.ext_zicclsm = true, .cfg.ext_zifencei = true, .cfg.ext_zicsr = true, .cfg.mmu = true, diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index 9eb47af0a7..f8c27a574f 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -139,6 +139,8 @@ BOOL_FIELD(has_priv_1_11) /* Always enabled for TCG if has_priv_1_11 */ BOOL_FIELD(ext_ziccrse) +BOOL_FIELD(ext_zicclsm) + /* Vendor-specific custom extensions */ BOOL_FIELD(ext_xtheadba) BOOL_FIELD(ext_xtheadbb) From 340a8c111dbf1f8f5524c6cbe959dad9b9af56b1 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:13 +0800 Subject: [PATCH 499/627] hw/riscv: sifive_u: Align ROM reset vector data The SiFive U ROM reset vector data needs proper 8-byte alignment for RV64 ld instructions. The misaligned load will cause exception when Zicclsm is supported as SiFive U CPU doesn't support hardware misaligned loads and stores. Add padding to ensure start_addr and fdt_load_addr are placed at 8-byte aligned offsets and adjust the load instruction offsets to match the new data layout. Signed-off-by: Frank Chang Reviewed-by: Daniel Henrique Barboza Message-ID: <20260810055618.1175500-3-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- hw/riscv/sifive_u.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 99423ef472..57a57c96e1 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -564,19 +564,20 @@ static void sifive_u_machine_init(MachineState *machine) 0, 0, 0x00028067, /* jr t0 */ + 0x00000000, /* padding for alignment */ start_addr, /* start: .dword */ start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ fdt_load_addr_hi32, - 0x00000000, /* fw_dyn: */ }; + if (riscv_is_32bit(&s->soc.u_cpus)) { - reset_vec[4] = 0x0202a583; /* lw a1, 32(t0) */ - reset_vec[5] = 0x0182a283; /* lw t0, 24(t0) */ + reset_vec[4] = 0x0242a583; /* lw a1, 36(t0) */ + reset_vec[5] = 0x01c2a283; /* lw t0, 28(t0) */ } else { - reset_vec[4] = 0x0202b583; /* ld a1, 32(t0) */ - reset_vec[5] = 0x0182b283; /* ld t0, 24(t0) */ + reset_vec[4] = 0x0242b583; /* ld a1, 36(t0) */ + reset_vec[5] = 0x01c2b283; /* ld t0, 28(t0) */ } From 7ff17f127bbf08bb17d2754d43028bab79a1c709 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:14 +0800 Subject: [PATCH 500/627] target/riscv: Support raising misaligned exceptions for scalar loads/stores When the Zicclsm extension is not enabled, raise misaligned load/store exceptions for misaligned accesses from scalar load/store instructions. Signed-off-by: Frank Chang Reviewed-by: Max Chou Reviewed-by: Alistair Francis Message-ID: <20260810055618.1175500-4-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvi.c.inc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/riscv/tcg/insn_trans/trans_rvi.c.inc b/target/riscv/tcg/insn_trans/trans_rvi.c.inc index e47b16a7fa..cc1b5dbbad 100644 --- a/target/riscv/tcg/insn_trans/trans_rvi.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvi.c.inc @@ -413,6 +413,9 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); if (get_xl(ctx) == MXL_RV128) { out = gen_load_i128(ctx, a, memop); @@ -524,6 +527,9 @@ static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); if (get_xl(ctx) == MXL_RV128) { return gen_store_i128(ctx, a, memop); From e1322e1558ac9b2547baa2eb9b5b924220e89910 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:15 +0800 Subject: [PATCH 501/627] target/riscv: Support raising misaligned exceptions for floating-point loads/stores When the Zicclsm extension is not enabled, raise misaligned load/store exceptions for misaligned accesses from floating-point load/store instructions (RVF, RVD, Zfh). Signed-off-by: Frank Chang Reviewed-by: Daniel Henrique Barboza Message-ID: <20260810055618.1175500-5-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvd.c.inc | 6 ++++++ target/riscv/tcg/insn_trans/trans_rvf.c.inc | 6 ++++++ target/riscv/tcg/insn_trans/trans_rvzfh.c.inc | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/target/riscv/tcg/insn_trans/trans_rvd.c.inc b/target/riscv/tcg/insn_trans/trans_rvd.c.inc index 3b9a745520..1be2bee946 100644 --- a/target/riscv/tcg/insn_trans/trans_rvd.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvd.c.inc @@ -61,6 +61,9 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a) memop |= MO_ATOM_IFALIGN; } memop |= ctx->mo_endianness; + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); addr = get_address(ctx, a->rs1, a->imm); @@ -86,6 +89,9 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a) memop |= MO_ATOM_IFALIGN; } memop |= ctx->mo_endianness; + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); addr = get_address(ctx, a->rs1, a->imm); diff --git a/target/riscv/tcg/insn_trans/trans_rvf.c.inc b/target/riscv/tcg/insn_trans/trans_rvf.c.inc index e935523c93..481f7282da 100644 --- a/target/riscv/tcg/insn_trans/trans_rvf.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvf.c.inc @@ -52,6 +52,9 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); addr = get_address(ctx, a->rs1, a->imm); @@ -75,6 +78,9 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a) if (ctx->cfg_ptr->ext_zama16b) { memop |= MO_ATOM_WITHIN16; } + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); addr = get_address(ctx, a->rs1, a->imm); diff --git a/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc b/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc index f36b46c211..88711fb076 100644 --- a/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc @@ -50,6 +50,9 @@ static bool trans_flh(DisasContext *ctx, arg_flh *a) REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx); memop |= ctx->mo_endianness; + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); t0 = get_gpr(ctx, a->rs1, EXT_NONE); if (a->imm) { @@ -75,6 +78,9 @@ static bool trans_fsh(DisasContext *ctx, arg_fsh *a) REQUIRE_ZFHMIN_OR_ZFBFMIN(ctx); memop |= ctx->mo_endianness; + if (!ctx->cfg_ptr->ext_zicclsm) { + memop |= MO_ALIGN; + } decode_save_opc(ctx, 0); t0 = get_gpr(ctx, a->rs1, EXT_NONE); if (a->imm) { From 460549ba1088ee9ac5f69c0f5c42c96ebb4d1355 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:16 +0800 Subject: [PATCH 502/627] target/riscv: Support raising misaligned exceptions for vector loads/stores When the Zicclsm extension is not enabled, raise misaligned load/store exceptions for misaligned accesses from vector load/store instructions. We will skip the host fast-path and fall back to the slow TLB-path to raise misaligned load/store exceptions for the misaligned accesses when Zicclsm extension is disabled. Signed-off-by: Frank Chang Reviewed-by: Max Chou Acked-by: Alistair Francis Message-ID: <20260810055618.1175500-6-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvv.c.inc | 18 +++++- target/riscv/tcg/vector_helper.c | 65 ++++++++++++++++----- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/target/riscv/tcg/insn_trans/trans_rvv.c.inc b/target/riscv/tcg/insn_trans/trans_rvv.c.inc index 23262b1d03..a22e2cae6c 100644 --- a/target/riscv/tcg/insn_trans/trans_rvv.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvv.c.inc @@ -1191,26 +1191,38 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, * Use the helper function if either: * - vstart is not 0. */ - bool use_helper_fn = !s->vstart_eq_zero; if (!use_helper_fn) { uint32_t size = s->cfg_ptr->vlenb * nf; TCGv_i64 t8 = tcg_temp_new_i64(); MemOp atomicity = MO_ATOM_NONE; + MemOp alignment = MO_UNALN; + + /* + * If Zicclsm is disabled, require alignment based on element size. + * Use MO_ALIGN_* based on log2_esz (0 = MO_UNALN, 1 = MO_ALIGN_2, etc). + */ + if (!s->cfg_ptr->ext_zicclsm) { + alignment = log2_esz << MO_ASHIFT; + } + if (log2_esz == 0) { atomicity = MO_ATOM_NONE; } else { atomicity = MO_ATOM_IFALIGN_PAIR; } + for (int i = 0; i < size; i += 8) { TCGv addr = get_address(s, rs1, i); if (is_load) { - tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx, MO_LEUQ | atomicity); + tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx, + MO_LEUQ | atomicity | alignment); tcg_gen_st_i64(t8, tcg_env, vreg_ofs(s, vd) + i); } else { tcg_gen_ld_i64(t8, tcg_env, vreg_ofs(s, vd) + i); - tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, MO_LEUQ | atomicity); + tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, + MO_LEUQ | atomicity | alignment); } if (i == size - 8) { tcg_gen_movi_i32(cpu_vstart, 0); diff --git a/target/riscv/tcg/vector_helper.c b/target/riscv/tcg/vector_helper.c index e321ca2616..e28d8a3d9f 100644 --- a/target/riscv/tcg/vector_helper.c +++ b/target/riscv/tcg/vector_helper.c @@ -199,20 +199,34 @@ static inline void vext_set_elem_mask(void *v0, int index, ((uint64_t *)v0)[idx] = deposit64(old, pos, 1, value); } +static inline MemOpIdx vext_make_memop_idx(CPURISCVState *env, size_t size) +{ + int mmu_idx = riscv_env_mmu_index(env, false); + MemOp memop = size_memop(size) | mo_endian_env(env); + + if (!riscv_cpu_cfg(env)->ext_zicclsm) { + memop |= MO_ALIGN; + } + + return make_memop_idx(memop, mmu_idx); +} + /* elements operations for load and store */ typedef void vext_ldst_elem_fn_tlb(CPURISCVState *env, abi_ptr addr, uint32_t idx, void *vd, uintptr_t retaddr); typedef void vext_ldst_elem_fn_host(void *vd, uint32_t idx, void *host); -#define GEN_VEXT_LD_ELEM(NAME, ETYPE, H, LDSUF) \ +#define GEN_VEXT_TLB_LD_ELEM(NAME, ETYPE, H, LDSUF) \ static inline QEMU_ALWAYS_INLINE \ void NAME##_tlb(CPURISCVState *env, abi_ptr addr, \ uint32_t idx, void *vd, uintptr_t retaddr) \ { \ ETYPE *cur = ((ETYPE *)vd + H(idx)); \ - *cur = cpu_##LDSUF##_data_ra(env, addr, retaddr); \ + MemOpIdx oi = vext_make_memop_idx(env, sizeof(ETYPE)); \ + *cur = cpu_##LDSUF##_mmu(env, addr, oi, retaddr); \ } \ - \ + +#define GEN_VEXT_HOST_LD_ELEM(NAME, ETYPE, H, LDSUF) \ static inline QEMU_ALWAYS_INLINE \ void NAME##_host(void *vd, uint32_t idx, void *host) \ { \ @@ -220,20 +234,27 @@ void NAME##_host(void *vd, uint32_t idx, void *host) \ *cur = (ETYPE)LDSUF##_p(host); \ } -GEN_VEXT_LD_ELEM(lde_b, uint8_t, H1, ldub) -GEN_VEXT_LD_ELEM(lde_h, uint16_t, H2, lduw_le) -GEN_VEXT_LD_ELEM(lde_w, uint32_t, H4, ldl_le) -GEN_VEXT_LD_ELEM(lde_d, uint64_t, H8, ldq_le) +GEN_VEXT_TLB_LD_ELEM(lde_b, uint8_t, H1, ldb) +GEN_VEXT_TLB_LD_ELEM(lde_h, uint16_t, H2, ldw) +GEN_VEXT_TLB_LD_ELEM(lde_w, uint32_t, H4, ldl) +GEN_VEXT_TLB_LD_ELEM(lde_d, uint64_t, H8, ldq) -#define GEN_VEXT_ST_ELEM(NAME, ETYPE, H, STSUF) \ +GEN_VEXT_HOST_LD_ELEM(lde_b, uint8_t, H1, ldub) +GEN_VEXT_HOST_LD_ELEM(lde_h, uint16_t, H2, lduw_le) +GEN_VEXT_HOST_LD_ELEM(lde_w, uint32_t, H4, ldl_le) +GEN_VEXT_HOST_LD_ELEM(lde_d, uint64_t, H8, ldq_le) + +#define GEN_VEXT_TLB_ST_ELEM(NAME, ETYPE, H, STSUF) \ static inline QEMU_ALWAYS_INLINE \ void NAME##_tlb(CPURISCVState *env, abi_ptr addr, \ uint32_t idx, void *vd, uintptr_t retaddr) \ { \ ETYPE data = *((ETYPE *)vd + H(idx)); \ - cpu_##STSUF##_data_ra(env, addr, data, retaddr); \ + MemOpIdx oi = vext_make_memop_idx(env, sizeof(ETYPE)); \ + cpu_##STSUF##_mmu(env, addr, data, oi, retaddr); \ } \ - \ + +#define GEN_VEXT_HOST_ST_ELEM(NAME, ETYPE, H, STSUF) \ static inline QEMU_ALWAYS_INLINE \ void NAME##_host(void *vd, uint32_t idx, void *host) \ { \ @@ -241,10 +262,15 @@ void NAME##_host(void *vd, uint32_t idx, void *host) \ STSUF##_p(host, data); \ } -GEN_VEXT_ST_ELEM(ste_b, uint8_t, H1, stb) -GEN_VEXT_ST_ELEM(ste_h, uint16_t, H2, stw_le) -GEN_VEXT_ST_ELEM(ste_w, uint32_t, H4, stl_le) -GEN_VEXT_ST_ELEM(ste_d, uint64_t, H8, stq_le) +GEN_VEXT_TLB_ST_ELEM(ste_b, uint8_t, H1, stb) +GEN_VEXT_TLB_ST_ELEM(ste_h, uint16_t, H2, stw) +GEN_VEXT_TLB_ST_ELEM(ste_w, uint32_t, H4, stl) +GEN_VEXT_TLB_ST_ELEM(ste_d, uint64_t, H8, stq) + +GEN_VEXT_HOST_ST_ELEM(ste_b, uint8_t, H1, stb) +GEN_VEXT_HOST_ST_ELEM(ste_h, uint16_t, H2, stw_le) +GEN_VEXT_HOST_ST_ELEM(ste_w, uint32_t, H4, stl_le) +GEN_VEXT_HOST_ST_ELEM(ste_d, uint64_t, H8, stq_le) static inline QEMU_ALWAYS_INLINE void vext_continuous_ldst_tlb(CPURISCVState *env, vext_ldst_elem_fn_tlb *ldst_tlb, @@ -398,7 +424,16 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr, probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags, true); - if (flags == 0) { + bool misaligned = addr & (esz - 1); + + /* + * Allow the host fast-pash when: + * 1. Page permission/pmp/watchpoint are checked and we have a contigous + * host mapping. + * 2. Zicclsm is enabled or load/store is not a misaligned access. + * Otherwise, we will fall back to the slow TLB-path. + */ + if (flags == 0 && (riscv_cpu_cfg(env)->ext_zicclsm || !misaligned)) { if (nf == 1) { vext_continuous_ldst_host(env, ldst_host, vd, evl, env->vstart, host, esz, is_load); From 836ffe9cfa51104a5df2802f3809cea74defd522 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:17 +0800 Subject: [PATCH 503/627] target/riscv: Expose Zicclsm as a CPU property and update RVA22U64 profile Update Zicclsm ISA string and expose it as a CPU property to allow user to turn on/off Zicclsm extension. In addition, Zicclsm extension is mandatory for the RVA22U64 profile. Previously, Zicclsm was enabled automatically when has_priv_1_11 was true. Now that Zicclsm has been converted to an explicit CPU option, it must be explicitly added to the RVA22U64 profile's extension list to ensure the profile remains compliant with the specification. Signed-off-by: Frank Chang Reviewed-by: Daniel Henrique Barboza Message-ID: <20260810055618.1175500-7-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b2693f4c20..d8f239e41d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -165,7 +165,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_zicboz), ISA_INTERNAL_EXT_DATA_ENTRY(ziccamoa, PRIV_VERSION_1_11_0, has_priv_1_11), ISA_INTERNAL_EXT_DATA_ENTRY(ziccif, PRIV_VERSION_1_11_0, has_priv_1_11), - ISA_INTERNAL_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, has_priv_1_11), + ISA_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, ext_zicclsm), ISA_EXT_DATA_ENTRY(ziccrse, PRIV_VERSION_1_11_0, ext_ziccrse), ISA_EXT_DATA_ENTRY(zicfilp, PRIV_VERSION_1_12_0, ext_zicfilp), ISA_EXT_DATA_ENTRY(zicfiss, PRIV_VERSION_1_13_0, ext_zicfiss), @@ -2316,6 +2316,7 @@ static RISCVCPUProfile RVA22U64 = { CPU_CFG_OFFSET(ext_zkt), CPU_CFG_OFFSET(ext_zicntr), CPU_CFG_OFFSET(ext_zihpm), CPU_CFG_OFFSET(ext_zicbom), CPU_CFG_OFFSET(ext_zicbop), CPU_CFG_OFFSET(ext_zicboz), + CPU_CFG_OFFSET(ext_zicclsm), /* mandatory named features for this profile */ CPU_CFG_OFFSET(ext_zic64b), From efb3db26887d7c8c515048019bd71d405173a59d Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 10 Aug 2026 13:56:18 +0800 Subject: [PATCH 504/627] tests/tcg/riscv64: Add test for Zicclsm Cover scalar, floating-point, vector, and segmented misaligned accesses with Zicclsm enabled and disabled. Clean up both generated test binaries. To build and run the tests: make -C build/tests/tcg/riscv64-softmmu \ CC=riscv64-unknown-elf-gcc LD=riscv64-unknown-elf-ld \ test-zicclsm test-zicclsm-off make -C build/tests/tcg/riscv64-softmmu \ run-test-zicclsm run-test-zicclsm-off To clean the generated binaries and objects: make -C build/tests/tcg/riscv64-softmmu clean Signed-off-by: Frank Chang Reviewed-by: Daniel Henrique Barboza Message-ID: <20260810055618.1175500-8-frank.chang@sifive.com> Signed-off-by: Alistair Francis --- tests/tcg/riscv64/Makefile.softmmu-target | 22 ++ tests/tcg/riscv64/test-zicclsm.S | 368 ++++++++++++++++++++++ 2 files changed, 390 insertions(+) create mode 100644 tests/tcg/riscv64/test-zicclsm.S diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target index 82be8a2c91..908fd008e4 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -41,5 +41,27 @@ comma:= , run-test-crc32: test-crc32 $(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<) +# Zicclsm: misaligned load/store support. Assemble one source twice: the +# default build expects every misaligned access to succeed (zicclsm=true), +# the -DZICCLSM_DISABLED build expects every one to trap (zicclsm=false). +ZICCLSM_MARCH = -march=rv64gcv_zfh +CLEANFILES += test-zicclsm test-zicclsm-off + +test-zicclsm: test-zicclsm.S $(LINK_SCRIPT) + $(CC) $(CFLAGS) $(ZICCLSM_MARCH) $< -Wa,--noexecstack -c -o test-zicclsm.o + $(LD) $(LDFLAGS) test-zicclsm.o -o $@ + +test-zicclsm-off: test-zicclsm.S $(LINK_SCRIPT) + $(CC) $(CFLAGS) $(ZICCLSM_MARCH) -DZICCLSM_DISABLED $< -Wa,--noexecstack -c -o test-zicclsm-off.o + $(LD) $(LDFLAGS) test-zicclsm-off.o -o $@ + +EXTRA_RUNS += run-test-zicclsm +run-test-zicclsm: test-zicclsm + $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=true $(QEMU_OPTS)$<) + +EXTRA_RUNS += run-test-zicclsm-off +run-test-zicclsm-off: test-zicclsm-off + $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=false $(QEMU_OPTS)$<) + # We don't currently support the multiarch system tests undefine MULTIARCH_TESTS diff --git a/tests/tcg/riscv64/test-zicclsm.S b/tests/tcg/riscv64/test-zicclsm.S new file mode 100644 index 0000000000..a2f217c0d1 --- /dev/null +++ b/tests/tcg/riscv64/test-zicclsm.S @@ -0,0 +1,368 @@ +/* + * Test the Zicclsm extension (misaligned load/store support). + * + * This single source is assembled twice: + * - test-zicclsm : run on a CPU with zicclsm=true. Every misaligned + * scalar integer, floating-point and vector + * load/store must complete WITHOUT raising a trap. + * - test-zicclsm-off : built with -DZICCLSM_DISABLED and run on a CPU with + * zicclsm=false. Every misaligned access must raise a + * misaligned load/store exception, with the correct + * mcause and mtval. + * + * Zicclsm governs all regular scalar loads/stores (integer and F/D/Zfh + * floating-point) as well as vector element loads/stores. Floating-point + * loads/stores (flh/flw/fld, fsh/fsw/fsd) are therefore exercised here. + * + * Atomic (A/Zacas/...) accesses are intentionally excluded: they always + * require natural alignment regardless of Zicclsm. Likewise cm.push/cm.pop + * (Zcmp) are excluded, as they are not regular loads/stores. + * + * Register conventions (persist across the whole test; the trap handler only + * clobbers t0-t4): + * s1 = expected mcause for the pending misaligned access + * s2 = expected mtval (the misaligned address) + * s3 = trap counter (incremented by the handler) + * s4 = base address of the aligned data buffer + * s5 = snapshot of s3 taken before an access, used to check the delta + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + .option norelax + .option norvc + +/* RISC-V exception causes (see target/riscv/cpu_bits.h). */ +#define CAUSE_LOAD_MISALIGNED 0x4 +#define CAUSE_STORE_MISALIGNED 0x6 + +/* + * EXPECT sets up the expectation for the access that immediately follows and + * snapshots the trap counter. + * \cause = expected mcause if the access traps + * \off = byte offset from the buffer base; also the expected mtval + */ + .macro EXPECT cause, off + li s1, \cause + addi s2, s4, \off + mv s5, s3 + .endm + +/* + * CHECK validates the outcome of the preceding access. + * - When Zicclsm is disabled, exactly one trap must have fired. + * - When Zicclsm is enabled, no trap must have fired. + */ + .macro CHECK +#ifdef ZICCLSM_DISABLED + addi s5, s5, 1 + bne s3, s5, fail +#else + bne s3, s5, fail +#endif + .endm + +/* In the enabled case, also verify the value returned by scalar loads. */ + .macro CHECK_VALUE value +#ifndef ZICCLSM_DISABLED + li t0, \value + bne a2, t0, fail +#endif + .endm + +/* Verify bytes written by an enabled scalar store. */ + .macro CHECK_BYTE off, value +#ifndef ZICCLSM_DISABLED + lbu t0, \off(s4) + li t1, \value + bne t0, t1, fail +#endif + .endm + + .text + .global _start +_start: + /* Install the trap handler. */ + lla t0, trap + csrw mtvec, t0 + + /* Enable the FP (FS) and Vector (VS) unit state so F/D/V instructions + * do not trap as illegal. 0x6600 = FS[14:13]=11 | VS[10:9]=11. */ + li t0, 0x6600 + csrs mstatus, t0 + + /* Initialise persistent state. */ + li s3, 0 /* trap counter */ + lla s4, buf /* aligned buffer base */ + + /* + * ---- Scalar integer loads ---- + * lh/lhu need 2-byte alignment; lw/lwu 4-byte; ld 8-byte. + */ + EXPECT CAUSE_LOAD_MISALIGNED, 1 + lh a2, 1(s4) + CHECK + CHECK_VALUE 0x2211 + EXPECT CAUSE_LOAD_MISALIGNED, 1 + lhu a2, 1(s4) + CHECK + CHECK_VALUE 0x2211 + + EXPECT CAUSE_LOAD_MISALIGNED, 1 + lw a2, 1(s4) + CHECK + CHECK_VALUE 0x44332211 + EXPECT CAUSE_LOAD_MISALIGNED, 3 + lw a2, 3(s4) + CHECK + CHECK_VALUE 0x66554433 + EXPECT CAUSE_LOAD_MISALIGNED, 1 + lwu a2, 1(s4) + CHECK + CHECK_VALUE 0x44332211 + + EXPECT CAUSE_LOAD_MISALIGNED, 1 + ld a2, 1(s4) + CHECK + CHECK_VALUE 0x8877665544332211 + EXPECT CAUSE_LOAD_MISALIGNED, 3 + ld a2, 3(s4) + CHECK + CHECK_VALUE 0xaa99887766554433 + EXPECT CAUSE_LOAD_MISALIGNED, 7 + ld a2, 7(s4) + CHECK + CHECK_VALUE 0xeeddccbbaa998877 + + /* + * ---- Scalar integer stores ---- + */ + li t6, 0x1122334455667788 + EXPECT CAUSE_STORE_MISALIGNED, 1 + sh t6, 1(s4) + CHECK + CHECK_BYTE 1, 0x88 + CHECK_BYTE 2, 0x77 + + EXPECT CAUSE_STORE_MISALIGNED, 1 + sw t6, 1(s4) + CHECK + CHECK_BYTE 1, 0x88 + CHECK_BYTE 2, 0x77 + CHECK_BYTE 3, 0x66 + CHECK_BYTE 4, 0x55 + EXPECT CAUSE_STORE_MISALIGNED, 3 + sw t6, 3(s4) + CHECK + CHECK_BYTE 3, 0x88 + CHECK_BYTE 4, 0x77 + CHECK_BYTE 5, 0x66 + CHECK_BYTE 6, 0x55 + + EXPECT CAUSE_STORE_MISALIGNED, 1 + sd t6, 1(s4) + CHECK + CHECK_BYTE 1, 0x88 + CHECK_BYTE 2, 0x77 + CHECK_BYTE 3, 0x66 + CHECK_BYTE 4, 0x55 + CHECK_BYTE 5, 0x44 + CHECK_BYTE 6, 0x33 + CHECK_BYTE 7, 0x22 + CHECK_BYTE 8, 0x11 + EXPECT CAUSE_STORE_MISALIGNED, 7 + sd t6, 7(s4) + CHECK + CHECK_BYTE 7, 0x88 + CHECK_BYTE 8, 0x77 + CHECK_BYTE 9, 0x66 + CHECK_BYTE 10, 0x55 + CHECK_BYTE 11, 0x44 + CHECK_BYTE 12, 0x33 + CHECK_BYTE 13, 0x22 + CHECK_BYTE 14, 0x11 + + /* + * ---- Floating-point loads ---- + * flh needs 2-byte alignment; flw 4-byte; fld 8-byte. Their alignment + * is governed by Zicclsm just like the scalar integer forms. + */ + EXPECT CAUSE_LOAD_MISALIGNED, 1 + flh fa0, 1(s4) + CHECK + + EXPECT CAUSE_LOAD_MISALIGNED, 1 + flw fa0, 1(s4) + CHECK + EXPECT CAUSE_LOAD_MISALIGNED, 3 + flw fa0, 3(s4) + CHECK + + EXPECT CAUSE_LOAD_MISALIGNED, 1 + fld fa0, 1(s4) + CHECK + EXPECT CAUSE_LOAD_MISALIGNED, 7 + fld fa0, 7(s4) + CHECK + + /* + * ---- Floating-point stores ---- + */ + EXPECT CAUSE_STORE_MISALIGNED, 1 + fsh fa0, 1(s4) + CHECK + + EXPECT CAUSE_STORE_MISALIGNED, 1 + fsw fa0, 1(s4) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 3 + fsw fa0, 3(s4) + CHECK + + EXPECT CAUSE_STORE_MISALIGNED, 1 + fsd fa0, 1(s4) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 7 + fsd fa0, 7(s4) + CHECK + + /* + * ---- Vector unit-stride loads / stores ---- + * A base address that is not aligned to the element size (SEW) is + * misaligned for the first element access. + */ + vsetvli t1, x0, e16, m1, ta, ma + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vle16.v v0, (a0) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 1 + addi a0, s4, 1 + vse16.v v0, (a0) + CHECK + + vsetvli t1, x0, e32, m1, ta, ma + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vle32.v v0, (a0) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 3 + addi a0, s4, 3 + vse32.v v0, (a0) + CHECK + + vsetvli t1, x0, e64, m1, ta, ma + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vle64.v v0, (a0) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 7 + addi a0, s4, 7 + vse64.v v0, (a0) + CHECK + + /* + * ---- Vector strided loads / stores ---- + */ + vsetvli t1, x0, e32, m1, ta, ma + li a1, 8 /* stride in bytes */ + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vlse32.v v0, (a0), a1 + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 1 + addi a0, s4, 1 + vsse32.v v0, (a0), a1 + CHECK + + /* ---- Vector indexed loads / stores ---- */ + /* + * Zero indices keep the first element at the deliberately misaligned base. + */ + vmv.v.i v1, 0 + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vluxei32.v v0, (a0), v1 + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 1 + addi a0, s4, 1 + vsuxei32.v v0, (a0), v1 + CHECK + + /* ---- Vector segmented loads / stores ---- */ + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vlseg2e32.v v0, (a0) + CHECK + EXPECT CAUSE_STORE_MISALIGNED, 1 + addi a0, s4, 1 + vsseg2e32.v v0, (a0) + CHECK + + /* + * ---- Vector whole-register load ---- + * Only the whole-register *load* forms carry an element width + * (vl1re32.v => EEW=32), so only they enforce alignment when Zicclsm is + * off. The whole-register store form (vs1r.v) is defined as EEW=8 + * (byte granular) and therefore never faults on misalignment, so it is + * not exercised here. + */ + EXPECT CAUSE_LOAD_MISALIGNED, 1 + addi a0, s4, 1 + vl1re32.v v1, (a0) + CHECK + + /* Success. */ + li a0, 0 + j _exit + + /* + * Trap handler: validate mcause and mtval against the expectation, bump + * the trap counter, then skip past the faulting instruction. The + * instruction length is decoded from its low two bits (0b11 => 4 bytes, + * otherwise a 2-byte compressed instruction). + */ + .balign 4 +trap: + csrr t0, mcause + bne t0, s1, fail + csrr t1, mtval + bne t1, s2, fail + addi s3, s3, 1 + + csrr t0, mepc + lhu t2, 0(t0) + andi t3, t2, 3 + li t4, 3 + bne t3, t4, 1f + addi t0, t0, 4 /* 32-bit instruction */ + j 2f +1: + addi t0, t0, 2 /* 16-bit compressed instruction */ +2: + csrw mepc, t0 + mret + +fail: + li a0, 1 +_exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 + .balign 64 +buf: + .byte 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 + .byte 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + .space 240 From 5a9fa8b5820998a5aca02ecf3df12819f7ff2173 Mon Sep 17 00:00:00 2001 From: Zephyr Li Date: Thu, 30 Jul 2026 11:21:20 +0800 Subject: [PATCH 505/627] target/riscv: do not count ECALL in minstret With icount enabled, helper_raise_exception() leaves ECALL in icount_get_raw() because it exits without restoring the current TB state. This makes minstret count an instruction that does not retire. Adjust only the fixed minstret baseline so that mcycle accounting remains unchanged. Add an RV64 softmmu regression test for the issue. Fixes: 4fe8ae09062d ("target/riscv: Combine mhpmcounter and mhpmcounterh") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4087 Signed-off-by: Zephyr Li Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20260730032122.2564190-1-fritchleybohrer@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/op_helper.c | 6 +++ target/riscv/tcg/pmu.c | 44 +++++++++++++----- target/riscv/tcg/pmu.h | 1 + tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/test-minstret-ecall.S | 55 +++++++++++++++++++++++ 5 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 tests/tcg/riscv64/test-minstret-ecall.S diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c index ba3c7da375..acdccd1a97 100644 --- a/target/riscv/tcg/op_helper.c +++ b/target/riscv/tcg/op_helper.c @@ -21,6 +21,9 @@ #include "qemu/osdep.h" #include "cpu.h" #include "target/riscv/tcg/csr.h" +#ifndef CONFIG_USER_ONLY +#include "pmu.h" +#endif #include "internals.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-ldst.h" @@ -47,6 +50,9 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env, void helper_raise_exception(CPURISCVState *env, uint32_t exception) { +#ifndef CONFIG_USER_ONLY + riscv_pmu_decr_instret(env); +#endif riscv_raise_exception(env, exception, 0); } diff --git a/target/riscv/tcg/pmu.c b/target/riscv/tcg/pmu.c index 38ad2737e1..1a4658319b 100644 --- a/target/riscv/tcg/pmu.c +++ b/target/riscv/tcg/pmu.c @@ -49,6 +49,21 @@ static bool riscv_pmu_counter_enabled(RISCVCPU *cpu, uint32_t ctr_idx) } } +static bool riscv_pmu_counter_filtered(CPURISCVState *env, uint64_t cfg) +{ + bool virt_on = env->virt_enabled; + + return (env->priv == PRV_M && (cfg & MHPMEVENT_BIT_MINH)) || + (env->priv == PRV_S && virt_on && + (cfg & MHPMEVENT_BIT_VSINH)) || + (env->priv == PRV_U && virt_on && + (cfg & MHPMEVENT_BIT_VUINH)) || + (env->priv == PRV_S && !virt_on && + (cfg & MHPMEVENT_BIT_SINH)) || + (env->priv == PRV_U && !virt_on && + (cfg & MHPMEVENT_BIT_UINH)); +} + /* * Information needed to update counters: * new_priv, new_virt: To correctly save starting snapshot for the newly @@ -147,12 +162,27 @@ void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, riscv_pmu_icount_update_priv(env, newpriv, new_virt); } +void riscv_pmu_decr_instret(CPURISCVState *env) +{ + if (!icount_enabled() || + (env->mcountinhibit & COUNTEREN_IR) || + riscv_pmu_counter_filtered(env, env->minstretcfg)) { + return; + } + + /* + * minstret is derived from icount, which includes the current + * instruction. Move the baseline forward to exclude an instruction + * that raises an exception and therefore does not retire. + */ + env->pmu_ctrs[2].mhpmcounter_prev++; +} + int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) { uint32_t ctr_idx; CPURISCVState *env = &cpu->env; uint64_t max_val = UINT64_MAX; - bool virt_on = env->virt_enabled; PMUCTRState *counter; gpointer value; @@ -170,17 +200,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) return -1; } - /* Privilege mode filtering */ - if ((env->priv == PRV_M && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_MINH)) || - (env->priv == PRV_S && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VSINH)) || - (env->priv == PRV_U && virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_VUINH)) || - (env->priv == PRV_S && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_SINH)) || - (env->priv == PRV_U && !virt_on && - (env->mhpmevent_val[ctr_idx] & MHPMEVENT_BIT_UINH))) { + if (riscv_pmu_counter_filtered(env, env->mhpmevent_val[ctr_idx])) { return 0; } diff --git a/target/riscv/tcg/pmu.h b/target/riscv/tcg/pmu.h index b4f1e469a2..2429c01b77 100644 --- a/target/riscv/tcg/pmu.h +++ b/target/riscv/tcg/pmu.h @@ -36,6 +36,7 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx); void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, privilege_mode_t newpriv, bool new_virt); +void riscv_pmu_decr_instret(CPURISCVState *env); RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, bool upper_half, uint32_t ctr_idx); diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target index 908fd008e4..fac0474746 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -24,6 +24,10 @@ EXTRA_RUNS += run-test-mepc-masking run-test-mepc-masking: test-mepc-masking $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<) +EXTRA_RUNS += run-test-minstret-ecall +run-test-minstret-ecall: test-minstret-ecall + $(call run-test, $<, $(QEMU) -icount shift=1 $(QEMU_OPTS)$<) + EXTRA_RUNS += run-plugin-doubletrap run-plugin-doubletrap: doubletrap $(call run-test, $<, \ diff --git a/tests/tcg/riscv64/test-minstret-ecall.S b/tests/tcg/riscv64/test-minstret-ecall.S new file mode 100644 index 0000000000..ab268f7f22 --- /dev/null +++ b/tests/tcg/riscv64/test-minstret-ecall.S @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + + .option norvc + + .text + .global _start +_start: + lla t0, trap + csrw mtvec, t0 + + /* + * The first CSR read retires after obtaining s0. The ecall does not + * retire, so the trap handler must observe a difference of one. + */ + csrr s0, minstret + ecall + sub t0, s1, s0 + li t1, 1 + bne t0, t1, fail + + li a0, 0 + j _exit + +trap: + csrr s1, minstret + csrr t0, mcause + li t1, 11 /* Environment call from M-mode */ + bne t0, t1, fail + + csrr t0, mepc + addi t0, t0, 4 + csrw mepc, t0 + mret + +fail: + li a0, 1 + +_exit: + lla a1, semiargs + li t0, 0x20026 /* ADP_Stopped_ApplicationExit */ + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */ + + /* Semihosting call sequence */ + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 From 51362da8f73b13ad029287ee33e190a212894183 Mon Sep 17 00:00:00 2001 From: Ivan Efremov Date: Sun, 2 Aug 2026 14:31:28 +0300 Subject: [PATCH 506/627] target/riscv: Fix seed CSR sign extension The SEED_OPST_* macros expanded to int expressions. When bit 31 was present, converting a CSR seed value to target_ulong on RV64 sign extended the value and incorrectly set the upper 32 bits. Make the SEED_OPST_* constants unsigned so that CSR values are zero extended on RV64. Fixes: 77442380ecbe ("target/riscv: rvk: add CSR support for Zkr") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4121 Signed-off-by: Ivan Efremov Reviewed-by: Alistair Francis Message-ID: <20260802113130.7818-2-nendensu@ispras.ru> Signed-off-by: Alistair Francis --- target/riscv/cpu_bits.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 3f146a43fe..c01050ce2b 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -1086,11 +1086,11 @@ typedef enum CTRType { (HVICTL_VTI | HVICTL_IID | HVICTL_IPRIOM | HVICTL_IPRIO) /* seed CSR bits */ -#define SEED_OPST (0b11 << 30) -#define SEED_OPST_BIST (0b00 << 30) -#define SEED_OPST_WAIT (0b01 << 30) -#define SEED_OPST_ES16 (0b10 << 30) -#define SEED_OPST_DEAD (0b11 << 30) +#define SEED_OPST (0b11U << 30) +#define SEED_OPST_BIST (0b00U << 30) +#define SEED_OPST_WAIT (0b01U << 30) +#define SEED_OPST_ES16 (0b10U << 30) +#define SEED_OPST_DEAD (0b11U << 30) /* PMU related bits */ #define MIE_LCOFIE (1 << IRQ_PMU_OVF) From e80cf294797870b019d31dd299328aebdfaaa76c Mon Sep 17 00:00:00 2001 From: Ivan Efremov Date: Sun, 2 Aug 2026 14:31:29 +0300 Subject: [PATCH 507/627] tests/qtest: Add seed CSR zero extension test Add a qtest that reads the seed CSR on RV64 machine with Zkr support and verifies that the upper 32 bits are clear. Signed-off-by: Ivan Efremov Reviewed-by: Alistair Francis Message-ID: <20260802113130.7818-3-nendensu@ispras.ru> Signed-off-by: Alistair Francis --- tests/qtest/riscv-csr-test.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/qtest/riscv-csr-test.c b/tests/qtest/riscv-csr-test.c index bb1b0ffed3..7479a5c5bc 100644 --- a/tests/qtest/riscv-csr-test.c +++ b/tests/qtest/riscv-csr-test.c @@ -20,6 +20,12 @@ #define CSR_MVENDORID 0xf11 #define CSR_MISELECT 0x350 +#define CSR_SEED 0x015 + +#define SEED_OPST_MASK (UINT64_C(0x3) << 30) +#define SEED_OPST_ES16 (UINT64_C(0x2) << 30) +#define SEED_OPST_DEAD (UINT64_C(0x3) << 30) + static void run_test_csr(void) { uint64_t res; @@ -46,12 +52,32 @@ static void run_test_csr(void) qtest_quit(qts); } +static void run_test_seed_csr(void) +{ + uint64_t val = 0; + uint64_t opst; + QTestState *qts; + + qts = qtest_init("-machine virt -cpu tt-ascalon"); + + qtest_csr_call(qts, "get_csr", 0, CSR_SEED, &val); + + opst = val & SEED_OPST_MASK; + g_assert_true(opst == SEED_OPST_ES16 || + opst == SEED_OPST_DEAD); + + g_assert_cmphex(val >> 32, ==, 0); + + qtest_quit(qts); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); if (qtest_has_machine("virt")) { qtest_add_func("/cpu/csr", run_test_csr); + qtest_add_func("/cpu/csr/seed", run_test_seed_csr); } return g_test_run(); From 6985cfc87512e96c0abfa7fffc836e7bd3889048 Mon Sep 17 00:00:00 2001 From: TANG Tiancheng Date: Fri, 3 Jul 2026 13:03:36 +0800 Subject: [PATCH 508/627] disas/riscv: Fix th.srri decoding target/riscv/xthead.decode defines th.srri as funct6=000100 in bits 31:26, with the 6-bit immediate in bits 25:20. decode_xtheadbb() switches on bits 31:25, i.e. funct6 plus imm[5]. Therefore valid th.srri encodings are 0001000 and 0001001. The current 0000100 and 0000101 cases use the wrong funct6 value and decode valid th.srri instructions as illegal. Fix the cases to match funct6=000100 with both imm[5] values. Fixes: 318df7238b9f ("disas/riscv: Add support for XThead* instructions") Signed-off-by: TANG Tiancheng Reviewed-by: LIU Zhiwei Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20260703-b4-disas-xthead-fix-riscv-next-v4-1-84c566330bc7@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv-xthead.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index fcca326d1c..2f2ddb8dd9 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -315,8 +315,10 @@ void decode_xtheadbb(rv_decode *dec, rv_isa isa) op = rv_op_th_revw; } break; - case 0b0000100: - case 0b0000101: op = rv_op_th_srri; break; + case 0b0001000: + case 0b0001001: + op = rv_op_th_srri; + break; } break; case 2: op = rv_op_th_ext; break; From 7a8454ef293085a45686929577b7d5a5daded242 Mon Sep 17 00:00:00 2001 From: TANG Tiancheng Date: Fri, 3 Jul 2026 13:03:37 +0800 Subject: [PATCH 509/627] disas/riscv: Fix 6-bit immediate extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rv_codec_r2_imm6 is used for XThead instructions whose 6-bit immediate field is encoded in bits 25:20. The old expression left-shifted by 38 and then right-shifted by 60, so it kept only bits 25:22. Use extract32() to decode bits 25:20 directly. This fixes the immediate printed for th.srri and th.tst. Fixes: 318df7238b9f ("disas/riscv: Add support for XThead* instructions") Suggested-by: Alex Bennée Signed-off-by: TANG Tiancheng Reviewed-by: LIU Zhiwei Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20260703-b4-disas-xthead-fix-riscv-next-v4-2-84c566330bc7@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas/riscv.c b/disas/riscv.c index 7f1b262773..fdf75a12ef 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -4546,7 +4546,7 @@ static uint32_t operand_zcmp_rlist(rv_inst inst) static uint32_t operand_imm6(rv_inst inst) { - return (inst << 38) >> 60; + return extract32(inst, 20, 6); } static uint32_t operand_imm2(rv_inst inst) From 7899d3c6bdb008dd301b474f3524bad5f37a411e Mon Sep 17 00:00:00 2001 From: TANG Tiancheng Date: Fri, 3 Jul 2026 13:03:38 +0800 Subject: [PATCH 510/627] disas/riscv: Use signed type for vector immediates operand_vimm() sign-extends the 5-bit vector immediate field in bits 19:15, but returns uint32_t. This sends negative immediates through an unsigned type before they are assigned to rv_decode.imm. Return int32_t to match the signed value extracted by the helper. Signed-off-by: TANG Tiancheng Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20260703-b4-disas-xthead-fix-riscv-next-v4-3-84c566330bc7@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas/riscv.c b/disas/riscv.c index fdf75a12ef..967739bdbb 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -4487,7 +4487,7 @@ static uint32_t operand_cimmq(rv_inst inst) ((inst << 57) >> 62) << 6; } -static uint32_t operand_vimm(rv_inst inst) +static int32_t operand_vimm(rv_inst inst) { return (int64_t)(inst << 44) >> 59; } From 00cec77a7f9f80eb6dc8f0c27009403729e3641e Mon Sep 17 00:00:00 2001 From: TANG Tiancheng Date: Fri, 3 Jul 2026 13:03:39 +0800 Subject: [PATCH 511/627] disas/riscv: Decode unsigned vector immediates as unsigned rv_codec_v_i decodes all .vi operands with operand_vimm(), which sign-extends bits 19:15. That matches spec operands named imm, but not the .vi forms whose operand is uimm; uimm=31 is decoded as -1 and printed by the shared 6-bit 'u' formatter as 63. Add rv_codec_v_i_u/operand_vuimm() for the 5-bit uimm forms: vsll.vi, vsrl.vi, vsra.vi, vnsrl.wi, vnsra.wi, vssrl.vi, vssra.vi, vnclipu.wi, vnclip.wi, vslideup.vi, vslidedown.vi, vrgather.vi, vaeskf1.vi, vaeskf2.vi, vsm3c.vi, vsm4k.vi and vwsll.vi. The remaining rv_codec_v_i entries are the signed imm forms. Fixes: 07f4964d1785 ("disas/riscv.c: rvv: Add disas support for vector instructions") Fixes: 9d92f56d4a44 ("disas/riscv: Add support for vector crypto extensions") Signed-off-by: TANG Tiancheng Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20260703-b4-disas-xthead-fix-riscv-next-v4-4-84c566330bc7@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 45 ++++++++++++++++++++++++++++----------------- disas/riscv.h | 1 + 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 967739bdbb..82b962dc71 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1803,19 +1803,19 @@ const rv_opcode_data rvi_opcode_data[] = { { "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, { "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsll.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsrl.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsra.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnsrl.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnsra.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, { "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, @@ -1909,16 +1909,16 @@ const rv_opcode_data rvi_opcode_data[] = { { "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, { "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssrl.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssra.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnclipu.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnclip.wi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, { "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, @@ -2048,15 +2048,15 @@ const rv_opcode_data rvi_opcode_data[] = { { "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2, NULL, 0, 0, 0 }, { "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1, NULL, 0, 0, 0 }, { "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vslideup.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, { "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vslidedown.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, { "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrgather.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, { "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, @@ -2144,8 +2144,8 @@ const rv_opcode_data rvi_opcode_data[] = { { "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaeskf1.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, - { "vaeskf2.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, + { "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, + { "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, { "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, @@ -2169,14 +2169,14 @@ const rv_opcode_data rvi_opcode_data[] = { { "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, { "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, { "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsm3c.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, + { "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, { "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsm4k.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, + { "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, { "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, { "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsll.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, { "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, @@ -4492,6 +4492,11 @@ static int32_t operand_vimm(rv_inst inst) return (int64_t)(inst << 44) >> 59; } +static uint32_t operand_vuimm(rv_inst inst) +{ + return extract32(inst, 15, 5); +} + static uint32_t operand_vzimm11(rv_inst inst) { return (inst << 33) >> 53; @@ -4895,6 +4900,12 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa) dec->imm = operand_vimm(inst); dec->vm = operand_vm(inst); break; + case rv_codec_v_i_u: + dec->rd = operand_rd(inst); + dec->rs2 = operand_rs2(inst); + dec->imm = operand_vuimm(inst); + dec->vm = operand_vm(inst); + break; case rv_codec_vror_vi: dec->rd = operand_rd(inst); dec->rs2 = operand_rs2(inst); diff --git a/disas/riscv.h b/disas/riscv.h index 379e642ec8..91ada8b531 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -149,6 +149,7 @@ typedef enum { rv_codec_v_r, rv_codec_v_ldst, rv_codec_v_i, + rv_codec_v_i_u, rv_codec_vsetvli, rv_codec_vsetivli, rv_codec_vror_vi, From dacaa5412b93cc67782decf5e586cc239fce0918 Mon Sep 17 00:00:00 2001 From: TANG Tiancheng Date: Fri, 3 Jul 2026 13:03:40 +0800 Subject: [PATCH 512/627] disas/riscv: Use extract helpers for operand fields Replace shift-based operand extraction with extract32() and sextract32(). For signed immediates, use sextract32() on the field that carries the sign bit and combine it with the remaining extract32() fields. The RISC-V disassembler currently follows target/riscv/internals.h: insn_len() and decodes only 16-bit or 32-bit instruction lengths, so the converted fields are all in the low 32 bits of rv_inst. Suggested-by: Richard Henderson Signed-off-by: TANG Tiancheng Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20260703-b4-disas-xthead-fix-riscv-next-v4-5-84c566330bc7@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 214 +++++++++++++++++++++++++------------------------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 82b962dc71..2ba0a6a73a 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -4202,82 +4202,82 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) static uint32_t operand_rd(rv_inst inst) { - return (inst << 52) >> 59; + return extract32(inst, 7, 5); } static uint32_t operand_rs1(rv_inst inst) { - return (inst << 44) >> 59; + return extract32(inst, 15, 5); } static uint32_t operand_rs2(rv_inst inst) { - return (inst << 39) >> 59; + return extract32(inst, 20, 5); } static uint32_t operand_rs3(rv_inst inst) { - return (inst << 32) >> 59; + return extract32(inst, 27, 5); } static uint32_t operand_aq(rv_inst inst) { - return (inst << 37) >> 63; + return extract32(inst, 26, 1); } static uint32_t operand_rl(rv_inst inst) { - return (inst << 38) >> 63; + return extract32(inst, 25, 1); } static uint32_t operand_pred(rv_inst inst) { - return (inst << 36) >> 60; + return extract32(inst, 24, 4); } static uint32_t operand_succ(rv_inst inst) { - return (inst << 40) >> 60; + return extract32(inst, 20, 4); } static uint32_t operand_rm(rv_inst inst) { - return (inst << 49) >> 61; + return extract32(inst, 12, 3); } static uint32_t operand_shamt5(rv_inst inst) { - return (inst << 39) >> 59; + return extract32(inst, 20, 5); } static uint32_t operand_shamt6(rv_inst inst) { - return (inst << 38) >> 58; + return extract32(inst, 20, 6); } static uint32_t operand_shamt7(rv_inst inst) { - return (inst << 37) >> 57; + return extract32(inst, 20, 7); } static uint32_t operand_crdq(rv_inst inst) { - return (inst << 59) >> 61; + return extract32(inst, 2, 3); } static uint32_t operand_crs1q(rv_inst inst) { - return (inst << 54) >> 61; + return extract32(inst, 7, 3); } static uint32_t operand_crs1rdq(rv_inst inst) { - return (inst << 54) >> 61; + return extract32(inst, 7, 3); } static uint32_t operand_crs2q(rv_inst inst) { - return (inst << 59) >> 61; + return extract32(inst, 2, 3); } static uint32_t calculate_xreg(uint32_t sreg) @@ -4287,80 +4287,80 @@ static uint32_t calculate_xreg(uint32_t sreg) static uint32_t operand_sreg1(rv_inst inst) { - return calculate_xreg((inst << 54) >> 61); + return calculate_xreg(extract32(inst, 7, 3)); } static uint32_t operand_sreg2(rv_inst inst) { - return calculate_xreg((inst << 59) >> 61); + return calculate_xreg(extract32(inst, 2, 3)); } static uint32_t operand_crd(rv_inst inst) { - return (inst << 52) >> 59; + return extract32(inst, 7, 5); } static uint32_t operand_crs1(rv_inst inst) { - return (inst << 52) >> 59; + return extract32(inst, 7, 5); } static uint32_t operand_crs1rd(rv_inst inst) { - return (inst << 52) >> 59; + return extract32(inst, 7, 5); } static uint32_t operand_crs2(rv_inst inst) { - return (inst << 57) >> 59; + return extract32(inst, 2, 5); } static uint32_t operand_cimmsh5(rv_inst inst) { - return (inst << 57) >> 59; + return extract32(inst, 2, 5); } static uint32_t operand_csr12(rv_inst inst) { - return (inst << 32) >> 52; + return extract32(inst, 20, 12); } static int32_t operand_imm12(rv_inst inst) { - return ((int64_t)inst << 32) >> 52; + return sextract32(inst, 20, 12); } static int32_t operand_imm20(rv_inst inst) { - return (((int64_t)inst << 32) >> 44) << 12; + return sextract32(inst, 12, 20) << 12; } static int32_t operand_jimm20(rv_inst inst) { - return (((int64_t)inst << 32) >> 63) << 20 | - ((inst << 33) >> 54) << 1 | - ((inst << 43) >> 63) << 11 | - ((inst << 44) >> 56) << 12; + return sextract32(inst, 31, 1) << 20 | + extract32(inst, 21, 10) << 1 | + extract32(inst, 20, 1) << 11 | + extract32(inst, 12, 8) << 12; } static int32_t operand_simm12(rv_inst inst) { - return (((int64_t)inst << 32) >> 57) << 5 | - (inst << 52) >> 59; + return sextract32(inst, 25, 7) << 5 | + extract32(inst, 7, 5); } static int32_t operand_sbimm12(rv_inst inst) { - return (((int64_t)inst << 32) >> 63) << 12 | - ((inst << 33) >> 58) << 5 | - ((inst << 52) >> 60) << 1 | - ((inst << 56) >> 63) << 11; + return sextract32(inst, 31, 1) << 12 | + extract32(inst, 25, 6) << 5 | + extract32(inst, 8, 4) << 1 | + extract32(inst, 7, 1) << 11; } static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) { - int imm = ((inst << 51) >> 63) << 5 | - (inst << 57) >> 59; + int imm = extract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); if (isa == rv128) { imm = imm ? imm : 64; } @@ -4369,8 +4369,8 @@ static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) { - int imm = ((inst << 51) >> 63) << 5 | - (inst << 57) >> 59; + int imm = extract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); if (isa == rv128) { imm = imm | (imm & 32) << 1; imm = imm ? imm : 64; @@ -4380,116 +4380,116 @@ static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) static int32_t operand_cimmi(rv_inst inst) { - return (((int64_t)inst << 51) >> 63) << 5 | - (inst << 57) >> 59; + return sextract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); } static int32_t operand_cimmui(rv_inst inst) { - return (((int64_t)inst << 51) >> 63) << 17 | - ((inst << 57) >> 59) << 12; + return sextract32(inst, 12, 1) << 17 | + extract32(inst, 2, 5) << 12; } static uint32_t operand_cimmlwsp(rv_inst inst) { - return ((inst << 51) >> 63) << 5 | - ((inst << 57) >> 61) << 2 | - ((inst << 60) >> 62) << 6; + return extract32(inst, 12, 1) << 5 | + extract32(inst, 4, 3) << 2 | + extract32(inst, 2, 2) << 6; } static uint32_t operand_cimmldsp(rv_inst inst) { - return ((inst << 51) >> 63) << 5 | - ((inst << 57) >> 62) << 3 | - ((inst << 59) >> 61) << 6; + return extract32(inst, 12, 1) << 5 | + extract32(inst, 5, 2) << 3 | + extract32(inst, 2, 3) << 6; } static uint32_t operand_cimmlqsp(rv_inst inst) { - return ((inst << 51) >> 63) << 5 | - ((inst << 57) >> 63) << 4 | - ((inst << 58) >> 60) << 6; + return extract32(inst, 12, 1) << 5 | + extract32(inst, 6, 1) << 4 | + extract32(inst, 2, 4) << 6; } static int32_t operand_cimm16sp(rv_inst inst) { - return (((int64_t)inst << 51) >> 63) << 9 | - ((inst << 57) >> 63) << 4 | - ((inst << 58) >> 63) << 6 | - ((inst << 59) >> 62) << 7 | - ((inst << 61) >> 63) << 5; + return sextract32(inst, 12, 1) << 9 | + extract32(inst, 6, 1) << 4 | + extract32(inst, 5, 1) << 6 | + extract32(inst, 3, 2) << 7 | + extract32(inst, 2, 1) << 5; } static int32_t operand_cimmj(rv_inst inst) { - return (((int64_t)inst << 51) >> 63) << 11 | - ((inst << 52) >> 63) << 4 | - ((inst << 53) >> 62) << 8 | - ((inst << 55) >> 63) << 10 | - ((inst << 56) >> 63) << 6 | - ((inst << 57) >> 63) << 7 | - ((inst << 58) >> 61) << 1 | - ((inst << 61) >> 63) << 5; + return sextract32(inst, 12, 1) << 11 | + extract32(inst, 11, 1) << 4 | + extract32(inst, 9, 2) << 8 | + extract32(inst, 8, 1) << 10 | + extract32(inst, 7, 1) << 6 | + extract32(inst, 6, 1) << 7 | + extract32(inst, 3, 3) << 1 | + extract32(inst, 2, 1) << 5; } static int32_t operand_cimmb(rv_inst inst) { - return (((int64_t)inst << 51) >> 63) << 8 | - ((inst << 52) >> 62) << 3 | - ((inst << 57) >> 62) << 6 | - ((inst << 59) >> 62) << 1 | - ((inst << 61) >> 63) << 5; + return sextract32(inst, 12, 1) << 8 | + extract32(inst, 10, 2) << 3 | + extract32(inst, 5, 2) << 6 | + extract32(inst, 3, 2) << 1 | + extract32(inst, 2, 1) << 5; } static uint32_t operand_cimmswsp(rv_inst inst) { - return ((inst << 51) >> 60) << 2 | - ((inst << 55) >> 62) << 6; + return extract32(inst, 9, 4) << 2 | + extract32(inst, 7, 2) << 6; } static uint32_t operand_cimmsdsp(rv_inst inst) { - return ((inst << 51) >> 61) << 3 | - ((inst << 54) >> 61) << 6; + return extract32(inst, 10, 3) << 3 | + extract32(inst, 7, 3) << 6; } static uint32_t operand_cimmsqsp(rv_inst inst) { - return ((inst << 51) >> 62) << 4 | - ((inst << 53) >> 60) << 6; + return extract32(inst, 11, 2) << 4 | + extract32(inst, 7, 4) << 6; } static uint32_t operand_cimm4spn(rv_inst inst) { - return ((inst << 51) >> 62) << 4 | - ((inst << 53) >> 60) << 6 | - ((inst << 57) >> 63) << 2 | - ((inst << 58) >> 63) << 3; + return extract32(inst, 11, 2) << 4 | + extract32(inst, 7, 4) << 6 | + extract32(inst, 6, 1) << 2 | + extract32(inst, 5, 1) << 3; } static uint32_t operand_cimmw(rv_inst inst) { - return ((inst << 51) >> 61) << 3 | - ((inst << 57) >> 63) << 2 | - ((inst << 58) >> 63) << 6; + return extract32(inst, 10, 3) << 3 | + extract32(inst, 6, 1) << 2 | + extract32(inst, 5, 1) << 6; } static uint32_t operand_cimmd(rv_inst inst) { - return ((inst << 51) >> 61) << 3 | - ((inst << 57) >> 62) << 6; + return extract32(inst, 10, 3) << 3 | + extract32(inst, 5, 2) << 6; } static uint32_t operand_cimmq(rv_inst inst) { - return ((inst << 51) >> 62) << 4 | - ((inst << 53) >> 63) << 8 | - ((inst << 57) >> 62) << 6; + return extract32(inst, 11, 2) << 4 | + extract32(inst, 10, 1) << 8 | + extract32(inst, 5, 2) << 6; } static int32_t operand_vimm(rv_inst inst) { - return (int64_t)(inst << 44) >> 59; + return sextract32(inst, 15, 5); } static uint32_t operand_vuimm(rv_inst inst) @@ -4499,54 +4499,54 @@ static uint32_t operand_vuimm(rv_inst inst) static uint32_t operand_vzimm11(rv_inst inst) { - return (inst << 33) >> 53; + return extract32(inst, 20, 11); } static uint32_t operand_vzimm10(rv_inst inst) { - return (inst << 34) >> 54; + return extract32(inst, 20, 10); } static uint32_t operand_vzimm6(rv_inst inst) { - return ((inst << 37) >> 63) << 5 | - ((inst << 44) >> 59); + return extract32(inst, 26, 1) << 5 | + extract32(inst, 15, 5); } static uint32_t operand_bs(rv_inst inst) { - return (inst << 32) >> 62; + return extract32(inst, 30, 2); } static uint32_t operand_rnum(rv_inst inst) { - return (inst << 40) >> 60; + return extract32(inst, 20, 4); } static uint32_t operand_vm(rv_inst inst) { - return (inst << 38) >> 63; + return extract32(inst, 25, 1); } static uint32_t operand_uimm_c_lb(rv_inst inst) { - return (((inst << 58) >> 63) << 1) | - ((inst << 57) >> 63); + return extract32(inst, 5, 1) << 1 | + extract32(inst, 6, 1); } static uint32_t operand_uimm_c_lh(rv_inst inst) { - return (((inst << 58) >> 63) << 1); + return extract32(inst, 5, 1) << 1; } static uint32_t operand_zcmp_spimm(rv_inst inst) { - return ((inst << 60) >> 62) << 4; + return extract32(inst, 2, 2) << 4; } static uint32_t operand_zcmp_rlist(rv_inst inst) { - return ((inst << 56) >> 60); + return extract32(inst, 4, 4); } static uint32_t operand_imm6(rv_inst inst) @@ -4556,17 +4556,17 @@ static uint32_t operand_imm6(rv_inst inst) static uint32_t operand_imm2(rv_inst inst) { - return (inst << 37) >> 62; + return extract32(inst, 25, 2); } static uint32_t operand_immh(rv_inst inst) { - return (inst << 32) >> 58; + return extract32(inst, 26, 6); } static uint32_t operand_imml(rv_inst inst) { - return (inst << 38) >> 58; + return extract32(inst, 20, 6); } static uint32_t calculate_stack_adj(rv_isa isa, uint32_t rlist, uint32_t spimm) @@ -4585,12 +4585,12 @@ static uint32_t operand_zcmp_stack_adj(rv_inst inst, rv_isa isa) static uint32_t operand_tbl_index(rv_inst inst) { - return ((inst << 54) >> 56); + return extract32(inst, 2, 8); } static uint32_t operand_lpl(rv_inst inst) { - return inst >> 12; + return extract32(inst, 12, 20); } /* decode operands */ From f16fd27b3fe3c305d95c61d3516e458c45c6e8c9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 17 Jul 2026 13:23:40 +0200 Subject: [PATCH 513/627] hw/riscv/riscv-iommu: fix U-bit check to apply only to leaf S/VS-stage PTEs Commit b795ea0ba471 ("hw/riscv/riscv-iommu.c: fault when !PTE_U and no priv access") placed its check ahead of the leaf-vs-non-leaf branch in riscv_iommu_spa_fetch(), so it fires on every PTE walked, including non-leaf/table entries. Per the RISC-V privileged spec's address translation algorithm (Sv39/Sv48/etc., the "leaf PTE has been reached" step, followed separately by the U-bit permission check), the U bit is only defined and checked for the leaf PTE reached at the end of the walk -- non-leaf PTEs don't carry a meaningful U bit at all. Move the check after the leaf/non-leaf branch, alongside the other leaf-only checks, mirroring how the G_STAGE U-bit check (added in 9158c900ab30) is already correctly placed. Fixes: b795ea0ba471 ("hw/riscv/riscv-iommu.c: fault when !PTE_U and no priv access") Signed-off-by: Andrew Jones Reviewed-by: Daniel Henrique Barboza Reviewed-by: Nutty Liu Message-ID: <20260717112340.1071148-1-andrew.jones@oss.qualcomm.com> Signed-off-by: Alistair Francis --- hw/riscv/riscv-iommu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index f6865d1e16..ed9fb09f8b 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -476,13 +476,6 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, break; /* Invalid PTE */ } else if (pte & PTE_RESERVED(false)) { break; /* Reserved PTE bits set */ - } else if (!(pte & PTE_U) && !pv) { - /* - * All accesses are assumed to be User mode unless - * process_id is valid (pv). In case we have a - * non-user mode PTE and !pv we need to fault. - */ - break; } else if (!(pte & (PTE_R | PTE_W | PTE_X))) { base = PPN_PHYS(ppn); /* Inner PTE, continue walking */ } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) { @@ -491,6 +484,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, break; /* Reserved leaf PTE flags: PTE_W + PTE_X */ } else if (ppn & ((1ULL << (va_skip - TARGET_PAGE_BITS)) - 1)) { break; /* Misaligned PPN */ + } else if (!(pte & PTE_U) && !pv) { + /* + * All accesses are assumed to be User mode unless + * process_id is valid (pv). In case we have a + * non-user mode leaf PTE and !pv we need to fault. + */ + break; } else if ((iotlb->perm & IOMMU_RO) && !(pte & PTE_R)) { break; /* Read access check failed */ } else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) { From aa51eec004461f671f878145d3fc921c6cabee48 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 17 Jul 2026 16:45:25 +0200 Subject: [PATCH 514/627] hw/riscv/riscv-iommu: preserve requested perm in spa_fetch() b18e3f0e2d0f fixed spa_fetch() faults whose TTYP used the leaf PTE permission instead of the original request permission. However, it kept that request-narrowed value in iotlb->perm after a successful walk, and riscv_iommu_translate() caches iotlb->perm for later accesses to the same IOVA. That means a write to an RW mapping can cache the entry as write-only. A later read then hits the cache and faults even though the mapping allows it, which showed up in NVMe testing as bogus completions and controller timeouts. Keep the requested permission in a separate req_perm and use it for all permission checks and fault-type decisions. Accumulate the leaf permissions separately and copy them to iotlb->perm only after the full walk succeeds, so cached entries describe the mapping rather than the current request. Since faults leave iotlb->perm as the original request, the S-stage and G-stage TTYP fixes remain intact. Fixes: b18e3f0e2d0f ("hw/riscv/riscv-iommu.c: fix fault type for spa_fetch() faults") Signed-off-by: Andrew Jones Reviewed-by: Daniel Henrique Barboza Message-ID: <20260717144525.1154204-1-andrew.jones@oss.qualcomm.com> Signed-off-by: Alistair Francis --- hw/riscv/riscv-iommu.c | 50 ++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index ed9fb09f8b..323a041b4a 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -281,7 +281,7 @@ static hwaddr riscv_iommu_napot_page_mask(hwaddr ppn, hwaddr addr, hwaddr *out) static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, IOMMUTLBEntry *iotlb) { - IOMMUAccessFlags pte_perm; + IOMMUAccessFlags trans_perm = IOMMU_NONE; dma_addr_t addr, base; uint64_t satp, gatp, pte; bool en_s, en_g; @@ -298,6 +298,14 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, } pass; MemTxResult ret; bool pv = !!ctx->process_id; + /* + * Keep the request permission separate from iotlb->perm. G-stage + * walks translate S-stage PTE addresses before the real leaf is + * reached, but permission checks and fault types must still use the + * original request. A successful walk leaves iotlb->perm with the + * effective leaf permission for the translation cache. + */ + const IOMMUAccessFlags req_perm = iotlb->perm; satp = get_field(ctx->satp, RISCV_IOMMU_ATP_MODE_FIELD); gatp = get_field(ctx->gatp, RISCV_IOMMU_ATP_MODE_FIELD); @@ -316,7 +324,7 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, * means we can't do an early MSI check unless we have * strictly !en_s. */ - if (!en_s && (iotlb->perm & IOMMU_WO) && + if (!en_s && (req_perm & IOMMU_WO) && riscv_iommu_msi_check(s, ctx, iotlb->iova)) { iotlb->target_as = &s->trap_as; iotlb->translated_addr = iotlb->iova; @@ -434,13 +442,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, masked_msbs = (addr >> (va_len - 1)) & mask; if (masked_msbs != 0 && masked_msbs != mask) { - return (iotlb->perm & IOMMU_WO) ? + return (req_perm & IOMMU_WO) ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S : RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S; } } else { if ((addr & va_mask) != addr) { - return (iotlb->perm & IOMMU_WO) ? + return (req_perm & IOMMU_WO) ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS : RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS; } @@ -465,8 +473,8 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, MEMTXATTRS_UNSPECIFIED); } if (ret != MEMTX_OK) { - return (iotlb->perm & IOMMU_WO) ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT - : RISCV_IOMMU_FQ_CAUSE_RD_FAULT; + return (req_perm & IOMMU_WO) ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT + : RISCV_IOMMU_FQ_CAUSE_RD_FAULT; } sc[pass].step++; @@ -491,13 +499,13 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, * non-user mode leaf PTE and !pv we need to fault. */ break; - } else if ((iotlb->perm & IOMMU_RO) && !(pte & PTE_R)) { + } else if ((req_perm & IOMMU_RO) && !(pte & PTE_R)) { break; /* Read access check failed */ - } else if ((iotlb->perm & IOMMU_WO) && !(pte & PTE_W)) { + } else if ((req_perm & IOMMU_WO) && !(pte & PTE_W)) { break; /* Write access check failed */ } else if (!ade && !(pte & PTE_A)) { break; /* Access bit not set */ - } else if ((iotlb->perm & IOMMU_WO) && !ade && !(pte & PTE_D)) { + } else if ((req_perm & IOMMU_WO) && !ade && !(pte & PTE_D)) { break; /* Dirty bit not set */ } else if (pass == G_STAGE && !(pte & PTE_U)) { /* @@ -532,21 +540,20 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, addr = iotlb->iova; continue; } + + /* Cache the effective permission, not this request's subset. */ + IOMMUAccessFlags leaf_perm = (pte & PTE_W) ? + ((pte & PTE_R) ? IOMMU_RW : IOMMU_WO) : + IOMMU_RO; + + trans_perm = trans_perm == IOMMU_NONE ? + leaf_perm : trans_perm & leaf_perm; + /* Translation phase completed (GPA or SPA) */ iotlb->translated_addr = base; - /* - * Do a bit_and between the PTE bits and the original - * request flags to determine the exact permission we - * need, i.e. if the original request is RO and the - * PTE has RW flags the actual perm is RO. - */ - pte_perm = (pte & PTE_W) ? ((pte & PTE_R) ? IOMMU_RW : IOMMU_WO) - : IOMMU_RO; - iotlb->perm &= pte_perm; - /* Check MSI GPA address match */ - if (pass == S_STAGE && (iotlb->perm & IOMMU_WO) && + if (pass == S_STAGE && (req_perm & IOMMU_WO) && riscv_iommu_msi_check(s, ctx, base)) { /* Trap MSI writes and return GPA address. */ iotlb->target_as = &s->trap_as; @@ -563,6 +570,7 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, continue; } + iotlb->perm = trans_perm; return 0; } @@ -587,7 +595,7 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx, */ iotlb->translated_addr = addr; - return (iotlb->perm & IOMMU_WO) ? + return (req_perm & IOMMU_WO) ? (pass ? RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS : RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S) : (pass ? RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS : From bd1ee9ab3c39f269d8bea8acf83ea833a69a6e10 Mon Sep 17 00:00:00 2001 From: A-Shehab Date: Sun, 26 Jul 2026 11:05:37 +0300 Subject: [PATCH 515/627] target/riscv: allow menvcfg/henvcfg LPE and SSE bits on RV32 The Zicfilp landing-pad enable (LPE, bit 2) and Zicfiss shadow-stack enable (SSE, bit 3) controls live in the low 32 bits of menvcfg and henvcfg, and the CFI specification defines them for both RV32 and RV64. QEMU only adds MENVCFG_LPE/MENVCFG_SSE (and the henvcfg equivalents) to the writable mask inside the "riscv_cpu_mxl(env) == MXL_RV64" block, so on RV32 these bits are silently dropped and the features cannot be enabled. This is inconsistent with write_senvcfg(), which already handles SENVCFG_LPE/SENVCFG_SSE regardless of MXLEN. Hoist the LPE/SSE mask handling out of the RV64-only block in write_menvcfg() and write_henvcfg() so the bits become writable on RV32 as well. The upper-half writers (write_menvcfgh/write_henvcfgh) are unaffected because these bits reside in the low 32 bits. Reproducible on qemu-system-riscv32 -cpu rv32,zicfilp=true,zicfiss=true: an M-mode write of menvcfg.{LPE,SSE} reads back as zero, while the same program on rv64 keeps the bits set. Fixes: 4923f672e3d7 ("target/riscv: Introduce elp state and enabling controls for zicfilp") Fixes: 8205bc127a83 ("target/riscv: introduce ssp and enabling controls for zicfiss") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4045 Signed-off-by: A-Shehab Reviewed-by: Daniel Henrique Barboza Message-ID: <20260726080537.13913-1-ahshehab24@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/csr.c | 45 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index a90449b87f..ffd751caa5 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -3221,6 +3221,19 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, MENVCFG_CBZE; bool stce_changed = false; + /* + * menvcfg.LPE (Zicfilp) and menvcfg.SSE (Zicfiss) reside in the low + * 32 bits and are defined for both RV32 and RV64, so they must be + * writable regardless of MXLEN. + */ + if (cfg->ext_zicfilp) { + mask |= MENVCFG_LPE; + } + + if (cfg->ext_zicfiss) { + mask |= MENVCFG_SSE; + } + if (riscv_cpu_mxl(env) == MXL_RV64) { mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | (cfg->ext_sstc ? MENVCFG_STCE : 0) | @@ -3228,14 +3241,6 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, (cfg->ext_svadu ? MENVCFG_ADUE : 0) | (cfg->ext_ssdbltrp ? MENVCFG_DTE : 0); - if (env_archcpu(env)->cfg.ext_zicfilp) { - mask |= MENVCFG_LPE; - } - - if (env_archcpu(env)->cfg.ext_zicfiss) { - mask |= MENVCFG_SSE; - } - /* Update PMM field only if the value is valid according to Zjpm v1.0 */ if (env_archcpu(env)->cfg.ext_smnpm && get_field(val, MENVCFG_PMM) != PMM_FIELD_RESERVED) { @@ -3383,20 +3388,24 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno, return ret; } + /* + * henvcfg.LPE (Zicfilp) and henvcfg.SSE (Zicfiss) reside in the low + * 32 bits and are defined for both RV32 and RV64, so they must be + * writable regardless of MXLEN. + */ + if (cfg->ext_zicfilp) { + mask |= HENVCFG_LPE; + } + + /* H can light up SSE for VS only if HS had it from menvcfg */ + if (cfg->ext_zicfiss && get_field(env->menvcfg, MENVCFG_SSE)) { + mask |= HENVCFG_SSE; + } + if (riscv_cpu_mxl(env) == MXL_RV64) { mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE | HENVCFG_DTE); - if (env_archcpu(env)->cfg.ext_zicfilp) { - mask |= HENVCFG_LPE; - } - - /* H can light up SSE for VS only if HS had it from menvcfg */ - if (env_archcpu(env)->cfg.ext_zicfiss && - get_field(env->menvcfg, MENVCFG_SSE)) { - mask |= HENVCFG_SSE; - } - /* Update PMM field only if the value is valid according to Zjpm v1.0 */ if (env_archcpu(env)->cfg.ext_ssnpm && get_field(val, HENVCFG_PMM) != PMM_FIELD_RESERVED) { From df975586d89f59c93c944815c69bef188bbde572 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:51 -0700 Subject: [PATCH 516/627] disas/riscv: Move operand extractors earlier in file Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-2-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 790 +++++++++++++++++++++++++------------------------- 1 file changed, 395 insertions(+), 395 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 2ba0a6a73a..e3fbc26626 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1259,6 +1259,401 @@ static const rv_comp_data rvcp_fsgnjx_q[] = { { rv_op_illegal, NULL } }; +/* operand extractors */ + +static uint32_t operand_rd(rv_inst inst) +{ + return extract32(inst, 7, 5); +} + +static uint32_t operand_rs1(rv_inst inst) +{ + return extract32(inst, 15, 5); +} + +static uint32_t operand_rs2(rv_inst inst) +{ + return extract32(inst, 20, 5); +} + +static uint32_t operand_rs3(rv_inst inst) +{ + return extract32(inst, 27, 5); +} + +static uint32_t operand_aq(rv_inst inst) +{ + return extract32(inst, 26, 1); +} + +static uint32_t operand_rl(rv_inst inst) +{ + return extract32(inst, 25, 1); +} + +static uint32_t operand_pred(rv_inst inst) +{ + return extract32(inst, 24, 4); +} + +static uint32_t operand_succ(rv_inst inst) +{ + return extract32(inst, 20, 4); +} + +static uint32_t operand_rm(rv_inst inst) +{ + return extract32(inst, 12, 3); +} + +static uint32_t operand_shamt5(rv_inst inst) +{ + return extract32(inst, 20, 5); +} + +static uint32_t operand_shamt6(rv_inst inst) +{ + return extract32(inst, 20, 6); +} + +static uint32_t operand_shamt7(rv_inst inst) +{ + return extract32(inst, 20, 7); +} + +static uint32_t operand_crdq(rv_inst inst) +{ + return extract32(inst, 2, 3); +} + +static uint32_t operand_crs1q(rv_inst inst) +{ + return extract32(inst, 7, 3); +} + +static uint32_t operand_crs1rdq(rv_inst inst) +{ + return extract32(inst, 7, 3); +} + +static uint32_t operand_crs2q(rv_inst inst) +{ + return extract32(inst, 2, 3); +} + +static uint32_t calculate_xreg(uint32_t sreg) +{ + return sreg < 2 ? sreg + 8 : sreg + 16; +} + +static uint32_t operand_sreg1(rv_inst inst) +{ + return calculate_xreg(extract32(inst, 7, 3)); +} + +static uint32_t operand_sreg2(rv_inst inst) +{ + return calculate_xreg(extract32(inst, 2, 3)); +} + +static uint32_t operand_crd(rv_inst inst) +{ + return extract32(inst, 7, 5); +} + +static uint32_t operand_crs1(rv_inst inst) +{ + return extract32(inst, 7, 5); +} + +static uint32_t operand_crs1rd(rv_inst inst) +{ + return extract32(inst, 7, 5); +} + +static uint32_t operand_crs2(rv_inst inst) +{ + return extract32(inst, 2, 5); +} + +static uint32_t operand_cimmsh5(rv_inst inst) +{ + return extract32(inst, 2, 5); +} + +static uint32_t operand_csr12(rv_inst inst) +{ + return extract32(inst, 20, 12); +} + +static int32_t operand_imm12(rv_inst inst) +{ + return sextract32(inst, 20, 12); +} + +static int32_t operand_imm20(rv_inst inst) +{ + return sextract32(inst, 12, 20) << 12; +} + +static int32_t operand_jimm20(rv_inst inst) +{ + return sextract32(inst, 31, 1) << 20 | + extract32(inst, 21, 10) << 1 | + extract32(inst, 20, 1) << 11 | + extract32(inst, 12, 8) << 12; +} + +static int32_t operand_simm12(rv_inst inst) +{ + return sextract32(inst, 25, 7) << 5 | + extract32(inst, 7, 5); +} + +static int32_t operand_sbimm12(rv_inst inst) +{ + return sextract32(inst, 31, 1) << 12 | + extract32(inst, 25, 6) << 5 | + extract32(inst, 8, 4) << 1 | + extract32(inst, 7, 1) << 11; +} + +static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) +{ + int imm = extract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); + if (isa == rv128) { + imm = imm ? imm : 64; + } + return imm; +} + +static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) +{ + int imm = extract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); + if (isa == rv128) { + imm = imm | (imm & 32) << 1; + imm = imm ? imm : 64; + } + return imm; +} + +static int32_t operand_cimmi(rv_inst inst) +{ + return sextract32(inst, 12, 1) << 5 | + extract32(inst, 2, 5); +} + +static int32_t operand_cimmui(rv_inst inst) +{ + return sextract32(inst, 12, 1) << 17 | + extract32(inst, 2, 5) << 12; +} + +static uint32_t operand_cimmlwsp(rv_inst inst) +{ + return extract32(inst, 12, 1) << 5 | + extract32(inst, 4, 3) << 2 | + extract32(inst, 2, 2) << 6; +} + +static uint32_t operand_cimmldsp(rv_inst inst) +{ + return extract32(inst, 12, 1) << 5 | + extract32(inst, 5, 2) << 3 | + extract32(inst, 2, 3) << 6; +} + +static uint32_t operand_cimmlqsp(rv_inst inst) +{ + return extract32(inst, 12, 1) << 5 | + extract32(inst, 6, 1) << 4 | + extract32(inst, 2, 4) << 6; +} + +static int32_t operand_cimm16sp(rv_inst inst) +{ + return sextract32(inst, 12, 1) << 9 | + extract32(inst, 6, 1) << 4 | + extract32(inst, 5, 1) << 6 | + extract32(inst, 3, 2) << 7 | + extract32(inst, 2, 1) << 5; +} + +static int32_t operand_cimmj(rv_inst inst) +{ + return sextract32(inst, 12, 1) << 11 | + extract32(inst, 11, 1) << 4 | + extract32(inst, 9, 2) << 8 | + extract32(inst, 8, 1) << 10 | + extract32(inst, 7, 1) << 6 | + extract32(inst, 6, 1) << 7 | + extract32(inst, 3, 3) << 1 | + extract32(inst, 2, 1) << 5; +} + +static int32_t operand_cimmb(rv_inst inst) +{ + return sextract32(inst, 12, 1) << 8 | + extract32(inst, 10, 2) << 3 | + extract32(inst, 5, 2) << 6 | + extract32(inst, 3, 2) << 1 | + extract32(inst, 2, 1) << 5; +} + +static uint32_t operand_cimmswsp(rv_inst inst) +{ + return extract32(inst, 9, 4) << 2 | + extract32(inst, 7, 2) << 6; +} + +static uint32_t operand_cimmsdsp(rv_inst inst) +{ + return extract32(inst, 10, 3) << 3 | + extract32(inst, 7, 3) << 6; +} + +static uint32_t operand_cimmsqsp(rv_inst inst) +{ + return extract32(inst, 11, 2) << 4 | + extract32(inst, 7, 4) << 6; +} + +static uint32_t operand_cimm4spn(rv_inst inst) +{ + return extract32(inst, 11, 2) << 4 | + extract32(inst, 7, 4) << 6 | + extract32(inst, 6, 1) << 2 | + extract32(inst, 5, 1) << 3; +} + +static uint32_t operand_cimmw(rv_inst inst) +{ + return extract32(inst, 10, 3) << 3 | + extract32(inst, 6, 1) << 2 | + extract32(inst, 5, 1) << 6; +} + +static uint32_t operand_cimmd(rv_inst inst) +{ + return extract32(inst, 10, 3) << 3 | + extract32(inst, 5, 2) << 6; +} + +static uint32_t operand_cimmq(rv_inst inst) +{ + return extract32(inst, 11, 2) << 4 | + extract32(inst, 10, 1) << 8 | + extract32(inst, 5, 2) << 6; +} + +static int32_t operand_vimm(rv_inst inst) +{ + return sextract32(inst, 15, 5); +} + +static uint32_t operand_vuimm(rv_inst inst) +{ + return extract32(inst, 15, 5); +} + +static uint32_t operand_vzimm11(rv_inst inst) +{ + return extract32(inst, 20, 11); +} + +static uint32_t operand_vzimm10(rv_inst inst) +{ + return extract32(inst, 20, 10); +} + +static uint32_t operand_vzimm6(rv_inst inst) +{ + return extract32(inst, 26, 1) << 5 | + extract32(inst, 15, 5); +} + +static uint32_t operand_bs(rv_inst inst) +{ + return extract32(inst, 30, 2); +} + +static uint32_t operand_rnum(rv_inst inst) +{ + return extract32(inst, 20, 4); +} + +static uint32_t operand_vm(rv_inst inst) +{ + return extract32(inst, 25, 1); +} + +static uint32_t operand_uimm_c_lb(rv_inst inst) +{ + return extract32(inst, 5, 1) << 1 | + extract32(inst, 6, 1); +} + +static uint32_t operand_uimm_c_lh(rv_inst inst) +{ + return extract32(inst, 5, 1) << 1; +} + +static uint32_t operand_zcmp_spimm(rv_inst inst) +{ + return extract32(inst, 2, 2) << 4; +} + +static uint32_t operand_zcmp_rlist(rv_inst inst) +{ + return extract32(inst, 4, 4); +} + +static uint32_t operand_imm6(rv_inst inst) +{ + return extract32(inst, 20, 6); +} + +static uint32_t operand_imm2(rv_inst inst) +{ + return extract32(inst, 25, 2); +} + +static uint32_t operand_immh(rv_inst inst) +{ + return extract32(inst, 26, 6); +} + +static uint32_t operand_imml(rv_inst inst) +{ + return extract32(inst, 20, 6); +} + +static uint32_t calculate_stack_adj(rv_isa isa, uint32_t rlist, uint32_t spimm) +{ + int xlen_bytes_log2 = isa == rv64 ? 3 : 2; + int regs = rlist == 15 ? 13 : rlist - 3; + uint32_t stack_adj_base = ROUND_UP(regs << xlen_bytes_log2, 16); + return stack_adj_base + spimm; +} + +static uint32_t operand_zcmp_stack_adj(rv_inst inst, rv_isa isa) +{ + return calculate_stack_adj(isa, operand_zcmp_rlist(inst), + operand_zcmp_spimm(inst)); +} + +static uint32_t operand_tbl_index(rv_inst inst) +{ + return extract32(inst, 2, 8); +} + +static uint32_t operand_lpl(rv_inst inst) +{ + return extract32(inst, 12, 20); +} + /* instruction metadata */ const rv_opcode_data rvi_opcode_data[] = { @@ -4198,401 +4593,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) dec->op = op; } -/* operand extractors */ - -static uint32_t operand_rd(rv_inst inst) -{ - return extract32(inst, 7, 5); -} - -static uint32_t operand_rs1(rv_inst inst) -{ - return extract32(inst, 15, 5); -} - -static uint32_t operand_rs2(rv_inst inst) -{ - return extract32(inst, 20, 5); -} - -static uint32_t operand_rs3(rv_inst inst) -{ - return extract32(inst, 27, 5); -} - -static uint32_t operand_aq(rv_inst inst) -{ - return extract32(inst, 26, 1); -} - -static uint32_t operand_rl(rv_inst inst) -{ - return extract32(inst, 25, 1); -} - -static uint32_t operand_pred(rv_inst inst) -{ - return extract32(inst, 24, 4); -} - -static uint32_t operand_succ(rv_inst inst) -{ - return extract32(inst, 20, 4); -} - -static uint32_t operand_rm(rv_inst inst) -{ - return extract32(inst, 12, 3); -} - -static uint32_t operand_shamt5(rv_inst inst) -{ - return extract32(inst, 20, 5); -} - -static uint32_t operand_shamt6(rv_inst inst) -{ - return extract32(inst, 20, 6); -} - -static uint32_t operand_shamt7(rv_inst inst) -{ - return extract32(inst, 20, 7); -} - -static uint32_t operand_crdq(rv_inst inst) -{ - return extract32(inst, 2, 3); -} - -static uint32_t operand_crs1q(rv_inst inst) -{ - return extract32(inst, 7, 3); -} - -static uint32_t operand_crs1rdq(rv_inst inst) -{ - return extract32(inst, 7, 3); -} - -static uint32_t operand_crs2q(rv_inst inst) -{ - return extract32(inst, 2, 3); -} - -static uint32_t calculate_xreg(uint32_t sreg) -{ - return sreg < 2 ? sreg + 8 : sreg + 16; -} - -static uint32_t operand_sreg1(rv_inst inst) -{ - return calculate_xreg(extract32(inst, 7, 3)); -} - -static uint32_t operand_sreg2(rv_inst inst) -{ - return calculate_xreg(extract32(inst, 2, 3)); -} - -static uint32_t operand_crd(rv_inst inst) -{ - return extract32(inst, 7, 5); -} - -static uint32_t operand_crs1(rv_inst inst) -{ - return extract32(inst, 7, 5); -} - -static uint32_t operand_crs1rd(rv_inst inst) -{ - return extract32(inst, 7, 5); -} - -static uint32_t operand_crs2(rv_inst inst) -{ - return extract32(inst, 2, 5); -} - -static uint32_t operand_cimmsh5(rv_inst inst) -{ - return extract32(inst, 2, 5); -} - -static uint32_t operand_csr12(rv_inst inst) -{ - return extract32(inst, 20, 12); -} - -static int32_t operand_imm12(rv_inst inst) -{ - return sextract32(inst, 20, 12); -} - -static int32_t operand_imm20(rv_inst inst) -{ - return sextract32(inst, 12, 20) << 12; -} - -static int32_t operand_jimm20(rv_inst inst) -{ - return sextract32(inst, 31, 1) << 20 | - extract32(inst, 21, 10) << 1 | - extract32(inst, 20, 1) << 11 | - extract32(inst, 12, 8) << 12; -} - -static int32_t operand_simm12(rv_inst inst) -{ - return sextract32(inst, 25, 7) << 5 | - extract32(inst, 7, 5); -} - -static int32_t operand_sbimm12(rv_inst inst) -{ - return sextract32(inst, 31, 1) << 12 | - extract32(inst, 25, 6) << 5 | - extract32(inst, 8, 4) << 1 | - extract32(inst, 7, 1) << 11; -} - -static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) -{ - int imm = extract32(inst, 12, 1) << 5 | - extract32(inst, 2, 5); - if (isa == rv128) { - imm = imm ? imm : 64; - } - return imm; -} - -static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) -{ - int imm = extract32(inst, 12, 1) << 5 | - extract32(inst, 2, 5); - if (isa == rv128) { - imm = imm | (imm & 32) << 1; - imm = imm ? imm : 64; - } - return imm; -} - -static int32_t operand_cimmi(rv_inst inst) -{ - return sextract32(inst, 12, 1) << 5 | - extract32(inst, 2, 5); -} - -static int32_t operand_cimmui(rv_inst inst) -{ - return sextract32(inst, 12, 1) << 17 | - extract32(inst, 2, 5) << 12; -} - -static uint32_t operand_cimmlwsp(rv_inst inst) -{ - return extract32(inst, 12, 1) << 5 | - extract32(inst, 4, 3) << 2 | - extract32(inst, 2, 2) << 6; -} - -static uint32_t operand_cimmldsp(rv_inst inst) -{ - return extract32(inst, 12, 1) << 5 | - extract32(inst, 5, 2) << 3 | - extract32(inst, 2, 3) << 6; -} - -static uint32_t operand_cimmlqsp(rv_inst inst) -{ - return extract32(inst, 12, 1) << 5 | - extract32(inst, 6, 1) << 4 | - extract32(inst, 2, 4) << 6; -} - -static int32_t operand_cimm16sp(rv_inst inst) -{ - return sextract32(inst, 12, 1) << 9 | - extract32(inst, 6, 1) << 4 | - extract32(inst, 5, 1) << 6 | - extract32(inst, 3, 2) << 7 | - extract32(inst, 2, 1) << 5; -} - -static int32_t operand_cimmj(rv_inst inst) -{ - return sextract32(inst, 12, 1) << 11 | - extract32(inst, 11, 1) << 4 | - extract32(inst, 9, 2) << 8 | - extract32(inst, 8, 1) << 10 | - extract32(inst, 7, 1) << 6 | - extract32(inst, 6, 1) << 7 | - extract32(inst, 3, 3) << 1 | - extract32(inst, 2, 1) << 5; -} - -static int32_t operand_cimmb(rv_inst inst) -{ - return sextract32(inst, 12, 1) << 8 | - extract32(inst, 10, 2) << 3 | - extract32(inst, 5, 2) << 6 | - extract32(inst, 3, 2) << 1 | - extract32(inst, 2, 1) << 5; -} - -static uint32_t operand_cimmswsp(rv_inst inst) -{ - return extract32(inst, 9, 4) << 2 | - extract32(inst, 7, 2) << 6; -} - -static uint32_t operand_cimmsdsp(rv_inst inst) -{ - return extract32(inst, 10, 3) << 3 | - extract32(inst, 7, 3) << 6; -} - -static uint32_t operand_cimmsqsp(rv_inst inst) -{ - return extract32(inst, 11, 2) << 4 | - extract32(inst, 7, 4) << 6; -} - -static uint32_t operand_cimm4spn(rv_inst inst) -{ - return extract32(inst, 11, 2) << 4 | - extract32(inst, 7, 4) << 6 | - extract32(inst, 6, 1) << 2 | - extract32(inst, 5, 1) << 3; -} - -static uint32_t operand_cimmw(rv_inst inst) -{ - return extract32(inst, 10, 3) << 3 | - extract32(inst, 6, 1) << 2 | - extract32(inst, 5, 1) << 6; -} - -static uint32_t operand_cimmd(rv_inst inst) -{ - return extract32(inst, 10, 3) << 3 | - extract32(inst, 5, 2) << 6; -} - -static uint32_t operand_cimmq(rv_inst inst) -{ - return extract32(inst, 11, 2) << 4 | - extract32(inst, 10, 1) << 8 | - extract32(inst, 5, 2) << 6; -} - -static int32_t operand_vimm(rv_inst inst) -{ - return sextract32(inst, 15, 5); -} - -static uint32_t operand_vuimm(rv_inst inst) -{ - return extract32(inst, 15, 5); -} - -static uint32_t operand_vzimm11(rv_inst inst) -{ - return extract32(inst, 20, 11); -} - -static uint32_t operand_vzimm10(rv_inst inst) -{ - return extract32(inst, 20, 10); -} - -static uint32_t operand_vzimm6(rv_inst inst) -{ - return extract32(inst, 26, 1) << 5 | - extract32(inst, 15, 5); -} - -static uint32_t operand_bs(rv_inst inst) -{ - return extract32(inst, 30, 2); -} - -static uint32_t operand_rnum(rv_inst inst) -{ - return extract32(inst, 20, 4); -} - -static uint32_t operand_vm(rv_inst inst) -{ - return extract32(inst, 25, 1); -} - -static uint32_t operand_uimm_c_lb(rv_inst inst) -{ - return extract32(inst, 5, 1) << 1 | - extract32(inst, 6, 1); -} - -static uint32_t operand_uimm_c_lh(rv_inst inst) -{ - return extract32(inst, 5, 1) << 1; -} - -static uint32_t operand_zcmp_spimm(rv_inst inst) -{ - return extract32(inst, 2, 2) << 4; -} - -static uint32_t operand_zcmp_rlist(rv_inst inst) -{ - return extract32(inst, 4, 4); -} - -static uint32_t operand_imm6(rv_inst inst) -{ - return extract32(inst, 20, 6); -} - -static uint32_t operand_imm2(rv_inst inst) -{ - return extract32(inst, 25, 2); -} - -static uint32_t operand_immh(rv_inst inst) -{ - return extract32(inst, 26, 6); -} - -static uint32_t operand_imml(rv_inst inst) -{ - return extract32(inst, 20, 6); -} - -static uint32_t calculate_stack_adj(rv_isa isa, uint32_t rlist, uint32_t spimm) -{ - int xlen_bytes_log2 = isa == rv64 ? 3 : 2; - int regs = rlist == 15 ? 13 : rlist - 3; - uint32_t stack_adj_base = ROUND_UP(regs << xlen_bytes_log2, 16); - return stack_adj_base + spimm; -} - -static uint32_t operand_zcmp_stack_adj(rv_inst inst, rv_isa isa) -{ - return calculate_stack_adj(isa, operand_zcmp_rlist(inst), - operand_zcmp_spimm(inst)); -} - -static uint32_t operand_tbl_index(rv_inst inst) -{ - return extract32(inst, 2, 8); -} - -static uint32_t operand_lpl(rv_inst inst) -{ - return extract32(inst, 12, 20); -} - /* decode operands */ static void decode_inst_operands(rv_decode *dec, rv_isa isa) From 21aa81318d2f8f55f9dcd96aca7ba3eb53844ea0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:52 -0700 Subject: [PATCH 517/627] disas/riscv: Reduce rv_insn to uint32_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 758dce9c98a, the only possible values for instruction length are 2 and 4. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-3-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 12 +++--------- disas/riscv.h | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index e3fbc26626..012f90fce6 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5491,10 +5491,8 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, return format_inst(24, &dec); } -#define INST_FMT_2 "%04" PRIx64 " " -#define INST_FMT_4 "%08" PRIx64 " " -#define INST_FMT_6 "%012" PRIx64 " " -#define INST_FMT_8 "%016" PRIx64 " " +#define INST_FMT_2 "%04x " +#define INST_FMT_4 "%08x " static int print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa) @@ -5530,12 +5528,8 @@ print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa) case 4: (*info->fprintf_func)(info->stream, INST_FMT_4, inst); break; - case 6: - (*info->fprintf_func)(info->stream, INST_FMT_6, inst); - break; default: - (*info->fprintf_func)(info->stream, INST_FMT_8, inst); - break; + g_assert_not_reached(); } } diff --git a/disas/riscv.h b/disas/riscv.h index 91ada8b531..eabe193b4f 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -11,7 +11,7 @@ /* types */ -typedef uint64_t rv_inst; +typedef uint32_t rv_inst; typedef uint16_t rv_opcode; /* enums */ From fcb7ec69d85e947b6a66b3f7891816dc53670fd5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:53 -0700 Subject: [PATCH 518/627] disas/riscv: Tidy dec initialization in disasm_inst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-4-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 012f90fce6..986dc6b752 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5441,10 +5441,11 @@ static void decode_inst_decompress(rv_decode *dec, rv_isa isa) static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, const RISCVCPUConfig *cfg) { - rv_decode dec = { 0 }; - dec.pc = pc; - dec.inst = inst; - dec.cfg = cfg; + rv_decode dec = { + .pc = pc, + .inst = inst, + .cfg = cfg, + }; static const struct { bool (*guard_func)(const RISCVCPUConfig *); From 2d64d3a6a1404f2f09c0d43ce715cd4b001f8f26 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:54 -0700 Subject: [PATCH 519/627] disas/riscv: Pass rv_opcode_data pointer to decode_inst_operands Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-5-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 986dc6b752..af43940732 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -4595,11 +4595,12 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) /* decode operands */ -static void decode_inst_operands(rv_decode *dec, rv_isa isa) +static void decode_inst_operands(rv_decode *dec, rv_isa isa, + const rv_opcode_data *op) { - const rv_opcode_data *opcode_data = dec->opcode_data; rv_inst inst = dec->inst; - dec->codec = opcode_data[dec->op].codec; + + dec->codec = op->codec; switch (dec->codec) { case rv_codec_none: dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; @@ -5468,6 +5469,8 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, { has_xlrbr_p, rv_xlrbr_opcode_data, decode_xlrbr }, }; + const rv_opcode_data *op; + for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { bool (*guard_func)(const RISCVCPUConfig *) = decoders[i].guard_func; const rv_opcode_data *opcode_data = decoders[i].opcode_data; @@ -5486,7 +5489,8 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, dec.opcode_data = rvi_opcode_data; } - decode_inst_operands(&dec, isa); + op = &dec.opcode_data[dec.op]; + decode_inst_operands(&dec, isa, op); decode_inst_decompress(&dec, isa); decode_inst_lift_pseudo(&dec); return format_inst(24, &dec); From 3d3abbb1469756811f50811aca27883e30d00ac6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:55 -0700 Subject: [PATCH 520/627] disas/riscv: Pass rv_opcode_data pointer to/from decode_inst_decompress Unify 4 functions, sharing code. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-6-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 70 ++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index af43940732..47fae7316c 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5377,64 +5377,36 @@ static void decode_inst_lift_pseudo(rv_decode *dec) /* decompress instruction */ -static void decode_inst_decompress_rv32(rv_decode *dec) +static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, rv_isa isa, + const rv_opcode_data *op) { - const rv_opcode_data *opcode_data = dec->opcode_data; - int decomp_op = opcode_data[dec->op].decomp_rv32; - if (decomp_op != rv_op_illegal) { - if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) - && dec->imm == 0) { - dec->op = rv_op_illegal; - } else { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; - } - } -} + int decomp_op; -static void decode_inst_decompress_rv64(rv_decode *dec) -{ - const rv_opcode_data *opcode_data = dec->opcode_data; - int decomp_op = opcode_data[dec->op].decomp_rv64; - if (decomp_op != rv_op_illegal) { - if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) - && dec->imm == 0) { - dec->op = rv_op_illegal; - } else { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; - } - } -} - -static void decode_inst_decompress_rv128(rv_decode *dec) -{ - const rv_opcode_data *opcode_data = dec->opcode_data; - int decomp_op = opcode_data[dec->op].decomp_rv128; - if (decomp_op != rv_op_illegal) { - if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz) - && dec->imm == 0) { - dec->op = rv_op_illegal; - } else { - dec->op = decomp_op; - dec->codec = opcode_data[decomp_op].codec; - } - } -} - -static void decode_inst_decompress(rv_decode *dec, rv_isa isa) -{ switch (isa) { case rv32: - decode_inst_decompress_rv32(dec); + decomp_op = op->decomp_rv32; break; case rv64: - decode_inst_decompress_rv64(dec); + decomp_op = op->decomp_rv64; break; case rv128: - decode_inst_decompress_rv128(dec); + decomp_op = op->decomp_rv128; break; + default: + g_assert_not_reached(); } + + if (decomp_op != rv_op_illegal) { + if ((op->decomp_data & rvcd_imm_nz) && dec->imm == 0) { + dec->opcode_data = rvi_opcode_data; + dec->op = rv_op_illegal; + } else { + dec->op = decomp_op; + } + op = &dec->opcode_data[decomp_op]; + dec->codec = op->codec; + } + return op; } /* disassemble instruction */ @@ -5491,7 +5463,7 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, op = &dec.opcode_data[dec.op]; decode_inst_operands(&dec, isa, op); - decode_inst_decompress(&dec, isa); + op = decode_inst_decompress(&dec, isa, op); decode_inst_lift_pseudo(&dec); return format_inst(24, &dec); } From f8bc5f5635f67dc21919454bdca4a9f917e5337d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:56 -0700 Subject: [PATCH 521/627] disas/riscv: Pass rv_opcode_data pointer to/from decode_inst_lift_pseudo Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-7-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 47fae7316c..0be2f07612 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5358,21 +5358,22 @@ static GString *format_inst(size_t tab, rv_decode *dec) /* lift instruction to pseudo-instruction */ -static void decode_inst_lift_pseudo(rv_decode *dec) +static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, + const rv_opcode_data *op) { - const rv_opcode_data *opcode_data = dec->opcode_data; - const rv_comp_data *comp_data = opcode_data[dec->op].pseudo; - if (!comp_data) { - return; - } - while (comp_data->constraints) { - if (check_constraints(dec, comp_data->constraints)) { - dec->op = comp_data->op; - dec->codec = opcode_data[dec->op].codec; - return; + const rv_comp_data *comp_data = op->pseudo; + if (comp_data) { + while (comp_data->constraints) { + if (check_constraints(dec, comp_data->constraints)) { + dec->op = comp_data->op; + op = &dec->opcode_data[dec->op]; + dec->codec = op->codec; + break; + } + comp_data++; } - comp_data++; } + return op; } /* decompress instruction */ @@ -5464,7 +5465,7 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, op = &dec.opcode_data[dec.op]; decode_inst_operands(&dec, isa, op); op = decode_inst_decompress(&dec, isa, op); - decode_inst_lift_pseudo(&dec); + op = decode_inst_lift_pseudo(&dec, op); return format_inst(24, &dec); } From 7276d0fbe60d1c757ee75a52a2c33b1835b13a73 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:57 -0700 Subject: [PATCH 522/627] disas/riscv: Pass rv_opcode_data pointer to format_inst Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-8-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 0be2f07612..70ea41f125 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5111,17 +5111,16 @@ static size_t inst_length(rv_inst inst) /* format instruction */ -static GString *format_inst(size_t tab, rv_decode *dec) +static GString *format_inst(size_t tab, rv_decode *dec, + const rv_opcode_data *op) { - const rv_opcode_data *opcode_data = dec->opcode_data; GString *buf = g_string_sized_new(64); - const char *fmt; + const char *fmt = op->format; - fmt = opcode_data[dec->op].format; while (*fmt) { switch (*fmt) { case 'O': - g_string_append(buf, opcode_data[dec->op].name); + g_string_append(buf, op->name); break; case '(': case ',': @@ -5466,7 +5465,7 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, decode_inst_operands(&dec, isa, op); op = decode_inst_decompress(&dec, isa, op); op = decode_inst_lift_pseudo(&dec, op); - return format_inst(24, &dec); + return format_inst(24, &dec, op); } #define INST_FMT_2 "%04x " From aae0ef66d463f9dd47624d249f975904a1ff2c0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:58 -0700 Subject: [PATCH 523/627] disas/riscv: Tidy disasm_inst main loop Unroll first iteration, so that always_true_p is not used, Drop some local variables and use 'decoders' directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-9-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 63 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 70ea41f125..9880b8de20 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5419,41 +5419,40 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, .inst = inst, .cfg = cfg, }; - - static const struct { - bool (*guard_func)(const RISCVCPUConfig *); - const rv_opcode_data *opcode_data; - void (*decode_func)(rv_decode *, rv_isa); - } decoders[] = { - { always_true_p, rvi_opcode_data, decode_inst_opcode }, - { has_xtheadba_p, xthead_opcode_data, decode_xtheadba }, - { has_xtheadbb_p, xthead_opcode_data, decode_xtheadbb }, - { has_xtheadbs_p, xthead_opcode_data, decode_xtheadbs }, - { has_xtheadcmo_p, xthead_opcode_data, decode_xtheadcmo }, - { has_xtheadcondmov_p, xthead_opcode_data, decode_xtheadcondmov }, - { has_xtheadfmemidx_p, xthead_opcode_data, decode_xtheadfmemidx }, - { has_xtheadfmv_p, xthead_opcode_data, decode_xtheadfmv }, - { has_xtheadmac_p, xthead_opcode_data, decode_xtheadmac }, - { has_xtheadmemidx_p, xthead_opcode_data, decode_xtheadmemidx }, - { has_xtheadmempair_p, xthead_opcode_data, decode_xtheadmempair }, - { has_xtheadsync_p, xthead_opcode_data, decode_xtheadsync }, - { has_XVentanaCondOps_p, ventana_opcode_data, decode_xventanacondops }, - { has_xlrbr_p, rv_xlrbr_opcode_data, decode_xlrbr }, - }; - const rv_opcode_data *op; - for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { - bool (*guard_func)(const RISCVCPUConfig *) = decoders[i].guard_func; - const rv_opcode_data *opcode_data = decoders[i].opcode_data; - void (*decode_func)(rv_decode *, rv_isa) = decoders[i].decode_func; + dec.opcode_data = rvi_opcode_data; + decode_inst_opcode(&dec, isa); - /* always_true_p don't dereference cfg */ - if (((i == 0) || cfg) && guard_func(cfg)) { - dec.opcode_data = opcode_data; - decode_func(&dec, isa); - if (dec.op != rv_op_illegal) - break; + if (dec.op == rv_op_illegal && cfg) { + static const struct { + bool (*guard_func)(const RISCVCPUConfig *); + const rv_opcode_data *opcode_data; + void (*decode_func)(rv_decode *, rv_isa); + } decoders[] = { + { has_xtheadba_p, xthead_opcode_data, decode_xtheadba }, + { has_xtheadbb_p, xthead_opcode_data, decode_xtheadbb }, + { has_xtheadbs_p, xthead_opcode_data, decode_xtheadbs }, + { has_xtheadcmo_p, xthead_opcode_data, decode_xtheadcmo }, + { has_xtheadcondmov_p, xthead_opcode_data, decode_xtheadcondmov }, + { has_xtheadfmemidx_p, xthead_opcode_data, decode_xtheadfmemidx }, + { has_xtheadfmv_p, xthead_opcode_data, decode_xtheadfmv }, + { has_xtheadmac_p, xthead_opcode_data, decode_xtheadmac }, + { has_xtheadmemidx_p, xthead_opcode_data, decode_xtheadmemidx }, + { has_xtheadmempair_p, xthead_opcode_data, decode_xtheadmempair }, + { has_xtheadsync_p, xthead_opcode_data, decode_xtheadsync }, + { has_XVentanaCondOps_p, ventana_opcode_data, decode_xventanacondops }, + { has_xlrbr_p, rv_xlrbr_opcode_data, decode_xlrbr }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { + if (decoders[i].guard_func(cfg)) { + dec.opcode_data = decoders[i].opcode_data; + decoders[i].decode_func(&dec, isa); + if (dec.op != rv_op_illegal) { + break; + } + } } } From 42031f21f9c8ee999dc6a1b1589a753df47bde37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:30:59 -0700 Subject: [PATCH 524/627] disas/riscv: Set dec->opcode_data in decode function This allows each opcode table to be private to the decode file. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-10-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xlrbr.c | 4 +++- disas/riscv-xlrbr.h | 2 -- disas/riscv-xthead.c | 13 ++++++++++++- disas/riscv-xthead.h | 2 -- disas/riscv-xventana.c | 3 ++- disas/riscv-xventana.h | 2 -- disas/riscv.c | 34 +++++++++++++++++----------------- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/disas/riscv-xlrbr.c b/disas/riscv-xlrbr.c index 57cb434523..f61028fce9 100644 --- a/disas/riscv-xlrbr.c +++ b/disas/riscv-xlrbr.c @@ -24,7 +24,7 @@ typedef enum { rv_op_crc32c_d = 8, } rv_xlrbr_op; -const rv_opcode_data rv_xlrbr_opcode_data[] = { +static const rv_opcode_data xlrbr_opcode_data[] = { { "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, { "crc32.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, { "crc32.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, @@ -75,5 +75,7 @@ void decode_xlrbr(rv_decode *dec, rv_isa isa) } break; } + + dec->opcode_data = xlrbr_opcode_data; dec->op = op; } diff --git a/disas/riscv-xlrbr.h b/disas/riscv-xlrbr.h index 939a69ea6d..ebf3d4c133 100644 --- a/disas/riscv-xlrbr.h +++ b/disas/riscv-xlrbr.h @@ -12,8 +12,6 @@ #include "disas/riscv.h" -extern const rv_opcode_data rv_xlrbr_opcode_data[]; - void decode_xlrbr(rv_decode *, rv_isa); #endif /* DISAS_RISCV_XLRBR_H */ diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index 2f2ddb8dd9..96f80bc8e5 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -127,7 +127,7 @@ typedef enum { rv_op_th_sync_s, } rv_xthead_op; -const rv_opcode_data xthead_opcode_data[] = { +static const rv_opcode_data xthead_opcode_data[] = { { "th.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, /* XTheadBa */ { "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, @@ -272,6 +272,7 @@ void decode_xtheadba(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -330,6 +331,7 @@ void decode_xtheadbb(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -356,6 +358,7 @@ void decode_xtheadbs(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -434,6 +437,7 @@ void decode_xtheadcmo(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -461,6 +465,7 @@ void decode_xtheadcondmov(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -498,6 +503,7 @@ void decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -533,6 +539,7 @@ void decode_xtheadfmv(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -564,6 +571,7 @@ void decode_xtheadmac(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -638,6 +646,7 @@ void decode_xtheadmemidx(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -672,6 +681,7 @@ void decode_xtheadmempair(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } @@ -706,5 +716,6 @@ void decode_xtheadsync(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = xthead_opcode_data; dec->op = op; } diff --git a/disas/riscv-xthead.h b/disas/riscv-xthead.h index fcd42746e7..0c65c8e0af 100644 --- a/disas/riscv-xthead.h +++ b/disas/riscv-xthead.h @@ -11,8 +11,6 @@ #include "disas/riscv.h" -extern const rv_opcode_data xthead_opcode_data[]; - void decode_xtheadba(rv_decode *, rv_isa); void decode_xtheadbb(rv_decode *, rv_isa); void decode_xtheadbs(rv_decode *, rv_isa); diff --git a/disas/riscv-xventana.c b/disas/riscv-xventana.c index cd694f15f3..4539173d95 100644 --- a/disas/riscv-xventana.c +++ b/disas/riscv-xventana.c @@ -14,7 +14,7 @@ typedef enum { ventana_op_vt_maskcn = 2, } rv_ventana_op; -const rv_opcode_data ventana_opcode_data[] = { +static const rv_opcode_data ventana_opcode_data[] = { { "vt.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, { "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, @@ -38,5 +38,6 @@ void decode_xventanacondops(rv_decode *dec, rv_isa isa) break; } + dec->opcode_data = ventana_opcode_data; dec->op = op; } diff --git a/disas/riscv-xventana.h b/disas/riscv-xventana.h index 72be9ffa16..1006c3be00 100644 --- a/disas/riscv-xventana.h +++ b/disas/riscv-xventana.h @@ -11,8 +11,6 @@ #include "disas/riscv.h" -extern const rv_opcode_data ventana_opcode_data[]; - void decode_xventanacondops(rv_decode*, rv_isa); #endif /* DISAS_RISCV_XVENTANA_H */ diff --git a/disas/riscv.c b/disas/riscv.c index 9880b8de20..eb6d132a2c 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1656,7 +1656,7 @@ static uint32_t operand_lpl(rv_inst inst) /* instruction metadata */ -const rv_opcode_data rvi_opcode_data[] = { +static const rv_opcode_data rvi_opcode_data[] = { { "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, { "lui", rv_codec_u, rv_fmt_rd_uimm, NULL, 0, 0, 0 }, { "auipc", rv_codec_u, rv_fmt_rd_uoffset, NULL, 0, 0, 0 }, @@ -2948,6 +2948,7 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; + switch ((inst >> 0) & 0b11) { case 0: switch ((inst >> 13) & 0b111) { @@ -4590,6 +4591,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) } break; } + + dec->opcode_data = rvi_opcode_data; dec->op = op; } @@ -5421,33 +5424,30 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, }; const rv_opcode_data *op; - dec.opcode_data = rvi_opcode_data; decode_inst_opcode(&dec, isa); if (dec.op == rv_op_illegal && cfg) { static const struct { bool (*guard_func)(const RISCVCPUConfig *); - const rv_opcode_data *opcode_data; void (*decode_func)(rv_decode *, rv_isa); } decoders[] = { - { has_xtheadba_p, xthead_opcode_data, decode_xtheadba }, - { has_xtheadbb_p, xthead_opcode_data, decode_xtheadbb }, - { has_xtheadbs_p, xthead_opcode_data, decode_xtheadbs }, - { has_xtheadcmo_p, xthead_opcode_data, decode_xtheadcmo }, - { has_xtheadcondmov_p, xthead_opcode_data, decode_xtheadcondmov }, - { has_xtheadfmemidx_p, xthead_opcode_data, decode_xtheadfmemidx }, - { has_xtheadfmv_p, xthead_opcode_data, decode_xtheadfmv }, - { has_xtheadmac_p, xthead_opcode_data, decode_xtheadmac }, - { has_xtheadmemidx_p, xthead_opcode_data, decode_xtheadmemidx }, - { has_xtheadmempair_p, xthead_opcode_data, decode_xtheadmempair }, - { has_xtheadsync_p, xthead_opcode_data, decode_xtheadsync }, - { has_XVentanaCondOps_p, ventana_opcode_data, decode_xventanacondops }, - { has_xlrbr_p, rv_xlrbr_opcode_data, decode_xlrbr }, + { has_xtheadba_p, decode_xtheadba }, + { has_xtheadbb_p, decode_xtheadbb }, + { has_xtheadbs_p, decode_xtheadbs }, + { has_xtheadcmo_p, decode_xtheadcmo }, + { has_xtheadcondmov_p, decode_xtheadcondmov }, + { has_xtheadfmemidx_p, decode_xtheadfmemidx }, + { has_xtheadfmv_p, decode_xtheadfmv }, + { has_xtheadmac_p, decode_xtheadmac }, + { has_xtheadmemidx_p, decode_xtheadmemidx }, + { has_xtheadmempair_p, decode_xtheadmempair }, + { has_xtheadsync_p, decode_xtheadsync }, + { has_XVentanaCondOps_p, decode_xventanacondops }, + { has_xlrbr_p, decode_xlrbr }, }; for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { if (decoders[i].guard_func(cfg)) { - dec.opcode_data = decoders[i].opcode_data; decoders[i].decode_func(&dec, isa); if (dec.op != rv_op_illegal) { break; From 7de6afd531867f9f479332a0d6f5a916ba6b8b66 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:00 -0700 Subject: [PATCH 525/627] disas/riscv: Drop explicit zero of rv_opcode_data fields Mechanical s/, NULL, 0, 0, 0 }/ }/ s/, 0, 0, 0 }/ }/ s/, NULL, 0, 0 }/ }/ s/, NULL, 0 }/ }/ Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-11-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xlrbr.c | 18 +- disas/riscv-xthead.c | 210 ++--- disas/riscv-xventana.c | 6 +- disas/riscv.c | 1826 ++++++++++++++++++++-------------------- 4 files changed, 1030 insertions(+), 1030 deletions(-) diff --git a/disas/riscv-xlrbr.c b/disas/riscv-xlrbr.c index f61028fce9..d0092e9edd 100644 --- a/disas/riscv-xlrbr.c +++ b/disas/riscv-xlrbr.c @@ -25,15 +25,15 @@ typedef enum { } rv_xlrbr_op; static const rv_opcode_data xlrbr_opcode_data[] = { - { "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, - { "crc32.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32.w", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32c.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32c.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32c.w", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "crc32c.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "illegal", rv_codec_illegal, rv_fmt_none }, + { "crc32.b", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32.h", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32.w", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32.d", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32c.b", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32c.h", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32c.w", rv_codec_r, rv_fmt_rd_rs1 }, + { "crc32c.d", rv_codec_r, rv_fmt_rd_rs1 }, }; void decode_xlrbr(rv_decode *dec, rv_isa isa) diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index 96f80bc8e5..757d6ff39f 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -128,122 +128,122 @@ typedef enum { } rv_xthead_op; static const rv_opcode_data xthead_opcode_data[] = { - { "th.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, + { "th.illegal", rv_codec_illegal, rv_fmt_none }, /* XTheadBa */ - { "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, + { "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, /* XTheadBb */ - { "th.srri", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "th.srriw", rv_codec_r2_imm5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "th.ext", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 }, - { "th.extu", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 }, - { "th.ff0", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "th.ff1", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "th.rev", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "th.revw", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "th.tstnbz", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, + { "th.srri", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm }, + { "th.srriw", rv_codec_r2_imm5, rv_fmt_rd_rs1_imm }, + { "th.ext", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml }, + { "th.extu", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml }, + { "th.ff0", rv_codec_r2, rv_fmt_rd_rs1 }, + { "th.ff1", rv_codec_r2, rv_fmt_rd_rs1 }, + { "th.rev", rv_codec_r2, rv_fmt_rd_rs1 }, + { "th.revw", rv_codec_r2, rv_fmt_rd_rs1 }, + { "th.tstnbz", rv_codec_r2, rv_fmt_rd_rs1 }, /* XTheadBs */ - { "th.tst", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, + { "th.tst", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm }, /* XTheadCmo */ - { "th.dcache.call", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.dcache.ciall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.dcache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.dcache.cpa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.cipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.ipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.cva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.civa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.iva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.csw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.cisw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.isw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.cpal1", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.dcache.cval1", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.icache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.icache.ialls", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.icache.ipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.icache.iva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "th.l2cache.call", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.l2cache.ciall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.l2cache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "th.dcache.call", rv_codec_none, rv_fmt_none }, + { "th.dcache.ciall", rv_codec_none, rv_fmt_none }, + { "th.dcache.iall", rv_codec_none, rv_fmt_none }, + { "th.dcache.cpa", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.cipa", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.ipa", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.cva", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.civa", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.iva", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.csw", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.cisw", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.isw", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.cpal1", rv_codec_r, rv_fmt_rs1 }, + { "th.dcache.cval1", rv_codec_r, rv_fmt_rs1 }, + { "th.icache.iall", rv_codec_none, rv_fmt_none }, + { "th.icache.ialls", rv_codec_none, rv_fmt_none }, + { "th.icache.ipa", rv_codec_r, rv_fmt_rs1 }, + { "th.icache.iva", rv_codec_r, rv_fmt_rs1 }, + { "th.l2cache.call", rv_codec_none, rv_fmt_none }, + { "th.l2cache.ciall", rv_codec_none, rv_fmt_none }, + { "th.l2cache.iall", rv_codec_none, rv_fmt_none }, /* XTheadCondMov */ - { "th.mveqz", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.mvnez", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "th.mveqz", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.mvnez", rv_codec_r, rv_fmt_rd_rs1_rs2 }, /* XTheadFMemIdx */ - { "th.flrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.flrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.flurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.flurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.fsrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.fsrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.fsurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.fsurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 }, + { "th.flrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.flrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.flurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.flurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.fsrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.fsrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.fsurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, + { "th.fsurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, /* XTheadFmv */ - { "th.fmv.hw.x", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "th.fmv.x.hw", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, + { "th.fmv.hw.x", rv_codec_r, rv_fmt_rd_frs1 }, + { "th.fmv.x.hw", rv_codec_r, rv_fmt_rd_frs1 }, /* XTheadMac */ - { "th.mula", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.mulaw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.mulah", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.muls", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.mulsw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "th.mula", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.mulaw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.mulah", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.muls", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.mulsw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, /* XTheadMemIdx */ - { "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 }, - { "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lhib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lhuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lhuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lwia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lwib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lwuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lwuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.ldia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.ldib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.sbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.sbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.shia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.shib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.swia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.swib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.sdia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.sdib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 }, - { "th.lrb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lrd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.srb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.srh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.srw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.srd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.lurd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.surb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.surh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.surw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, - { "th.surd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 }, + { "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml }, + { "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lhib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lhuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lhuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lwia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lwib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lwuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lwuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.ldia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.ldib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.sbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.sbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.shia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.shib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.swia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.swib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.sdia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.sdib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, + { "th.lrb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lrd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.srb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.srh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.srw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.srd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.lurd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.surb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.surh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.surw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, + { "th.surd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, /* XTheadMemPair */ - { "th.ldd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 }, - { "th.lwd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 }, - { "th.lwud", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 }, - { "th.sdd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 }, - { "th.swd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 }, + { "th.ldd", rv_codec_r_imm2, rv_fmt_rd2_imm }, + { "th.lwd", rv_codec_r_imm2, rv_fmt_rd2_imm }, + { "th.lwud", rv_codec_r_imm2, rv_fmt_rd2_imm }, + { "th.sdd", rv_codec_r_imm2, rv_fmt_rd2_imm }, + { "th.swd", rv_codec_r_imm2, rv_fmt_rd2_imm }, /* XTheadSync */ - { "th.sfence.vmas", rv_codec_r, rv_fmt_rs1_rs2, NULL, 0, 0, 0 }, - { "th.sync", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.sync.i", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.sync.is", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "th.sync.s", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "th.sfence.vmas", rv_codec_r, rv_fmt_rs1_rs2 }, + { "th.sync", rv_codec_none, rv_fmt_none }, + { "th.sync.i", rv_codec_none, rv_fmt_none }, + { "th.sync.is", rv_codec_none, rv_fmt_none }, + { "th.sync.s", rv_codec_none, rv_fmt_none }, }; void decode_xtheadba(rv_decode *dec, rv_isa isa) diff --git a/disas/riscv-xventana.c b/disas/riscv-xventana.c index 4539173d95..4fb9a29d0b 100644 --- a/disas/riscv-xventana.c +++ b/disas/riscv-xventana.c @@ -15,9 +15,9 @@ typedef enum { } rv_ventana_op; static const rv_opcode_data ventana_opcode_data[] = { - { "vt.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, - { "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "vt.illegal", rv_codec_illegal, rv_fmt_none }, + { "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, }; void decode_xventanacondops(rv_decode *dec, rv_isa isa) diff --git a/disas/riscv.c b/disas/riscv.c index eb6d132a2c..ec40abb618 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1657,233 +1657,233 @@ static uint32_t operand_lpl(rv_inst inst) /* instruction metadata */ static const rv_opcode_data rvi_opcode_data[] = { - { "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 }, - { "lui", rv_codec_u, rv_fmt_rd_uimm, NULL, 0, 0, 0 }, - { "auipc", rv_codec_u, rv_fmt_rd_uoffset, NULL, 0, 0, 0 }, - { "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal, 0, 0, 0 }, - { "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr, 0, 0, 0 }, - { "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq, 0, 0, 0 }, - { "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne, 0, 0, 0 }, - { "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt, 0, 0, 0 }, - { "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge, 0, 0, 0 }, - { "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bltu, 0, 0, 0 }, - { "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bgeu, 0, 0, 0 }, - { "lb", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "lh", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "lw", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "lbu", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "lhu", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "sb", rv_codec_s, rv_fmt_rs2_offset_rs1, NULL, 0, 0, 0 }, - { "sh", rv_codec_s, rv_fmt_rs2_offset_rs1, NULL, 0, 0, 0 }, - { "sw", rv_codec_s, rv_fmt_rs2_offset_rs1, NULL, 0, 0, 0 }, - { "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi, 0, 0, 0 }, - { "slti", rv_codec_i, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu, 0, 0, 0 }, - { "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori, 0, 0, 0 }, - { "ori", rv_codec_i, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "andi", rv_codec_i, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "add", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub, 0, 0, 0 }, - { "sll", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt, 0, 0, 0 }, - { "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu, 0, 0, 0 }, - { "xor", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "srl", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sra", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "or", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "and", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "fence", rv_codec_r_f, rv_fmt_pred_succ, NULL, 0, 0, 0 }, - { "fence.i", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "lwu", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "ld", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "sd", rv_codec_s, rv_fmt_rs2_offset_rs1, NULL, 0, 0, 0 }, - { "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw, 0, 0, 0 }, - { "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "addw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw, 0, 0, 0 }, - { "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "ldu", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "lq", rv_codec_i, rv_fmt_rd_offset_rs1, NULL, 0, 0, 0 }, - { "sq", rv_codec_s, rv_fmt_rs2_offset_rs1, NULL, 0, 0, 0 }, - { "addid", rv_codec_i, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "addd", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "subd", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "slld", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "srld", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "srad", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mul", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mulh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mulhsu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mulhu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "div", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "divu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "rem", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "remu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mulw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "divw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "remw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "muld", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "divd", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "divud", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "remd", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "remud", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1, NULL, 0, 0, 0 }, - { "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1, NULL, 0, 0, 0 }, - { "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1, NULL, 0, 0, 0 }, - { "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "ecall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "ebreak", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "uret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "sret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "hret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "mret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "dret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "sfence.vm", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2, NULL, 0, 0, 0 }, - { "wfi", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrw, 0, 0, 0 }, - { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrs, 0, 0, 0 }, - { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1, NULL, 0, 0, 0 }, - { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, rvcp_csrrwi, 0, 0, 0 }, - { "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, NULL, 0, 0, 0 }, - { "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm, NULL, 0, 0, 0 }, - { "flw", rv_codec_i, rv_fmt_frd_offset_rs1, NULL, 0, 0, 0 }, - { "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1, NULL, 0, 0, 0 }, - { "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s, 0, 0, 0 }, - { "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s, 0, 0, 0 }, - { "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s, 0, 0, 0 }, - { "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fclass.s", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fld", rv_codec_i, rv_fmt_frd_offset_rs1, NULL, 0, 0, 0 }, - { "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1, NULL, 0, 0, 0 }, - { "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d, 0, 0, 0 }, - { "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d, 0, 0, 0 }, - { "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d, 0, 0, 0 }, - { "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fclass.d", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 }, - { "flq", rv_codec_i, rv_fmt_frd_offset_rs1, NULL, 0, 0, 0 }, - { "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1, NULL, 0, 0, 0 }, - { "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3, NULL, 0, 0, 0 }, - { "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q, 0, 0, 0 }, - { "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q, 0, 0, 0 }, - { "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q, 0, 0, 0 }, - { "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fclass.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 }, - { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 }, + { "illegal", rv_codec_illegal, rv_fmt_none }, + { "lui", rv_codec_u, rv_fmt_rd_uimm }, + { "auipc", rv_codec_u, rv_fmt_rd_uoffset }, + { "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal }, + { "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr }, + { "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq }, + { "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne }, + { "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt }, + { "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge }, + { "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bltu }, + { "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bgeu }, + { "lb", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "lh", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "lw", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "lbu", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "lhu", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "sb", rv_codec_s, rv_fmt_rs2_offset_rs1 }, + { "sh", rv_codec_s, rv_fmt_rs2_offset_rs1 }, + { "sw", rv_codec_s, rv_fmt_rs2_offset_rs1 }, + { "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi }, + { "slti", rv_codec_i, rv_fmt_rd_rs1_imm }, + { "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu }, + { "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori }, + { "ori", rv_codec_i, rv_fmt_rd_rs1_imm }, + { "andi", rv_codec_i, rv_fmt_rd_rs1_imm }, + { "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub }, + { "sll", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt }, + { "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu }, + { "xor", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "srl", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sra", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "or", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "and", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "fence", rv_codec_r_f, rv_fmt_pred_succ }, + { "fence.i", rv_codec_none, rv_fmt_none }, + { "lwu", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "ld", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "sd", rv_codec_s, rv_fmt_rs2_offset_rs1 }, + { "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw }, + { "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, + { "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, + { "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, + { "addw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw }, + { "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "ldu", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "lq", rv_codec_i, rv_fmt_rd_offset_rs1 }, + { "sq", rv_codec_s, rv_fmt_rs2_offset_rs1 }, + { "addid", rv_codec_i, rv_fmt_rd_rs1_imm }, + { "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, + { "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, + { "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, + { "addd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "subd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "slld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "srld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "srad", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mul", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mulh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mulhsu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mulhu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "div", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "divu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "rem", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "remu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mulw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "divw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "remw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "muld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "divd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "divud", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "remd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "remud", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, + { "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, + { "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, + { "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "ecall", rv_codec_none, rv_fmt_none }, + { "ebreak", rv_codec_none, rv_fmt_none }, + { "uret", rv_codec_none, rv_fmt_none }, + { "sret", rv_codec_none, rv_fmt_none }, + { "hret", rv_codec_none, rv_fmt_none }, + { "mret", rv_codec_none, rv_fmt_none }, + { "dret", rv_codec_none, rv_fmt_none }, + { "sfence.vm", rv_codec_r, rv_fmt_rs1 }, + { "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2 }, + { "wfi", rv_codec_none, rv_fmt_none }, + { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrw }, + { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrs }, + { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, + { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, rvcp_csrrwi }, + { "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, + { "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, + { "flw", rv_codec_i, rv_fmt_frd_offset_rs1 }, + { "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1 }, + { "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s }, + { "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s }, + { "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s }, + { "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1 }, + { "fclass.s", rv_codec_r, rv_fmt_rd_frs1 }, + { "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1 }, + { "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fld", rv_codec_i, rv_fmt_frd_offset_rs1 }, + { "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1 }, + { "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d }, + { "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d }, + { "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d }, + { "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fclass.d", rv_codec_r, rv_fmt_rd_frs1 }, + { "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1 }, + { "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1 }, + { "flq", rv_codec_i, rv_fmt_frd_offset_rs1 }, + { "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1 }, + { "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, + { "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, + { "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q }, + { "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q }, + { "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q }, + { "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fclass.q", rv_codec_r, rv_fmt_rd_frs1 }, + { "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, + { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, + { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi, rvcd_imm_nz }, { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, @@ -1970,696 +1970,696 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, NULL, 0, 0, rv_op_lq }, { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, NULL, 0, 0, rv_op_sq }, - { "nop", rv_codec_i, rv_fmt_none, NULL, 0, 0, 0 }, - { "mv", rv_codec_i, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "not", rv_codec_i, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "neg", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "negw", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "sext.w", rv_codec_i, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "seqz", rv_codec_i, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "snez", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "sltz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "sgtz", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "fmv.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fabs.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fneg.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fmv.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fabs.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fneg.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fmv.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fabs.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "fneg.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 }, - { "beqz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 }, - { "bnez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 }, - { "blez", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 }, - { "bgez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 }, - { "bltz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 }, - { "bgtz", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 }, - { "ble", rv_codec_sb, rv_fmt_rs2_rs1_offset, NULL, 0, 0, 0 }, - { "bleu", rv_codec_sb, rv_fmt_rs2_rs1_offset, NULL, 0, 0, 0 }, - { "bgt", rv_codec_sb, rv_fmt_rs2_rs1_offset, NULL, 0, 0, 0 }, - { "bgtu", rv_codec_sb, rv_fmt_rs2_rs1_offset, NULL, 0, 0, 0 }, - { "j", rv_codec_uj, rv_fmt_offset, NULL, 0, 0, 0 }, - { "ret", rv_codec_i, rv_fmt_none, NULL, 0, 0, 0 }, - { "jr", rv_codec_i, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "rdcycle", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "rdtime", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "rdinstret", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "rdcycleh", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "rdtimeh", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "rdinstreth", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "frcsr", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "frrm", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "frflags", rv_codec_i_csr, rv_fmt_rd, NULL, 0, 0, 0 }, - { "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm, NULL, 0, 0, 0 }, - { "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm, NULL, 0, 0, 0 }, - { "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "clz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "ctz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "cpop", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "sext.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "sext.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "orn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "andn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "rol", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "ror", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "min", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "minu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "ctzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "rev8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "zext.h", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 }, - { "orc.b", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "bset", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "binv", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "bext", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum, NULL, 0, 0, 0 }, - { "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "aes64im", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha256sig0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sha256sig1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sha256sum0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sha256sum1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "sm3p0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sm3p1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs, NULL, 0, 0, 0 }, - { "brev8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "pack", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "packh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "packw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "unzip", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "zip", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "xperm8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 }, - { "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm, NULL, 0, 0, 0 }, - { "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm, NULL, 0, 0, 0 }, - { "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, 0, 0, 0 }, - { "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, 0, 0, 0 }, - { "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, 0, 0, 0 }, - { "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, 0, 0, 0 }, - { "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, 0, 0, 0 }, - { "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, 0, 0, 0 }, - { "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, 0, 0, 0 }, - { "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, 0, 0, 0 }, - { "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, 0, 0, 0 }, - { "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, 0, 0, 0 }, - { "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm, NULL, 0, 0, 0 }, - { "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1, NULL, 0, 0, 0 }, - { "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1, NULL, 0, 0, 0 }, - { "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm, NULL, 0, 0, 0 }, - { "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl, NULL, 0, 0, 0 }, - { "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl, NULL, 0, 0, 0 }, - { "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl, NULL, 0, 0, 0 }, - { "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm, NULL, 0, 0, 0 }, - { "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm, NULL, 0, 0, 0 }, - { "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl, NULL, 0, 0, 0 }, - { "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1, NULL, 0, 0, 0 }, - { "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm, NULL, 0, 0, 0 }, - { "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm, NULL, 0, 0, 0 }, - { "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vid.v", rv_codec_v_r, rv_fmt_vd_vm, NULL, 0, 0, 0 }, - { "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2, NULL, 0, 0, 0 }, - { "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1, NULL, 0, 0, 0 }, - { "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2, NULL, 0, 0, 0 }, - { "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1, NULL, 0, 0, 0 }, - { "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli, NULL, 0, 0, 0 }, - { "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli, NULL, 0, 0, 0 }, - { "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.not", rv_codec_zcb_ext, rv_fmt_rd, NULL, 0 }, - { "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2, NULL, 0, 0 }, - { "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst, NULL, 0, 0, 0 }, - { "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst, NULL, 0, 0, 0 }, - { "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst, NULL, 0, 0, 0 }, - { "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst, NULL, 0, 0, 0 }, - { "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst, NULL, 0, 0, 0 }, - { "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist, NULL, 0, 0 }, - { "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist, NULL, 0, 0 }, - { "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist, NULL, 0, 0, 0 }, - { "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist, NULL, 0, 0 }, - { "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2, NULL, 0, 0, 0 }, - { "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index, NULL, 0 }, - { "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index, NULL, 0 }, - { "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 }, - { "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 }, - { "flh", rv_codec_i, rv_fmt_frd_offset_rs1, NULL, 0, 0, 0 }, - { "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1, NULL, 0, 0, 0 }, - { "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 }, - { "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fli.s", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 }, - { "fli.d", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 }, - { "fli.q", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 }, - { "fli.h", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 }, - { "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 }, - { "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 }, - { "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 }, - { "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2, NULL, 0, 0, 0 }, - { "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 }, - { "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2, NULL, 0, 0, 0 }, - { "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, - { "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, - { "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, - { "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 }, - { "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, - { "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 }, - { "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 }, - { "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 }, - { "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, - { "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, - { "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, - { "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "mop.r.0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.2", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.3", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.4", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.5", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.6", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.7", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.9", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.10", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.11", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.12", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.13", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.14", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.15", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.16", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.17", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.18", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.19", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.20", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.21", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.22", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.23", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.24", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.25", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.26", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.27", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.28", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.29", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.30", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.r.31", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, - { "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, - { "c.mop.1", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.3", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.5", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.7", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.9", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.11", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.13", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "c.mop.15", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "wrs.sto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "wrs.nto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, - { "lpad", rv_codec_lp, rv_fmt_imm, NULL, 0, 0, 0 }, - { "sspush", rv_codec_r, rv_fmt_rs2, NULL, 0, 0, 0 }, - { "sspopchk", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "ssrdp", rv_codec_r, rv_fmt_rd, NULL, 0, 0, 0 }, - { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, - { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "nop", rv_codec_i, rv_fmt_none }, + { "mv", rv_codec_i, rv_fmt_rd_rs1 }, + { "not", rv_codec_i, rv_fmt_rd_rs1 }, + { "neg", rv_codec_r, rv_fmt_rd_rs2 }, + { "negw", rv_codec_r, rv_fmt_rd_rs2 }, + { "sext.w", rv_codec_i, rv_fmt_rd_rs1 }, + { "seqz", rv_codec_i, rv_fmt_rd_rs1 }, + { "snez", rv_codec_r, rv_fmt_rd_rs2 }, + { "sltz", rv_codec_r, rv_fmt_rd_rs1 }, + { "sgtz", rv_codec_r, rv_fmt_rd_rs2 }, + { "fmv.s", rv_codec_r, rv_fmt_frd_frs1 }, + { "fabs.s", rv_codec_r, rv_fmt_frd_frs1 }, + { "fneg.s", rv_codec_r, rv_fmt_frd_frs1 }, + { "fmv.d", rv_codec_r, rv_fmt_frd_frs1 }, + { "fabs.d", rv_codec_r, rv_fmt_frd_frs1 }, + { "fneg.d", rv_codec_r, rv_fmt_frd_frs1 }, + { "fmv.q", rv_codec_r, rv_fmt_frd_frs1 }, + { "fabs.q", rv_codec_r, rv_fmt_frd_frs1 }, + { "fneg.q", rv_codec_r, rv_fmt_frd_frs1 }, + { "beqz", rv_codec_sb, rv_fmt_rs1_offset }, + { "bnez", rv_codec_sb, rv_fmt_rs1_offset }, + { "blez", rv_codec_sb, rv_fmt_rs2_offset }, + { "bgez", rv_codec_sb, rv_fmt_rs1_offset }, + { "bltz", rv_codec_sb, rv_fmt_rs1_offset }, + { "bgtz", rv_codec_sb, rv_fmt_rs2_offset }, + { "ble", rv_codec_sb, rv_fmt_rs2_rs1_offset }, + { "bleu", rv_codec_sb, rv_fmt_rs2_rs1_offset }, + { "bgt", rv_codec_sb, rv_fmt_rs2_rs1_offset }, + { "bgtu", rv_codec_sb, rv_fmt_rs2_rs1_offset }, + { "j", rv_codec_uj, rv_fmt_offset }, + { "ret", rv_codec_i, rv_fmt_none }, + { "jr", rv_codec_i, rv_fmt_rs1 }, + { "rdcycle", rv_codec_i_csr, rv_fmt_rd }, + { "rdtime", rv_codec_i_csr, rv_fmt_rd }, + { "rdinstret", rv_codec_i_csr, rv_fmt_rd }, + { "rdcycleh", rv_codec_i_csr, rv_fmt_rd }, + { "rdtimeh", rv_codec_i_csr, rv_fmt_rd }, + { "rdinstreth", rv_codec_i_csr, rv_fmt_rd }, + { "frcsr", rv_codec_i_csr, rv_fmt_rd }, + { "frrm", rv_codec_i_csr, rv_fmt_rd }, + { "frflags", rv_codec_i_csr, rv_fmt_rd }, + { "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1 }, + { "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1 }, + { "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1 }, + { "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm }, + { "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm }, + { "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, + { "clz", rv_codec_r, rv_fmt_rd_rs1 }, + { "ctz", rv_codec_r, rv_fmt_rd_rs1 }, + { "cpop", rv_codec_r, rv_fmt_rd_rs1 }, + { "sext.h", rv_codec_r, rv_fmt_rd_rs1 }, + { "sext.b", rv_codec_r, rv_fmt_rd_rs1 }, + { "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "orn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "andn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "rol", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "ror", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "min", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "minu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "max", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "clzw", rv_codec_r, rv_fmt_rd_rs1 }, + { "ctzw", rv_codec_r, rv_fmt_rd_rs1 }, + { "cpopw", rv_codec_r, rv_fmt_rd_rs1 }, + { "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, + { "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "rev8", rv_codec_r, rv_fmt_rd_rs1 }, + { "zext.h", rv_codec_r, rv_fmt_rd_rs1 }, + { "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, + { "orc.b", rv_codec_r, rv_fmt_rd_rs1 }, + { "bset", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "binv", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "bext", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum }, + { "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "aes64im", rv_codec_r, rv_fmt_rd_rs1 }, + { "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha256sig0", rv_codec_r, rv_fmt_rd_rs1 }, + { "sha256sig1", rv_codec_r, rv_fmt_rd_rs1 }, + { "sha256sum0", rv_codec_r, rv_fmt_rd_rs1 }, + { "sha256sum1", rv_codec_r, rv_fmt_rd_rs1 }, + { "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "sm3p0", rv_codec_r, rv_fmt_rd_rs1 }, + { "sm3p1", rv_codec_r, rv_fmt_rd_rs1 }, + { "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, + { "brev8", rv_codec_r, rv_fmt_rd_rs1 }, + { "pack", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "packh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "packw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "unzip", rv_codec_r, rv_fmt_rd_rs1 }, + { "zip", rv_codec_r, rv_fmt_rd_rs1 }, + { "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "xperm8", rv_codec_r, rv_fmt_rd_rs1 }, + { "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, + { "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, + { "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, + { "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, + { "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, + { "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, + { "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, + { "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, + { "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, + { "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, + { "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, + { "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, + { "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, + { "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, + { "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1 }, + { "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1 }, + { "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm }, + { "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, + { "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, + { "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, + { "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, + { "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, + { "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl }, + { "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1 }, + { "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm }, + { "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm }, + { "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vid.v", rv_codec_v_r, rv_fmt_vd_vm }, + { "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2 }, + { "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1 }, + { "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2 }, + { "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1 }, + { "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli }, + { "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli }, + { "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.not", rv_codec_zcb_ext, rv_fmt_rd }, + { "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2 }, + { "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst }, + { "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, + { "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, + { "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst }, + { "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, + { "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist }, + { "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, + { "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, + { "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, + { "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2 }, + { "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2 }, + { "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index }, + { "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index }, + { "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, + { "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, + { "flh", rv_codec_i, rv_fmt_frd_offset_rs1 }, + { "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1 }, + { "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1 }, + { "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1 }, + { "fli.s", rv_codec_fli, rv_fmt_fli }, + { "fli.d", rv_codec_fli, rv_fmt_fli }, + { "fli.q", rv_codec_fli, rv_fmt_fli }, + { "fli.h", rv_codec_fli, rv_fmt_fli }, + { "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2 }, + { "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, + { "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, + { "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1 }, + { "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2 }, + { "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1 }, + { "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2 }, + { "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2 }, + { "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, + { "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, + { "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, + { "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm }, + { "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, + { "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, + { "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, + { "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, + { "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, + { "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, + { "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, + { "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "mop.r.0", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.1", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.2", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.3", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.4", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.5", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.6", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.7", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.8", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.9", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.10", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.11", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.12", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.13", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.14", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.15", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.16", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.17", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.18", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.19", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.20", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.21", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.22", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.23", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.24", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.25", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.26", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.27", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.28", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.29", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.30", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.r.31", rv_codec_r, rv_fmt_rd_rs1 }, + { "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2 }, + { "c.mop.1", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.3", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.5", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.7", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.9", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.11", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.13", rv_codec_ci_none, rv_fmt_none }, + { "c.mop.15", rv_codec_ci_none, rv_fmt_none }, + { "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "wrs.sto", rv_codec_none, rv_fmt_none }, + { "wrs.nto", rv_codec_none, rv_fmt_none }, + { "lpad", rv_codec_lp, rv_fmt_imm }, + { "sspush", rv_codec_r, rv_fmt_rs2 }, + { "sspopchk", rv_codec_r, rv_fmt_rs1 }, + { "ssrdp", rv_codec_r, rv_fmt_rd }, + { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, + { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, NULL, rv_op_sspush, rv_op_sspush, 0 }, { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk, rv_op_sspopchk, 0 }, - { "cbo.inval", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "cbo.clean", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "cbo.flush", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "cbo.zero", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 }, - { "mnret", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "cbo.inval", rv_codec_r, rv_fmt_rs1 }, + { "cbo.clean", rv_codec_r, rv_fmt_rs1 }, + { "cbo.flush", rv_codec_r, rv_fmt_rs1 }, + { "cbo.zero", rv_codec_r, rv_fmt_rs1 }, + { "mnret", rv_codec_none, rv_fmt_none }, }; /* CSR names */ From 81305446b4eb847f0613dbae3510e08d5fb56929 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:01 -0700 Subject: [PATCH 526/627] disas/riscv: Drop useless const in structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Individual fields should not be const, only full structures. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-12-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/disas/riscv.h b/disas/riscv.h index eabe193b4f..3325b7b4ef 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -174,19 +174,19 @@ typedef enum { /* structures */ typedef struct { - const int op; + int op; const rvc_constraint *constraints; } rv_comp_data; typedef struct { - const char * const name; - const rv_codec codec; - const char * const format; + const char *name; + rv_codec codec; + const char *format; const rv_comp_data *pseudo; - const short decomp_rv32; - const short decomp_rv64; - const short decomp_rv128; - const short decomp_data; + short decomp_rv32; + short decomp_rv64; + short decomp_rv128; + short decomp_data; } rv_opcode_data; typedef struct { From 4a5a8434bb8d71cbed6e71a7355e59eb514a97fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:02 -0700 Subject: [PATCH 527/627] disas/riscv: Drop codec from rv_decode This is mostly write-only, only used in one place; other updates are ignored. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-13-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 7 +++---- disas/riscv.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index ec40abb618..9813d75feb 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -4603,8 +4603,9 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, { rv_inst inst = dec->inst; - dec->codec = op->codec; - switch (dec->codec) { + switch (op->codec) { + case rv_codec_illegal: + break; case rv_codec_none: dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; dec->imm = 0; @@ -5369,7 +5370,6 @@ static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, if (check_constraints(dec, comp_data->constraints)) { dec->op = comp_data->op; op = &dec->opcode_data[dec->op]; - dec->codec = op->codec; break; } comp_data++; @@ -5407,7 +5407,6 @@ static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, rv_isa isa, dec->op = decomp_op; } op = &dec->opcode_data[decomp_op]; - dec->codec = op->codec; } return op; } diff --git a/disas/riscv.h b/disas/riscv.h index 3325b7b4ef..31bb0db86c 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -197,7 +197,6 @@ typedef struct { int32_t imm; int32_t imm1; uint16_t op; - uint8_t codec; uint8_t rd; uint8_t rs1; uint8_t rs2; From ae8f42f440265cc17c902f56f1ca94db86e6411f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:03 -0700 Subject: [PATCH 528/627] disas/riscv: Handle c.addi4spn imm != 0 during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-14-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 9813d75feb..8a957e6a1e 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1885,7 +1885,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, - rv_op_addi, rv_op_addi, rvcd_imm_nz }, + rv_op_addi, rv_op_addi }, { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, 0 }, { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, @@ -2952,7 +2952,11 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) switch ((inst >> 0) & 0b11) { case 0: switch ((inst >> 13) & 0b111) { - case 0: op = rv_op_c_addi4spn; break; + case 0: + if ((inst >> 5) & 0xff) { + op = rv_op_c_addi4spn; + } + break; case 1: if (isa == rv128) { op = rv_op_c_lq; From 87f162e424d2622732b82749594f57271af7b3af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:04 -0700 Subject: [PATCH 529/627] disas/riscv: Simplify c.addi While c.addi with imm == 0 and rd == 0 is c.nop, other c.addi with imm == 0 and rd != 0 are not illegal, but are reserved as HINTs. Go ahead and disassemble as c.addi rather than falling back to invalid. Further, there's no reason to differentiate c.nop, since we have c.addi -> addi -> nop vs c.nop -> addi -> nop via decompress and pseudo translation steps. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-15-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 8a957e6a1e..7978ffb378 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -263,7 +263,6 @@ typedef enum { rv_op_c_fsd = 231, rv_op_c_sw = 232, rv_op_c_fsw = 233, - rv_op_c_nop = 234, rv_op_c_addi = 235, rv_op_c_jal = 236, rv_op_c_li = 237, @@ -1896,10 +1895,9 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, rv_op_sw, rv_op_sw }, { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, 0 }, - { "c.nop", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_addi, rv_op_addi, - rv_op_addi }, + { }, { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, - rv_op_addi, rvcd_imm_nz }, + rv_op_addi }, { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal, 0, 0 }, { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, @@ -3010,10 +3008,7 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 1: switch ((inst >> 13) & 0b111) { case 0: - switch ((inst >> 2) & 0b11111111111) { - case 0: op = rv_op_c_nop; break; - default: op = rv_op_c_addi; break; - } + op = rv_op_c_addi; /* or unspecified HINT */ break; case 1: if (isa == rv32) { From 3421486be8e9420eb357b878d867f47c9647c1c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:05 -0700 Subject: [PATCH 530/627] disas/riscv: Handle c.lui imm != 0 during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-16-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 7978ffb378..d6fbb3bca6 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1902,9 +1902,9 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi }, { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, - rv_op_addi, rv_op_addi, rvcd_imm_nz }, + rv_op_addi, rv_op_addi }, { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui, rv_op_lui, - rv_op_lui, rvcd_imm_nz }, + rv_op_lui }, { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, rv_op_srli, rv_op_srli, rvcd_imm_nz }, { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, @@ -3032,9 +3032,11 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; } } - switch ((inst >> 7) & 0b11111) { - case 2: op = rv_op_c_addi16sp; break; - default: op = rv_op_c_lui; break; + if (inst & ((1 << 12) | (0x1f << 2))) { + switch ((inst >> 7) & 0b11111) { + case 2: op = rv_op_c_addi16sp; break; + default: op = rv_op_c_lui; break; + } } break; case 4: From dc2fe85523d059d34c7f4ba35aae57bf7218b396 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:06 -0700 Subject: [PATCH 531/627] disas/riscv: Handle c.{srli,srai} imm during decode Zero shift immediate to c.srli and c.srai are not illegal, but are reserved as HINTs. Go ahead and disassemble as shifts rather than falling back to invalid. On the other hand, shift immediate >= 32 with RV32 is reserved for custom extensions, and we need to reject those early so that the extension disassemblers get a look in. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-17-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index d6fbb3bca6..a8fbefb9bd 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1906,9 +1906,9 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui, rv_op_lui, rv_op_lui }, { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, - rv_op_srli, rv_op_srli, rvcd_imm_nz }, + rv_op_srli, rv_op_srli }, { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, - rv_op_srai, rv_op_srai, rvcd_imm_nz }, + rv_op_srai, rv_op_srai }, { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, rv_op_andi, rv_op_andi }, { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub, rv_op_sub, @@ -3042,10 +3042,16 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 4: switch ((inst >> 10) & 0b11) { case 0: - op = rv_op_c_srli; + /* For rv32, shamt[5]=1 is designated for custom extensions. */ + if (isa != rv32 || (inst & 0x1000) == 0) { + op = rv_op_c_srli; /* or unspecified HINT */ + } break; case 1: - op = rv_op_c_srai; + /* For rv32, shamt[5]=1 is designated for custom extensions. */ + if (isa != rv32 || (inst & 0x1000) == 0) { + op = rv_op_c_srai; /* or unspecified HINT */ + } break; case 2: op = rv_op_c_andi; break; case 3: From 4de89e9a82fcf8e87a53895bbc01bc0434c92793 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:07 -0700 Subject: [PATCH 532/627] disas/riscv: Handle c.slli imm != 0 during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-18-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index a8fbefb9bd..77347b557d 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1930,7 +1930,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne, rv_op_bne, rv_op_bne }, { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, - rv_op_slli, rv_op_slli, rvcd_imm_nz }, + rv_op_slli, rv_op_slli }, { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, rv_op_fld }, { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, @@ -3085,7 +3085,9 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 2: switch ((inst >> 13) & 0b111) { case 0: - op = rv_op_c_slli; + if (isa != rv32 || (inst & 0x1000) == 0) { + op = rv_op_c_slli; /* or unspecified HINT */ + } break; case 1: if (isa == rv128) { From 70c0e443432dda01d4e603961e0baee54e668f4d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:08 -0700 Subject: [PATCH 533/627] disas/riscv: Do not recognize c.{addw, subw} with rv32 These code points are reserved with RV32. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-19-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 77347b557d..ddc2f73eae 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -3060,8 +3060,16 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 1: op = rv_op_c_xor; break; case 2: op = rv_op_c_or; break; case 3: op = rv_op_c_and; break; - case 4: op = rv_op_c_subw; break; - case 5: op = rv_op_c_addw; break; + case 4: + if (isa != rv32) { + op = rv_op_c_subw; + } + break; + case 5: + if (isa != rv32) { + op = rv_op_c_addw; + } + break; case 6: op = rv_op_c_mul; break; case 7: switch ((inst >> 2) & 0b111) { From af216549cb0651404fbe7eebc9a0e377faeb57f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:09 -0700 Subject: [PATCH 534/627] disas/riscv: Remove rvcd_imm_nz Remove rvcd_imm_nz and rv_opcode_data.decomp_data as unused. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-20-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 7 +------ disas/riscv.h | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index ddc2f73eae..95957506bd 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5417,12 +5417,7 @@ static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, rv_isa isa, } if (decomp_op != rv_op_illegal) { - if ((op->decomp_data & rvcd_imm_nz) && dec->imm == 0) { - dec->opcode_data = rvi_opcode_data; - dec->op = rv_op_illegal; - } else { - dec->op = decomp_op; - } + dec->op = decomp_op; op = &dec->opcode_data[decomp_op]; } return op; diff --git a/disas/riscv.h b/disas/riscv.h index 31bb0db86c..3909d73dd0 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -186,7 +186,6 @@ typedef struct { short decomp_rv32; short decomp_rv64; short decomp_rv128; - short decomp_data; } rv_opcode_data; typedef struct { @@ -217,10 +216,6 @@ enum { rv_op_illegal = 0 }; -enum { - rvcd_imm_nz = 0x1 -}; - /* instruction formats */ #define rv_fmt_none "O\t" From ebb571dc8066ba66137f6a7657d95a43e7728563 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:10 -0700 Subject: [PATCH 535/627] disas/riscv: Unify decomp_rv{32,64,128} We now distinguish compressed opcodes by isa during decode. Therefore we don't need 3 copies of decomp_*. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-21-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 155 ++++++++++++++++---------------------------------- disas/riscv.h | 4 +- 2 files changed, 51 insertions(+), 108 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 95957506bd..2e891f509e 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1883,91 +1883,52 @@ static const rv_opcode_data rvi_opcode_data[] = { { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, - rv_op_addi, rv_op_addi }, - { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, - rv_op_fld, 0 }, - { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, - rv_op_lw }, - { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 }, - { "c.fsd", rv_codec_cs_sd, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd, - rv_op_fsd, 0 }, - { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, rv_op_sw, - rv_op_sw }, - { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, 0 }, + { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, + { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld }, + { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw }, + { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw }, + { "c.fsd", rv_codec_cs_sd, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd }, + { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw }, + { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw }, { }, - { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, - rv_op_addi }, - { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal, 0, 0 }, - { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, - rv_op_addi }, - { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, - rv_op_addi, rv_op_addi }, - { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui, rv_op_lui, - rv_op_lui }, - { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, - rv_op_srli, rv_op_srli }, - { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, - rv_op_srai, rv_op_srai }, - { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, - rv_op_andi, rv_op_andi }, - { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub, rv_op_sub, - rv_op_sub }, - { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor, rv_op_xor, - rv_op_xor }, - { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or, rv_op_or, - rv_op_or }, - { "c.and", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_and, rv_op_and, - rv_op_and }, - { "c.subw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_subw, rv_op_subw, - rv_op_subw }, - { "c.addw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_addw, rv_op_addw, - rv_op_addw }, - { "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal, rv_op_jal, - rv_op_jal }, - { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq, rv_op_beq, - rv_op_beq }, - { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne, rv_op_bne, - rv_op_bne }, - { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, - rv_op_slli, rv_op_slli }, - { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, - rv_op_fld, rv_op_fld }, - { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, - rv_op_lw, rv_op_lw }, - { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, - 0 }, - { "c.jr", rv_codec_cr_jr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr, - rv_op_jalr, rv_op_jalr }, - { "c.mv", rv_codec_cr_mv, rv_fmt_rd_rs1_rs2, NULL, rv_op_addi, rv_op_addi, - rv_op_addi }, - { "c.ebreak", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_ebreak, - rv_op_ebreak, rv_op_ebreak }, - { "c.jalr", rv_codec_cr_jalr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr, - rv_op_jalr, rv_op_jalr }, - { "c.add", rv_codec_cr, rv_fmt_rd_rs1_rs2, NULL, rv_op_add, rv_op_add, - rv_op_add }, - { "c.fsdsp", rv_codec_css_sdsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd, - rv_op_fsd, rv_op_fsd }, - { "c.swsp", rv_codec_css_swsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, - rv_op_sw, rv_op_sw }, - { "c.fswsp", rv_codec_css_swsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, - 0 }, - { "c.ld", rv_codec_cl_ld, rv_fmt_rd_offset_rs1, NULL, 0, rv_op_ld, - rv_op_ld }, - { "c.sd", rv_codec_cs_sd, rv_fmt_rs2_offset_rs1, NULL, 0, rv_op_sd, - rv_op_sd }, - { "c.addiw", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, 0, rv_op_addiw, - rv_op_addiw }, - { "c.ldsp", rv_codec_ci_ldsp, rv_fmt_rd_offset_rs1, NULL, 0, rv_op_ld, - rv_op_ld }, - { "c.sdsp", rv_codec_css_sdsp, rv_fmt_rs2_offset_rs1, NULL, 0, rv_op_sd, - rv_op_sd }, - { "c.lq", rv_codec_cl_lq, rv_fmt_rd_offset_rs1, NULL, 0, 0, rv_op_lq }, - { "c.sq", rv_codec_cs_sq, rv_fmt_rs2_offset_rs1, NULL, 0, 0, rv_op_sq }, - { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, NULL, 0, 0, rv_op_lq }, - { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, NULL, 0, 0, - rv_op_sq }, + { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, + { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal }, + { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, + { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, + { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui }, + { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli }, + { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai }, + { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi }, + { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub }, + { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor }, + { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or }, + { "c.and", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_and }, + { "c.subw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_subw }, + { "c.addw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_addw }, + { "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal }, + { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq }, + { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne }, + { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli }, + { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld }, + { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw }, + { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw }, + { "c.jr", rv_codec_cr_jr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr }, + { "c.mv", rv_codec_cr_mv, rv_fmt_rd_rs1_rs2, NULL, rv_op_addi }, + { "c.ebreak", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_ebreak }, + { "c.jalr", rv_codec_cr_jalr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr }, + { "c.add", rv_codec_cr, rv_fmt_rd_rs1_rs2, NULL, rv_op_add }, + { "c.fsdsp", rv_codec_css_sdsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd }, + { "c.swsp", rv_codec_css_swsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw }, + { "c.fswsp", rv_codec_css_swsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw }, + { "c.ld", rv_codec_cl_ld, rv_fmt_rd_offset_rs1, NULL, rv_op_ld }, + { "c.sd", rv_codec_cs_sd, rv_fmt_rs2_offset_rs1, NULL, rv_op_sd }, + { "c.addiw", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addiw }, + { "c.ldsp", rv_codec_ci_ldsp, rv_fmt_rd_offset_rs1, NULL, rv_op_ld }, + { "c.sdsp", rv_codec_css_sdsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sd }, + { "c.lq", rv_codec_cl_lq, rv_fmt_rd_offset_rs1, NULL, rv_op_lq }, + { "c.sq", rv_codec_cs_sq, rv_fmt_rs2_offset_rs1, NULL, rv_op_sq }, + { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lq }, + { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sq }, { "nop", rv_codec_i, rv_fmt_none }, { "mv", rv_codec_i, rv_fmt_rd_rs1 }, { "not", rv_codec_i, rv_fmt_rd_rs1 }, @@ -2649,10 +2610,8 @@ static const rv_opcode_data rvi_opcode_data[] = { { "ssrdp", rv_codec_r, rv_fmt_rd }, { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, NULL, rv_op_sspush, - rv_op_sspush, 0 }, - { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk, - rv_op_sspopchk, 0 }, + { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, NULL, rv_op_sspush }, + { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk }, { "cbo.inval", rv_codec_r, rv_fmt_rs1 }, { "cbo.clean", rv_codec_r, rv_fmt_rs1 }, { "cbo.flush", rv_codec_r, rv_fmt_rs1 }, @@ -5397,24 +5356,10 @@ static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, /* decompress instruction */ -static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, rv_isa isa, +static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, const rv_opcode_data *op) { - int decomp_op; - - switch (isa) { - case rv32: - decomp_op = op->decomp_rv32; - break; - case rv64: - decomp_op = op->decomp_rv64; - break; - case rv128: - decomp_op = op->decomp_rv128; - break; - default: - g_assert_not_reached(); - } + int decomp_op = op->decomp; if (decomp_op != rv_op_illegal) { dec->op = decomp_op; @@ -5473,7 +5418,7 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, op = &dec.opcode_data[dec.op]; decode_inst_operands(&dec, isa, op); - op = decode_inst_decompress(&dec, isa, op); + op = decode_inst_decompress(&dec, op); op = decode_inst_lift_pseudo(&dec, op); return format_inst(24, &dec, op); } diff --git a/disas/riscv.h b/disas/riscv.h index 3909d73dd0..900363c603 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -183,9 +183,7 @@ typedef struct { rv_codec codec; const char *format; const rv_comp_data *pseudo; - short decomp_rv32; - short decomp_rv64; - short decomp_rv128; + rv_opcode decomp; } rv_opcode_data; typedef struct { From 7376e4d7d29c7c4bf4ad552624502c92e2deac06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:11 -0700 Subject: [PATCH 536/627] disas/riscv: Drop always true branch pseudos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real insns are blt, bge, bltu, bgeu. Do not include pseudos that unconditionally swap operands. That's fine for an assembler but not a disassembler. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-22-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 2e891f509e..bde1cc6e62 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -326,10 +326,6 @@ typedef enum { rv_op_bgez = 295, rv_op_bltz = 296, rv_op_bgtz = 297, - rv_op_ble = 298, - rv_op_bleu = 299, - rv_op_bgt = 300, - rv_op_bgtu = 301, rv_op_j = 302, rv_op_ret = 303, rv_op_jr = 304, @@ -1062,10 +1058,6 @@ static const rvc_constraint rvcc_blez[] = { rvc_rs1_eq_x0, rvc_end }; static const rvc_constraint rvcc_bgez[] = { rvc_rs2_eq_x0, rvc_end }; static const rvc_constraint rvcc_bltz[] = { rvc_rs2_eq_x0, rvc_end }; static const rvc_constraint rvcc_bgtz[] = { rvc_rs1_eq_x0, rvc_end }; -static const rvc_constraint rvcc_ble[] = { rvc_end }; -static const rvc_constraint rvcc_bleu[] = { rvc_end }; -static const rvc_constraint rvcc_bgt[] = { rvc_end }; -static const rvc_constraint rvcc_bgtu[] = { rvc_end }; static const rvc_constraint rvcc_j[] = { rvc_rd_eq_x0, rvc_end }; static const rvc_constraint rvcc_ret[] = { rvc_rd_eq_x0, rvc_rs1_eq_ra, rvc_end }; @@ -1123,24 +1115,12 @@ static const rv_comp_data rvcp_bne[] = { static const rv_comp_data rvcp_blt[] = { { rv_op_bltz, rvcc_bltz }, { rv_op_bgtz, rvcc_bgtz }, - { rv_op_bgt, rvcc_bgt }, { rv_op_illegal, NULL } }; static const rv_comp_data rvcp_bge[] = { { rv_op_blez, rvcc_blez }, { rv_op_bgez, rvcc_bgez }, - { rv_op_ble, rvcc_ble }, - { rv_op_illegal, NULL } -}; - -static const rv_comp_data rvcp_bltu[] = { - { rv_op_bgtu, rvcc_bgtu }, - { rv_op_illegal, NULL } -}; - -static const rv_comp_data rvcp_bgeu[] = { - { rv_op_bleu, rvcc_bleu }, { rv_op_illegal, NULL } }; @@ -1665,8 +1645,8 @@ static const rv_opcode_data rvi_opcode_data[] = { { "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne }, { "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt }, { "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge }, - { "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bltu }, - { "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bgeu }, + { "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset }, + { "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset }, { "lb", rv_codec_i, rv_fmt_rd_offset_rs1 }, { "lh", rv_codec_i, rv_fmt_rd_offset_rs1 }, { "lw", rv_codec_i, rv_fmt_rd_offset_rs1 }, @@ -1954,10 +1934,10 @@ static const rv_opcode_data rvi_opcode_data[] = { { "bgez", rv_codec_sb, rv_fmt_rs1_offset }, { "bltz", rv_codec_sb, rv_fmt_rs1_offset }, { "bgtz", rv_codec_sb, rv_fmt_rs2_offset }, - { "ble", rv_codec_sb, rv_fmt_rs2_rs1_offset }, - { "bleu", rv_codec_sb, rv_fmt_rs2_rs1_offset }, - { "bgt", rv_codec_sb, rv_fmt_rs2_rs1_offset }, - { "bgtu", rv_codec_sb, rv_fmt_rs2_rs1_offset }, + { }, + { }, + { }, + { }, { "j", rv_codec_uj, rv_fmt_offset }, { "ret", rv_codec_i, rv_fmt_none }, { "jr", rv_codec_i, rv_fmt_rs1 }, From b1d5cbf56abc5604c6848350926271e7f865f988 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:12 -0700 Subject: [PATCH 537/627] disas/riscv: Handle aliases of csrrw during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-23-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index bde1cc6e62..e464b8b075 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1081,9 +1081,6 @@ static const rvc_constraint rvcc_frrm[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x002, rvc_end }; static const rvc_constraint rvcc_frflags[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x001, rvc_end }; -static const rvc_constraint rvcc_fscsr[] = { rvc_csr_eq_0x003, rvc_end }; -static const rvc_constraint rvcc_fsrm[] = { rvc_csr_eq_0x002, rvc_end }; -static const rvc_constraint rvcc_fsflags[] = { rvc_csr_eq_0x001, rvc_end }; static const rvc_constraint rvcc_fsrmi[] = { rvc_csr_eq_0x002, rvc_end }; static const rvc_constraint rvcc_fsflagsi[] = { rvc_csr_eq_0x001, rvc_end }; @@ -1166,14 +1163,6 @@ static const rv_comp_data rvcp_subw[] = { { rv_op_illegal, NULL } }; -static const rv_comp_data rvcp_csrrw[] = { - { rv_op_fscsr, rvcc_fscsr }, - { rv_op_fsrm, rvcc_fsrm }, - { rv_op_fsflags, rvcc_fsflags }, - { rv_op_illegal, NULL } -}; - - static const rv_comp_data rvcp_csrrs[] = { { rv_op_rdcycle, rvcc_rdcycle }, { rv_op_rdtime, rvcc_rdtime }, @@ -1761,7 +1750,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "sfence.vm", rv_codec_r, rv_fmt_rs1 }, { "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2 }, { "wfi", rv_codec_none, rv_fmt_none }, - { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrw }, + { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrs }, { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, rvcp_csrrwi }, @@ -4443,7 +4432,14 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; } break; - case 1: op = rv_op_csrrw; break; + case 1: + switch (operand_csr12(inst)) { + case 1: op = rv_op_fsflags; break; + case 2: op = rv_op_fsrm; break; + case 3: op = rv_op_fscsr; break; + default: op = rv_op_csrrw; break; + } + break; case 2: op = rv_op_csrrs; break; case 3: op = rv_op_csrrc; break; case 4: From 6bfb6410562592a7f6a1e496c99600a58b838231 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:13 -0700 Subject: [PATCH 538/627] disas/riscv: Handle aliases of csrrs during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-24-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 85 +++++++++++---------------------------------------- disas/riscv.h | 7 ----- 2 files changed, 17 insertions(+), 75 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index e464b8b075..9ec79baf4d 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1063,24 +1063,6 @@ static const rvc_constraint rvcc_ret[] = { rvc_rd_eq_x0, rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, rvc_end }; -static const rvc_constraint rvcc_rdcycle[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc00, - rvc_end }; -static const rvc_constraint rvcc_rdtime[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc01, - rvc_end }; -static const rvc_constraint rvcc_rdinstret[] = { rvc_rs1_eq_x0, - rvc_csr_eq_0xc02, rvc_end }; -static const rvc_constraint rvcc_rdcycleh[] = { rvc_rs1_eq_x0, - rvc_csr_eq_0xc80, rvc_end }; -static const rvc_constraint rvcc_rdtimeh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc81, - rvc_end }; -static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0, - rvc_csr_eq_0xc82, rvc_end }; -static const rvc_constraint rvcc_frcsr[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x003, - rvc_end }; -static const rvc_constraint rvcc_frrm[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x002, - rvc_end }; -static const rvc_constraint rvcc_frflags[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x001, - rvc_end }; static const rvc_constraint rvcc_fsrmi[] = { rvc_csr_eq_0x002, rvc_end }; static const rvc_constraint rvcc_fsflagsi[] = { rvc_csr_eq_0x001, rvc_end }; @@ -1163,19 +1145,6 @@ static const rv_comp_data rvcp_subw[] = { { rv_op_illegal, NULL } }; -static const rv_comp_data rvcp_csrrs[] = { - { rv_op_rdcycle, rvcc_rdcycle }, - { rv_op_rdtime, rvcc_rdtime }, - { rv_op_rdinstret, rvcc_rdinstret }, - { rv_op_rdcycleh, rvcc_rdcycleh }, - { rv_op_rdtimeh, rvcc_rdtimeh }, - { rv_op_rdinstreth, rvcc_rdinstreth }, - { rv_op_frcsr, rvcc_frcsr }, - { rv_op_frrm, rvcc_frrm }, - { rv_op_frflags, rvcc_frflags }, - { rv_op_illegal, NULL } -}; - static const rv_comp_data rvcp_csrrwi[] = { { rv_op_fsrmi, rvcc_fsrmi }, { rv_op_fsflagsi, rvcc_fsflagsi }, @@ -1751,7 +1720,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2 }, { "wfi", rv_codec_none, rv_fmt_none }, { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, - { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1, rvcp_csrrs }, + { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, rvcp_csrrwi }, { "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, @@ -4440,7 +4409,22 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) default: op = rv_op_csrrw; break; } break; - case 2: op = rv_op_csrrs; break; + case 2: + op = rv_op_csrrs; + if (operand_rs1(inst) == 0) { + switch (operand_csr12(inst)) { + case 0x001: op = rv_op_frflags; break; + case 0x002: op = rv_op_frrm; break; + case 0x003: op = rv_op_frcsr; break; + case 0xc00: op = rv_op_rdcycle; break; + case 0xc01: op = rv_op_rdtime; break; + case 0xc02: op = rv_op_rdinstret; break; + case 0xc80: op = rv_op_rdcycleh; break; + case 0xc81: op = rv_op_rdtimeh; break; + case 0xc82: op = rv_op_rdinstreth; break; + } + } + break; case 3: op = rv_op_csrrc; break; case 4: if (dec->cfg && dec->cfg->ext_zimop) { @@ -5017,41 +5001,6 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c) return false; } break; - case rvc_csr_eq_0x003: - if (!(imm == 0x003)) { - return false; - } - break; - case rvc_csr_eq_0xc00: - if (!(imm == 0xc00)) { - return false; - } - break; - case rvc_csr_eq_0xc01: - if (!(imm == 0xc01)) { - return false; - } - break; - case rvc_csr_eq_0xc02: - if (!(imm == 0xc02)) { - return false; - } - break; - case rvc_csr_eq_0xc80: - if (!(imm == 0xc80)) { - return false; - } - break; - case rvc_csr_eq_0xc81: - if (!(imm == 0xc81)) { - return false; - } - break; - case rvc_csr_eq_0xc82: - if (!(imm == 0xc82)) { - return false; - } - break; default: break; } c++; diff --git a/disas/riscv.h b/disas/riscv.h index 900363c603..d8c5acd969 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -86,13 +86,6 @@ typedef enum { rvc_imm_eq_p1, rvc_csr_eq_0x001, rvc_csr_eq_0x002, - rvc_csr_eq_0x003, - rvc_csr_eq_0xc00, - rvc_csr_eq_0xc01, - rvc_csr_eq_0xc02, - rvc_csr_eq_0xc80, - rvc_csr_eq_0xc81, - rvc_csr_eq_0xc82, } rvc_constraint; typedef enum { From 9803e8277307e153dbbb1757c083167f882a9ef8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:14 -0700 Subject: [PATCH 539/627] disas/riscv: Handle aliases of csrrwi during decode Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-25-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 28 ++++++++-------------------- disas/riscv.h | 2 -- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 9ec79baf4d..d3cbfb86ac 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1063,8 +1063,6 @@ static const rvc_constraint rvcc_ret[] = { rvc_rd_eq_x0, rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, rvc_end }; -static const rvc_constraint rvcc_fsrmi[] = { rvc_csr_eq_0x002, rvc_end }; -static const rvc_constraint rvcc_fsflagsi[] = { rvc_csr_eq_0x001, rvc_end }; /* pseudo-instruction metadata */ @@ -1145,12 +1143,6 @@ static const rv_comp_data rvcp_subw[] = { { rv_op_illegal, NULL } }; -static const rv_comp_data rvcp_csrrwi[] = { - { rv_op_fsrmi, rvcc_fsrmi }, - { rv_op_fsflagsi, rvcc_fsflagsi }, - { rv_op_illegal, NULL } -}; - static const rv_comp_data rvcp_fsgnj_s[] = { { rv_op_fmv_s, rvcc_fmv_s }, { rv_op_illegal, NULL } @@ -1722,7 +1714,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, - { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm, rvcp_csrrwi }, + { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, { "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, { "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, { "flw", rv_codec_i, rv_fmt_frd_offset_rs1 }, @@ -4469,7 +4461,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) } } break; - case 5: op = rv_op_csrrwi; break; + case 5: + switch (operand_csr12(inst)) { + case 1: op = rv_op_fsflagsi; break; + case 2: op = rv_op_fsrmi; break; + default: op = rv_op_csrrwi; break; + } + break; case 6: op = rv_op_csrrsi; break; case 7: op = rv_op_csrrci; break; } @@ -4991,16 +4989,6 @@ static bool check_constraints(rv_decode *dec, const rvc_constraint *c) return false; } break; - case rvc_csr_eq_0x001: - if (!(imm == 0x001)) { - return false; - } - break; - case rvc_csr_eq_0x002: - if (!(imm == 0x002)) { - return false; - } - break; default: break; } c++; diff --git a/disas/riscv.h b/disas/riscv.h index d8c5acd969..3bbcbf10fb 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -84,8 +84,6 @@ typedef enum { rvc_imm_eq_zero, rvc_imm_eq_n1, rvc_imm_eq_p1, - rvc_csr_eq_0x001, - rvc_csr_eq_0x002, } rvc_constraint; typedef enum { From 4abc45a78ff3cb6dbb2d74d8d651e2325c731c28 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:15 -0700 Subject: [PATCH 540/627] disas/riscv: Break pseudo loop for jal and jalr These were clearly intending to simplify jal ra, foo to jal foo and similarly for jalr, but the pseudo expansion looped back to the original jal/jalr with the full format. Add new opcode expansions dropping the implied ra. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-26-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index d3cbfb86ac..fe503b6cae 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -326,6 +326,8 @@ typedef enum { rv_op_bgez = 295, rv_op_bltz = 296, rv_op_bgtz = 297, + rv_op_jal_ra = 298, + rv_op_jalr_ra = 299, rv_op_j = 302, rv_op_ret = 303, rv_op_jr = 304, @@ -1029,9 +1031,9 @@ static const char rv_fli_name_const[32][9] = /* pseudo-instruction constraints */ -static const rvc_constraint rvcc_jal[] = { rvc_rd_eq_ra, rvc_end }; -static const rvc_constraint rvcc_jalr[] = { rvc_rd_eq_ra, rvc_imm_eq_zero, - rvc_end }; +static const rvc_constraint rvcc_jal_ra[] = { rvc_rd_eq_ra, rvc_end }; +static const rvc_constraint rvcc_jalr_ra[] = { rvc_rd_eq_ra, rvc_imm_eq_zero, + rvc_end }; static const rvc_constraint rvcc_nop[] = { rvc_rd_eq_x0, rvc_rs1_eq_x0, rvc_imm_eq_zero, rvc_end }; static const rvc_constraint rvcc_mv[] = { rvc_imm_eq_zero, rvc_end }; @@ -1068,14 +1070,14 @@ static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, static const rv_comp_data rvcp_jal[] = { { rv_op_j, rvcc_j }, - { rv_op_jal, rvcc_jal }, + { rv_op_jal_ra, rvcc_jal_ra }, { rv_op_illegal, NULL } }; static const rv_comp_data rvcp_jalr[] = { { rv_op_ret, rvcc_ret }, { rv_op_jr, rvcc_jr }, - { rv_op_jalr, rvcc_jalr }, + { rv_op_jalr_ra, rvcc_jalr_ra }, { rv_op_illegal, NULL } }; @@ -1884,8 +1886,8 @@ static const rv_opcode_data rvi_opcode_data[] = { { "bgez", rv_codec_sb, rv_fmt_rs1_offset }, { "bltz", rv_codec_sb, rv_fmt_rs1_offset }, { "bgtz", rv_codec_sb, rv_fmt_rs2_offset }, - { }, - { }, + { "jal", rv_codec_none, rv_fmt_offset }, /* rv_op_jal_ra */ + { "jalr", rv_codec_none, rv_fmt_rs1 }, /* rv_op_jalr_ra */ { }, { }, { "j", rv_codec_uj, rv_fmt_offset }, From 6b1230862c221986c1548c423db4b48967de09ea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:16 -0700 Subject: [PATCH 541/627] disas/riscv: Allow decode_inst_lift_pseudo to loop Allow pseudo expansion to proceed in multiple steps. Assert that we don't have simple loops. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-27-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index fe503b6cae..b8e5b124a5 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5259,9 +5259,9 @@ static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, if (comp_data) { while (comp_data->constraints) { if (check_constraints(dec, comp_data->constraints)) { - dec->op = comp_data->op; - op = &dec->opcode_data[dec->op]; - break; + const rv_opcode_data *new_op = &dec->opcode_data[comp_data->op]; + assert(new_op != op); + return decode_inst_lift_pseudo(dec, new_op); } comp_data++; } From 34adc6c2dc4c8771ce80b04b87e6b1c7fd96c457 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:17 -0700 Subject: [PATCH 542/627] disas/riscv: Handle decompression via decode_inst_lift_pseudo Introduce a DECOMP macro that expands an rv_comp_data that always succeeds. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-28-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 113 +++++++++++++++++++++++--------------------------- disas/riscv.h | 1 - 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index b8e5b124a5..a359badab5 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1065,6 +1065,7 @@ static const rvc_constraint rvcc_ret[] = { rvc_rd_eq_x0, rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, rvc_end }; +static const rvc_constraint rvcc_true[] = { rvc_end }; /* pseudo-instruction metadata */ @@ -1190,6 +1191,9 @@ static const rv_comp_data rvcp_fsgnjx_q[] = { { rv_op_illegal, NULL } }; +/* Convert compressed insns into normal insns via pseudo expansion. */ +#define DECOMP(X) &(const rv_comp_data){ X, rvcc_true } + /* operand extractors */ static uint32_t operand_rd(rv_inst inst) @@ -1815,52 +1819,52 @@ static const rv_opcode_data rvi_opcode_data[] = { { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, - { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld }, - { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw }, - { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw }, - { "c.fsd", rv_codec_cs_sd, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd }, - { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw }, - { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw }, + { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, + { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, DECOMP(rv_op_fld) }, + { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lw) }, + { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, DECOMP(rv_op_flw) }, + { "c.fsd", rv_codec_cs_sd, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsd) }, + { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sw) }, + { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsw) }, { }, - { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, - { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal }, - { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, - { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi }, - { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui }, - { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli }, - { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai }, - { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi }, - { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub }, - { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor }, - { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or }, - { "c.and", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_and }, - { "c.subw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_subw }, - { "c.addw", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_addw }, - { "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal }, - { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq }, - { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne }, - { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli }, - { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld }, - { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw }, - { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw }, - { "c.jr", rv_codec_cr_jr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr }, - { "c.mv", rv_codec_cr_mv, rv_fmt_rd_rs1_rs2, NULL, rv_op_addi }, - { "c.ebreak", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_ebreak }, - { "c.jalr", rv_codec_cr_jalr, rv_fmt_rd_rs1_offset, NULL, rv_op_jalr }, - { "c.add", rv_codec_cr, rv_fmt_rd_rs1_rs2, NULL, rv_op_add }, - { "c.fsdsp", rv_codec_css_sdsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsd }, - { "c.swsp", rv_codec_css_swsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw }, - { "c.fswsp", rv_codec_css_swsp, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw }, - { "c.ld", rv_codec_cl_ld, rv_fmt_rd_offset_rs1, NULL, rv_op_ld }, - { "c.sd", rv_codec_cs_sd, rv_fmt_rs2_offset_rs1, NULL, rv_op_sd }, - { "c.addiw", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addiw }, - { "c.ldsp", rv_codec_ci_ldsp, rv_fmt_rd_offset_rs1, NULL, rv_op_ld }, - { "c.sdsp", rv_codec_css_sdsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sd }, - { "c.lq", rv_codec_cl_lq, rv_fmt_rd_offset_rs1, NULL, rv_op_lq }, - { "c.sq", rv_codec_cs_sq, rv_fmt_rs2_offset_rs1, NULL, rv_op_sq }, - { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lq }, - { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, NULL, rv_op_sq }, + { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, + { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, DECOMP(rv_op_jal) }, + { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, + { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, + { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, DECOMP(rv_op_lui) }, + { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_srli) }, + { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_srai) }, + { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, DECOMP(rv_op_andi) }, + { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_sub) }, + { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_xor) }, + { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_or) }, + { "c.and", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_and) }, + { "c.subw", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_subw) }, + { "c.addw", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_addw) }, + { "c.j", rv_codec_cj, rv_fmt_rd_offset, DECOMP(rv_op_jal) }, + { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, DECOMP(rv_op_beq) }, + { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, DECOMP(rv_op_bne) }, + { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_slli) }, + { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, DECOMP(rv_op_fld) }, + { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lw) }, + { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, DECOMP(rv_op_flw) }, + { "c.jr", rv_codec_cr_jr, rv_fmt_rd_rs1_offset, DECOMP(rv_op_jalr) }, + { "c.mv", rv_codec_cr_mv, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_addi) }, + { "c.ebreak", rv_codec_ci_none, rv_fmt_none, DECOMP(rv_op_ebreak) }, + { "c.jalr", rv_codec_cr_jalr, rv_fmt_rd_rs1_offset, DECOMP(rv_op_jalr) }, + { "c.add", rv_codec_cr, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_add) }, + { "c.fsdsp", rv_codec_css_sdsp, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsd) }, + { "c.swsp", rv_codec_css_swsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sw) }, + { "c.fswsp", rv_codec_css_swsp, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsw) }, + { "c.ld", rv_codec_cl_ld, rv_fmt_rd_offset_rs1, DECOMP(rv_op_ld) }, + { "c.sd", rv_codec_cs_sd, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sd) }, + { "c.addiw", rv_codec_ci, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addiw) }, + { "c.ldsp", rv_codec_ci_ldsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_ld) }, + { "c.sdsp", rv_codec_css_sdsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sd) }, + { "c.lq", rv_codec_cl_lq, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lq) }, + { "c.sq", rv_codec_cs_sq, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sq) }, + { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lq) }, + { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sq) }, { "nop", rv_codec_i, rv_fmt_none }, { "mv", rv_codec_i, rv_fmt_rd_rs1 }, { "not", rv_codec_i, rv_fmt_rd_rs1 }, @@ -2542,8 +2546,8 @@ static const rv_opcode_data rvi_opcode_data[] = { { "ssrdp", rv_codec_r, rv_fmt_rd }, { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, NULL, rv_op_sspush }, - { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk }, + { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, DECOMP(rv_op_sspush) }, + { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, DECOMP(rv_op_sspopchk) }, { "cbo.inval", rv_codec_r, rv_fmt_rs1 }, { "cbo.clean", rv_codec_r, rv_fmt_rs1 }, { "cbo.flush", rv_codec_r, rv_fmt_rs1 }, @@ -5269,20 +5273,6 @@ static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, return op; } -/* decompress instruction */ - -static const rv_opcode_data *decode_inst_decompress(rv_decode *dec, - const rv_opcode_data *op) -{ - int decomp_op = op->decomp; - - if (decomp_op != rv_op_illegal) { - dec->op = decomp_op; - op = &dec->opcode_data[decomp_op]; - } - return op; -} - /* disassemble instruction */ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, @@ -5333,7 +5323,6 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, op = &dec.opcode_data[dec.op]; decode_inst_operands(&dec, isa, op); - op = decode_inst_decompress(&dec, op); op = decode_inst_lift_pseudo(&dec, op); return format_inst(24, &dec, op); } diff --git a/disas/riscv.h b/disas/riscv.h index 3bbcbf10fb..ea7141d3b5 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -174,7 +174,6 @@ typedef struct { rv_codec codec; const char *format; const rv_comp_data *pseudo; - rv_opcode decomp; } rv_opcode_data; typedef struct { From ed3a538849dab7e945a2e76df4bcd6f48898d618 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:18 -0700 Subject: [PATCH 543/627] disas/riscv: Drop format from DECOMP insns The format for these will never be used -- we will use the format from the decompressed insn. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-29-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 94 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index a359badab5..e0b3d22031 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1819,52 +1819,52 @@ static const rv_opcode_data rvi_opcode_data[] = { { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, - { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, DECOMP(rv_op_fld) }, - { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lw) }, - { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, DECOMP(rv_op_flw) }, - { "c.fsd", rv_codec_cs_sd, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsd) }, - { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sw) }, - { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsw) }, + { "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(rv_op_addi) }, + { "c.fld", rv_codec_cl_ld, NULL, DECOMP(rv_op_fld) }, + { "c.lw", rv_codec_cl_lw, NULL, DECOMP(rv_op_lw) }, + { "c.flw", rv_codec_cl_lw, NULL, DECOMP(rv_op_flw) }, + { "c.fsd", rv_codec_cs_sd, NULL, DECOMP(rv_op_fsd) }, + { "c.sw", rv_codec_cs_sw, NULL, DECOMP(rv_op_sw) }, + { "c.fsw", rv_codec_cs_sw, NULL, DECOMP(rv_op_fsw) }, { }, - { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, - { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, DECOMP(rv_op_jal) }, - { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, - { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addi) }, - { "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, DECOMP(rv_op_lui) }, - { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_srli) }, - { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_srai) }, - { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, DECOMP(rv_op_andi) }, - { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_sub) }, - { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_xor) }, - { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_or) }, - { "c.and", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_and) }, - { "c.subw", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_subw) }, - { "c.addw", rv_codec_cs, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_addw) }, - { "c.j", rv_codec_cj, rv_fmt_rd_offset, DECOMP(rv_op_jal) }, - { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, DECOMP(rv_op_beq) }, - { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, DECOMP(rv_op_bne) }, - { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, DECOMP(rv_op_slli) }, - { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, DECOMP(rv_op_fld) }, - { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lw) }, - { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, DECOMP(rv_op_flw) }, - { "c.jr", rv_codec_cr_jr, rv_fmt_rd_rs1_offset, DECOMP(rv_op_jalr) }, - { "c.mv", rv_codec_cr_mv, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_addi) }, - { "c.ebreak", rv_codec_ci_none, rv_fmt_none, DECOMP(rv_op_ebreak) }, - { "c.jalr", rv_codec_cr_jalr, rv_fmt_rd_rs1_offset, DECOMP(rv_op_jalr) }, - { "c.add", rv_codec_cr, rv_fmt_rd_rs1_rs2, DECOMP(rv_op_add) }, - { "c.fsdsp", rv_codec_css_sdsp, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsd) }, - { "c.swsp", rv_codec_css_swsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sw) }, - { "c.fswsp", rv_codec_css_swsp, rv_fmt_frs2_offset_rs1, DECOMP(rv_op_fsw) }, - { "c.ld", rv_codec_cl_ld, rv_fmt_rd_offset_rs1, DECOMP(rv_op_ld) }, - { "c.sd", rv_codec_cs_sd, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sd) }, - { "c.addiw", rv_codec_ci, rv_fmt_rd_rs1_imm, DECOMP(rv_op_addiw) }, - { "c.ldsp", rv_codec_ci_ldsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_ld) }, - { "c.sdsp", rv_codec_css_sdsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sd) }, - { "c.lq", rv_codec_cl_lq, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lq) }, - { "c.sq", rv_codec_cs_sq, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sq) }, - { "c.lqsp", rv_codec_ci_lqsp, rv_fmt_rd_offset_rs1, DECOMP(rv_op_lq) }, - { "c.sqsp", rv_codec_css_sqsp, rv_fmt_rs2_offset_rs1, DECOMP(rv_op_sq) }, + { "c.addi", rv_codec_ci, NULL, DECOMP(rv_op_addi) }, + { "c.jal", rv_codec_cj_jal, NULL, DECOMP(rv_op_jal) }, + { "c.li", rv_codec_ci_li, NULL, DECOMP(rv_op_addi) }, + { "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(rv_op_addi) }, + { "c.lui", rv_codec_ci_lui, NULL, DECOMP(rv_op_lui) }, + { "c.srli", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srli) }, + { "c.srai", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srai) }, + { "c.andi", rv_codec_cb_imm, NULL, DECOMP(rv_op_andi) }, + { "c.sub", rv_codec_cs, NULL, DECOMP(rv_op_sub) }, + { "c.xor", rv_codec_cs, NULL, DECOMP(rv_op_xor) }, + { "c.or", rv_codec_cs, NULL, DECOMP(rv_op_or) }, + { "c.and", rv_codec_cs, NULL, DECOMP(rv_op_and) }, + { "c.subw", rv_codec_cs, NULL, DECOMP(rv_op_subw) }, + { "c.addw", rv_codec_cs, NULL, DECOMP(rv_op_addw) }, + { "c.j", rv_codec_cj, NULL, DECOMP(rv_op_jal) }, + { "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beq) }, + { "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bne) }, + { "c.slli", rv_codec_ci_sh6, NULL, DECOMP(rv_op_slli) }, + { "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_fld) }, + { "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_lw) }, + { "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_flw) }, + { "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jalr) }, + { "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_addi) }, + { "c.ebreak", rv_codec_ci_none, NULL, DECOMP(rv_op_ebreak) }, + { "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(rv_op_jalr) }, + { "c.add", rv_codec_cr, NULL, DECOMP(rv_op_add) }, + { "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_fsd) }, + { "c.swsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_sw) }, + { "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_fsw) }, + { "c.ld", rv_codec_cl_ld, NULL, DECOMP(rv_op_ld) }, + { "c.sd", rv_codec_cs_sd, NULL, DECOMP(rv_op_sd) }, + { "c.addiw", rv_codec_ci, NULL, DECOMP(rv_op_addiw) }, + { "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_ld) }, + { "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_sd) }, + { "c.lq", rv_codec_cl_lq, NULL, DECOMP(rv_op_lq) }, + { "c.sq", rv_codec_cs_sq, NULL, DECOMP(rv_op_sq) }, + { "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq) }, + { "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq) }, { "nop", rv_codec_i, rv_fmt_none }, { "mv", rv_codec_i, rv_fmt_rd_rs1 }, { "not", rv_codec_i, rv_fmt_rd_rs1 }, @@ -2546,8 +2546,8 @@ static const rv_opcode_data rvi_opcode_data[] = { { "ssrdp", rv_codec_r, rv_fmt_rd }, { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, DECOMP(rv_op_sspush) }, - { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, DECOMP(rv_op_sspopchk) }, + { "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspush) }, + { "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspopchk) }, { "cbo.inval", rv_codec_r, rv_fmt_rs1 }, { "cbo.clean", rv_codec_r, rv_fmt_rs1 }, { "cbo.flush", rv_codec_r, rv_fmt_rs1 }, From 0a2382f0867a1f66b3ae79d974426aa939eaf129 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:19 -0700 Subject: [PATCH 544/627] disas/riscv: Tidy rv_comp_data terminators Use { } instead of two zeros. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-30-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index e0b3d22031..f3c9213fd1 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1072,123 +1072,123 @@ static const rvc_constraint rvcc_true[] = { rvc_end }; static const rv_comp_data rvcp_jal[] = { { rv_op_j, rvcc_j }, { rv_op_jal_ra, rvcc_jal_ra }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_jalr[] = { { rv_op_ret, rvcc_ret }, { rv_op_jr, rvcc_jr }, { rv_op_jalr_ra, rvcc_jalr_ra }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_beq[] = { { rv_op_beqz, rvcc_beqz }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_bne[] = { { rv_op_bnez, rvcc_bnez }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_blt[] = { { rv_op_bltz, rvcc_bltz }, { rv_op_bgtz, rvcc_bgtz }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_bge[] = { { rv_op_blez, rvcc_blez }, { rv_op_bgez, rvcc_bgez }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_addi[] = { { rv_op_nop, rvcc_nop }, { rv_op_mv, rvcc_mv }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_sltiu[] = { { rv_op_seqz, rvcc_seqz }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_xori[] = { { rv_op_not, rvcc_not }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_sub[] = { { rv_op_neg, rvcc_neg }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_slt[] = { { rv_op_sltz, rvcc_sltz }, { rv_op_sgtz, rvcc_sgtz }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_sltu[] = { { rv_op_snez, rvcc_snez }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_addiw[] = { { rv_op_sext_w, rvcc_sext_w }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_subw[] = { { rv_op_negw, rvcc_negw }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnj_s[] = { { rv_op_fmv_s, rvcc_fmv_s }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjn_s[] = { { rv_op_fneg_s, rvcc_fneg_s }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjx_s[] = { { rv_op_fabs_s, rvcc_fabs_s }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnj_d[] = { { rv_op_fmv_d, rvcc_fmv_d }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjn_d[] = { { rv_op_fneg_d, rvcc_fneg_d }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjx_d[] = { { rv_op_fabs_d, rvcc_fabs_d }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnj_q[] = { { rv_op_fmv_q, rvcc_fmv_q }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjn_q[] = { { rv_op_fneg_q, rvcc_fneg_q }, - { rv_op_illegal, NULL } + { }, }; static const rv_comp_data rvcp_fsgnjx_q[] = { { rv_op_fabs_q, rvcc_fabs_q }, - { rv_op_illegal, NULL } + { }, }; /* Convert compressed insns into normal insns via pseudo expansion. */ From 583b84e18f4e793aade850315013f60ed8ae2d84 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:20 -0700 Subject: [PATCH 545/627] disas/riscv: Chain "ret" pseudo off "jr" pseudo "jr" has already checked two conditions that apply to "ret". Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-31-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index f3c9213fd1..91f6d9e4af 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1061,8 +1061,7 @@ static const rvc_constraint rvcc_bgez[] = { rvc_rs2_eq_x0, rvc_end }; static const rvc_constraint rvcc_bltz[] = { rvc_rs2_eq_x0, rvc_end }; static const rvc_constraint rvcc_bgtz[] = { rvc_rs1_eq_x0, rvc_end }; static const rvc_constraint rvcc_j[] = { rvc_rd_eq_x0, rvc_end }; -static const rvc_constraint rvcc_ret[] = { rvc_rd_eq_x0, rvc_rs1_eq_ra, - rvc_end }; +static const rvc_constraint rvcc_ret[] = { rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, rvc_end }; static const rvc_constraint rvcc_true[] = { rvc_end }; @@ -1076,12 +1075,16 @@ static const rv_comp_data rvcp_jal[] = { }; static const rv_comp_data rvcp_jalr[] = { - { rv_op_ret, rvcc_ret }, { rv_op_jr, rvcc_jr }, { rv_op_jalr_ra, rvcc_jalr_ra }, { }, }; +static const rv_comp_data rvcp_jr[] = { + { rv_op_ret, rvcc_ret }, + { }, +}; + static const rv_comp_data rvcp_beq[] = { { rv_op_beqz, rvcc_beqz }, { }, @@ -1896,7 +1899,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { }, { "j", rv_codec_uj, rv_fmt_offset }, { "ret", rv_codec_i, rv_fmt_none }, - { "jr", rv_codec_i, rv_fmt_rs1 }, + { "jr", rv_codec_i, rv_fmt_rs1, rvcp_jr }, { "rdcycle", rv_codec_i_csr, rv_fmt_rd }, { "rdtime", rv_codec_i_csr, rv_fmt_rd }, { "rdinstret", rv_codec_i_csr, rv_fmt_rd }, From 78b2b441a6cc364d63874e0d35391345b36038b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:21 -0700 Subject: [PATCH 546/627] disas/riscv: Chain "nop" pseudo off "mv" pseudo "mv" has already checked a condition that applies to "nop". Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-32-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 91f6d9e4af..7fa76b2d15 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1035,7 +1035,7 @@ static const rvc_constraint rvcc_jal_ra[] = { rvc_rd_eq_ra, rvc_end }; static const rvc_constraint rvcc_jalr_ra[] = { rvc_rd_eq_ra, rvc_imm_eq_zero, rvc_end }; static const rvc_constraint rvcc_nop[] = { rvc_rd_eq_x0, rvc_rs1_eq_x0, - rvc_imm_eq_zero, rvc_end }; + rvc_end }; static const rvc_constraint rvcc_mv[] = { rvc_imm_eq_zero, rvc_end }; static const rvc_constraint rvcc_not[] = { rvc_imm_eq_n1, rvc_end }; static const rvc_constraint rvcc_neg[] = { rvc_rs1_eq_x0, rvc_end }; @@ -1108,11 +1108,15 @@ static const rv_comp_data rvcp_bge[] = { }; static const rv_comp_data rvcp_addi[] = { - { rv_op_nop, rvcc_nop }, { rv_op_mv, rvcc_mv }, { }, }; +static const rv_comp_data rvcp_mv[] = { + { rv_op_nop, rvcc_nop }, + { }, +}; + static const rv_comp_data rvcp_sltiu[] = { { rv_op_seqz, rvcc_seqz }, { }, @@ -1869,7 +1873,7 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq) }, { "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq) }, { "nop", rv_codec_i, rv_fmt_none }, - { "mv", rv_codec_i, rv_fmt_rd_rs1 }, + { "mv", rv_codec_i, rv_fmt_rd_rs1, rvcp_mv }, { "not", rv_codec_i, rv_fmt_rd_rs1 }, { "neg", rv_codec_r, rv_fmt_rd_rs2 }, { "negw", rv_codec_r, rv_fmt_rd_rs2 }, From 73a0f25feba58f356ba65d5b888b60744331f62a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:22 -0700 Subject: [PATCH 547/627] disas/riscv: Use rv_codec_illegal for pseudos The codec is never used, since we arrive into pseudos from a decoding of another opcode. Assert that rv_codec_illegal is never decoded. Use rv_codec_none for rv_op_illegal. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-33-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 68 +++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 7fa76b2d15..dedd925077 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1599,7 +1599,7 @@ static uint32_t operand_lpl(rv_inst inst) /* instruction metadata */ static const rv_opcode_data rvi_opcode_data[] = { - { "illegal", rv_codec_illegal, rv_fmt_none }, + { "illegal", rv_codec_none, rv_fmt_none }, { "lui", rv_codec_u, rv_fmt_rd_uimm }, { "auipc", rv_codec_u, rv_fmt_rd_uoffset }, { "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal }, @@ -1872,38 +1872,38 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.sq", rv_codec_cs_sq, NULL, DECOMP(rv_op_sq) }, { "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq) }, { "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq) }, - { "nop", rv_codec_i, rv_fmt_none }, - { "mv", rv_codec_i, rv_fmt_rd_rs1, rvcp_mv }, - { "not", rv_codec_i, rv_fmt_rd_rs1 }, - { "neg", rv_codec_r, rv_fmt_rd_rs2 }, - { "negw", rv_codec_r, rv_fmt_rd_rs2 }, - { "sext.w", rv_codec_i, rv_fmt_rd_rs1 }, - { "seqz", rv_codec_i, rv_fmt_rd_rs1 }, - { "snez", rv_codec_r, rv_fmt_rd_rs2 }, - { "sltz", rv_codec_r, rv_fmt_rd_rs1 }, - { "sgtz", rv_codec_r, rv_fmt_rd_rs2 }, - { "fmv.s", rv_codec_r, rv_fmt_frd_frs1 }, - { "fabs.s", rv_codec_r, rv_fmt_frd_frs1 }, - { "fneg.s", rv_codec_r, rv_fmt_frd_frs1 }, - { "fmv.d", rv_codec_r, rv_fmt_frd_frs1 }, - { "fabs.d", rv_codec_r, rv_fmt_frd_frs1 }, - { "fneg.d", rv_codec_r, rv_fmt_frd_frs1 }, - { "fmv.q", rv_codec_r, rv_fmt_frd_frs1 }, - { "fabs.q", rv_codec_r, rv_fmt_frd_frs1 }, - { "fneg.q", rv_codec_r, rv_fmt_frd_frs1 }, - { "beqz", rv_codec_sb, rv_fmt_rs1_offset }, - { "bnez", rv_codec_sb, rv_fmt_rs1_offset }, - { "blez", rv_codec_sb, rv_fmt_rs2_offset }, - { "bgez", rv_codec_sb, rv_fmt_rs1_offset }, - { "bltz", rv_codec_sb, rv_fmt_rs1_offset }, - { "bgtz", rv_codec_sb, rv_fmt_rs2_offset }, - { "jal", rv_codec_none, rv_fmt_offset }, /* rv_op_jal_ra */ - { "jalr", rv_codec_none, rv_fmt_rs1 }, /* rv_op_jalr_ra */ + { "nop", rv_codec_illegal, rv_fmt_none }, + { "mv", rv_codec_illegal, rv_fmt_rd_rs1, rvcp_mv }, + { "not", rv_codec_illegal, rv_fmt_rd_rs1 }, + { "neg", rv_codec_illegal, rv_fmt_rd_rs2 }, + { "negw", rv_codec_illegal, rv_fmt_rd_rs2 }, + { "sext.w", rv_codec_illegal, rv_fmt_rd_rs1 }, + { "seqz", rv_codec_illegal, rv_fmt_rd_rs1 }, + { "snez", rv_codec_illegal, rv_fmt_rd_rs2 }, + { "sltz", rv_codec_illegal, rv_fmt_rd_rs1 }, + { "sgtz", rv_codec_illegal, rv_fmt_rd_rs2 }, + { "fmv.s", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fabs.s", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fneg.s", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fmv.d", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fabs.d", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fneg.d", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fmv.q", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fabs.q", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "fneg.q", rv_codec_illegal, rv_fmt_frd_frs1 }, + { "beqz", rv_codec_illegal, rv_fmt_rs1_offset }, + { "bnez", rv_codec_illegal, rv_fmt_rs1_offset }, + { "blez", rv_codec_illegal, rv_fmt_rs2_offset }, + { "bgez", rv_codec_illegal, rv_fmt_rs1_offset }, + { "bltz", rv_codec_illegal, rv_fmt_rs1_offset }, + { "bgtz", rv_codec_illegal, rv_fmt_rs2_offset }, + { "jal", rv_codec_illegal, rv_fmt_offset }, /* rv_op_jal_ra */ + { "jalr", rv_codec_illegal, rv_fmt_rs1 }, /* rv_op_jalr_ra */ { }, { }, - { "j", rv_codec_uj, rv_fmt_offset }, - { "ret", rv_codec_i, rv_fmt_none }, - { "jr", rv_codec_i, rv_fmt_rs1, rvcp_jr }, + { "j", rv_codec_illegal, rv_fmt_offset }, + { "ret", rv_codec_illegal, rv_fmt_none }, + { "jr", rv_codec_illegal, rv_fmt_rs1, rvcp_jr }, { "rdcycle", rv_codec_i_csr, rv_fmt_rd }, { "rdtime", rv_codec_i_csr, rv_fmt_rd }, { "rdinstret", rv_codec_i_csr, rv_fmt_rd }, @@ -4551,8 +4551,6 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, rv_inst inst = dec->inst; switch (op->codec) { - case rv_codec_illegal: - break; case rv_codec_none: dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; dec->imm = 0; @@ -4946,7 +4944,9 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, dec->rs1 = dec->rs2 = operand_crs1(inst); dec->imm = 0; break; - }; + default: + g_assert_not_reached(); + } } /* check constraint */ From 8594445d444aa6a842194cc15ab88ee73ca08857 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:23 -0700 Subject: [PATCH 548/627] disas/riscv: Simplify some insn decompressions Route "c.j" to "j" instead of "jal", etc. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-34-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index dedd925077..342e2db3cc 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1848,15 +1848,15 @@ static const rv_opcode_data rvi_opcode_data[] = { { "c.and", rv_codec_cs, NULL, DECOMP(rv_op_and) }, { "c.subw", rv_codec_cs, NULL, DECOMP(rv_op_subw) }, { "c.addw", rv_codec_cs, NULL, DECOMP(rv_op_addw) }, - { "c.j", rv_codec_cj, NULL, DECOMP(rv_op_jal) }, - { "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beq) }, - { "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bne) }, + { "c.j", rv_codec_cj, NULL, DECOMP(rv_op_j) }, + { "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beqz) }, + { "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bnez) }, { "c.slli", rv_codec_ci_sh6, NULL, DECOMP(rv_op_slli) }, { "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_fld) }, { "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_lw) }, { "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_flw) }, - { "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jalr) }, - { "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_addi) }, + { "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jr) }, + { "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_mv) }, { "c.ebreak", rv_codec_ci_none, NULL, DECOMP(rv_op_ebreak) }, { "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(rv_op_jalr) }, { "c.add", rv_codec_cr, NULL, DECOMP(rv_op_add) }, From 6a238ffe354505ad1dd3354a90caa7c64eac6092 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:24 -0700 Subject: [PATCH 549/627] disas/riscv: Store op pointer in rv_comp_data Store a pointer instead of an array index. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-35-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 69 ++++++++++++++++++++++++++------------------------- disas/riscv.h | 8 +++--- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 342e2db3cc..9d05e86c09 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1068,138 +1068,140 @@ static const rvc_constraint rvcc_true[] = { rvc_end }; /* pseudo-instruction metadata */ +static const rv_opcode_data rvi_opcode_data[]; + static const rv_comp_data rvcp_jal[] = { - { rv_op_j, rvcc_j }, - { rv_op_jal_ra, rvcc_jal_ra }, + { &rvi_opcode_data[rv_op_j], rvcc_j }, + { &rvi_opcode_data[rv_op_jal_ra], rvcc_jal_ra }, { }, }; static const rv_comp_data rvcp_jalr[] = { - { rv_op_jr, rvcc_jr }, - { rv_op_jalr_ra, rvcc_jalr_ra }, + { &rvi_opcode_data[rv_op_jr], rvcc_jr }, + { &rvi_opcode_data[rv_op_jalr_ra], rvcc_jalr_ra }, { }, }; static const rv_comp_data rvcp_jr[] = { - { rv_op_ret, rvcc_ret }, + { &rvi_opcode_data[rv_op_ret], rvcc_ret }, { }, }; static const rv_comp_data rvcp_beq[] = { - { rv_op_beqz, rvcc_beqz }, + { &rvi_opcode_data[rv_op_beqz], rvcc_beqz }, { }, }; static const rv_comp_data rvcp_bne[] = { - { rv_op_bnez, rvcc_bnez }, + { &rvi_opcode_data[rv_op_bnez], rvcc_bnez }, { }, }; static const rv_comp_data rvcp_blt[] = { - { rv_op_bltz, rvcc_bltz }, - { rv_op_bgtz, rvcc_bgtz }, + { &rvi_opcode_data[rv_op_bltz], rvcc_bltz }, + { &rvi_opcode_data[rv_op_bgtz], rvcc_bgtz }, { }, }; static const rv_comp_data rvcp_bge[] = { - { rv_op_blez, rvcc_blez }, - { rv_op_bgez, rvcc_bgez }, + { &rvi_opcode_data[rv_op_blez], rvcc_blez }, + { &rvi_opcode_data[rv_op_bgez], rvcc_bgez }, { }, }; static const rv_comp_data rvcp_addi[] = { - { rv_op_mv, rvcc_mv }, + { &rvi_opcode_data[rv_op_mv], rvcc_mv }, { }, }; static const rv_comp_data rvcp_mv[] = { - { rv_op_nop, rvcc_nop }, + { &rvi_opcode_data[rv_op_nop], rvcc_nop }, { }, }; static const rv_comp_data rvcp_sltiu[] = { - { rv_op_seqz, rvcc_seqz }, + { &rvi_opcode_data[rv_op_seqz], rvcc_seqz }, { }, }; static const rv_comp_data rvcp_xori[] = { - { rv_op_not, rvcc_not }, + { &rvi_opcode_data[rv_op_not], rvcc_not }, { }, }; static const rv_comp_data rvcp_sub[] = { - { rv_op_neg, rvcc_neg }, + { &rvi_opcode_data[rv_op_neg], rvcc_neg }, { }, }; static const rv_comp_data rvcp_slt[] = { - { rv_op_sltz, rvcc_sltz }, - { rv_op_sgtz, rvcc_sgtz }, + { &rvi_opcode_data[rv_op_sltz], rvcc_sltz }, + { &rvi_opcode_data[rv_op_sgtz], rvcc_sgtz }, { }, }; static const rv_comp_data rvcp_sltu[] = { - { rv_op_snez, rvcc_snez }, + { &rvi_opcode_data[rv_op_snez], rvcc_snez }, { }, }; static const rv_comp_data rvcp_addiw[] = { - { rv_op_sext_w, rvcc_sext_w }, + { &rvi_opcode_data[rv_op_sext_w], rvcc_sext_w }, { }, }; static const rv_comp_data rvcp_subw[] = { - { rv_op_negw, rvcc_negw }, + { &rvi_opcode_data[rv_op_negw], rvcc_negw }, { }, }; static const rv_comp_data rvcp_fsgnj_s[] = { - { rv_op_fmv_s, rvcc_fmv_s }, + { &rvi_opcode_data[rv_op_fmv_s], rvcc_fmv_s }, { }, }; static const rv_comp_data rvcp_fsgnjn_s[] = { - { rv_op_fneg_s, rvcc_fneg_s }, + { &rvi_opcode_data[rv_op_fneg_s], rvcc_fneg_s }, { }, }; static const rv_comp_data rvcp_fsgnjx_s[] = { - { rv_op_fabs_s, rvcc_fabs_s }, + { &rvi_opcode_data[rv_op_fabs_s], rvcc_fabs_s }, { }, }; static const rv_comp_data rvcp_fsgnj_d[] = { - { rv_op_fmv_d, rvcc_fmv_d }, + { &rvi_opcode_data[rv_op_fmv_d], rvcc_fmv_d }, { }, }; static const rv_comp_data rvcp_fsgnjn_d[] = { - { rv_op_fneg_d, rvcc_fneg_d }, + { &rvi_opcode_data[rv_op_fneg_d], rvcc_fneg_d }, { }, }; static const rv_comp_data rvcp_fsgnjx_d[] = { - { rv_op_fabs_d, rvcc_fabs_d }, + { &rvi_opcode_data[rv_op_fabs_d], rvcc_fabs_d }, { }, }; static const rv_comp_data rvcp_fsgnj_q[] = { - { rv_op_fmv_q, rvcc_fmv_q }, + { &rvi_opcode_data[rv_op_fmv_q], rvcc_fmv_q }, { }, }; static const rv_comp_data rvcp_fsgnjn_q[] = { - { rv_op_fneg_q, rvcc_fneg_q }, + { &rvi_opcode_data[rv_op_fneg_q], rvcc_fneg_q }, { }, }; static const rv_comp_data rvcp_fsgnjx_q[] = { - { rv_op_fabs_q, rvcc_fabs_q }, + { &rvi_opcode_data[rv_op_fabs_q], rvcc_fabs_q }, { }, }; /* Convert compressed insns into normal insns via pseudo expansion. */ -#define DECOMP(X) &(const rv_comp_data){ X, rvcc_true } +#define DECOMP(X) &(const rv_comp_data){ &rvi_opcode_data[X], rvcc_true } /* operand extractors */ @@ -5270,9 +5272,8 @@ static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, if (comp_data) { while (comp_data->constraints) { if (check_constraints(dec, comp_data->constraints)) { - const rv_opcode_data *new_op = &dec->opcode_data[comp_data->op]; - assert(new_op != op); - return decode_inst_lift_pseudo(dec, new_op); + assert(op != comp_data->op); + return decode_inst_lift_pseudo(dec, comp_data->op); } comp_data++; } diff --git a/disas/riscv.h b/disas/riscv.h index ea7141d3b5..ab62c0db94 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -164,17 +164,19 @@ typedef enum { /* structures */ +typedef struct rv_opcode_data rv_opcode_data; + typedef struct { - int op; + const rv_opcode_data *op; const rvc_constraint *constraints; } rv_comp_data; -typedef struct { +struct rv_opcode_data { const char *name; rv_codec codec; const char *format; const rv_comp_data *pseudo; -} rv_opcode_data; +}; typedef struct { const RISCVCPUConfig *cfg; From 850708045ab30e2252e30a647a822a5d0e6f2cbd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:25 -0700 Subject: [PATCH 550/627] disas/riscv: Return rv_opcode_data pointer from decoders Rather than putting array + index into rv_decode, return the pointer to the object directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-36-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xlrbr.c | 5 ++-- disas/riscv-xlrbr.h | 2 +- disas/riscv-xthead.c | 55 +++++++++++++++++------------------------- disas/riscv-xthead.h | 22 ++++++++--------- disas/riscv-xventana.c | 5 ++-- disas/riscv-xventana.h | 2 +- disas/riscv.c | 23 +++++++----------- disas/riscv.h | 2 -- 8 files changed, 48 insertions(+), 68 deletions(-) diff --git a/disas/riscv-xlrbr.c b/disas/riscv-xlrbr.c index d0092e9edd..b12916c9da 100644 --- a/disas/riscv-xlrbr.c +++ b/disas/riscv-xlrbr.c @@ -36,7 +36,7 @@ static const rv_opcode_data xlrbr_opcode_data[] = { { "crc32c.d", rv_codec_r, rv_fmt_rd_rs1 }, }; -void decode_xlrbr(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xlrbr(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -76,6 +76,5 @@ void decode_xlrbr(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xlrbr_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xlrbr_opcode_data[op]; } diff --git a/disas/riscv-xlrbr.h b/disas/riscv-xlrbr.h index ebf3d4c133..da14f1b340 100644 --- a/disas/riscv-xlrbr.h +++ b/disas/riscv-xlrbr.h @@ -12,6 +12,6 @@ #include "disas/riscv.h" -void decode_xlrbr(rv_decode *, rv_isa); +const rv_opcode_data *decode_xlrbr(rv_decode *, rv_isa); #endif /* DISAS_RISCV_XLRBR_H */ diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index 757d6ff39f..428a6380e9 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -246,7 +246,7 @@ static const rv_opcode_data xthead_opcode_data[] = { { "th.sync.s", rv_codec_none, rv_fmt_none }, }; -void decode_xtheadba(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadba(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -272,11 +272,10 @@ void decode_xtheadba(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadbb(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadbb(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -331,11 +330,10 @@ void decode_xtheadbb(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadbs(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadbs(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -358,11 +356,10 @@ void decode_xtheadbs(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadcmo(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadcmo(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -437,11 +434,10 @@ void decode_xtheadcmo(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadcondmov(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadcondmov(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -465,11 +461,10 @@ void decode_xtheadcondmov(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -503,11 +498,10 @@ void decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadfmv(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadfmv(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -539,11 +533,10 @@ void decode_xtheadfmv(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadmac(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadmac(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -571,11 +564,10 @@ void decode_xtheadmac(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadmemidx(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadmemidx(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -646,11 +638,10 @@ void decode_xtheadmemidx(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadmempair(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadmempair(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -681,11 +672,10 @@ void decode_xtheadmempair(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } -void decode_xtheadsync(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xtheadsync(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -716,6 +706,5 @@ void decode_xtheadsync(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = xthead_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; } diff --git a/disas/riscv-xthead.h b/disas/riscv-xthead.h index 0c65c8e0af..f2160be8a4 100644 --- a/disas/riscv-xthead.h +++ b/disas/riscv-xthead.h @@ -11,16 +11,16 @@ #include "disas/riscv.h" -void decode_xtheadba(rv_decode *, rv_isa); -void decode_xtheadbb(rv_decode *, rv_isa); -void decode_xtheadbs(rv_decode *, rv_isa); -void decode_xtheadcmo(rv_decode *, rv_isa); -void decode_xtheadcondmov(rv_decode *, rv_isa); -void decode_xtheadfmemidx(rv_decode *, rv_isa); -void decode_xtheadfmv(rv_decode *, rv_isa); -void decode_xtheadmac(rv_decode *, rv_isa); -void decode_xtheadmemidx(rv_decode *, rv_isa); -void decode_xtheadmempair(rv_decode *, rv_isa); -void decode_xtheadsync(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadba(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadbb(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadbs(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadcmo(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadcondmov(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadfmemidx(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadfmv(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadmac(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadmemidx(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadmempair(rv_decode *, rv_isa); +const rv_opcode_data *decode_xtheadsync(rv_decode *, rv_isa); #endif /* DISAS_RISCV_XTHEAD_H */ diff --git a/disas/riscv-xventana.c b/disas/riscv-xventana.c index 4fb9a29d0b..a4e59312d0 100644 --- a/disas/riscv-xventana.c +++ b/disas/riscv-xventana.c @@ -20,7 +20,7 @@ static const rv_opcode_data ventana_opcode_data[] = { { "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, }; -void decode_xventanacondops(rv_decode *dec, rv_isa isa) +const rv_opcode_data *decode_xventanacondops(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -38,6 +38,5 @@ void decode_xventanacondops(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = ventana_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &ventana_opcode_data[op]; } diff --git a/disas/riscv-xventana.h b/disas/riscv-xventana.h index 1006c3be00..d28e84c7e4 100644 --- a/disas/riscv-xventana.h +++ b/disas/riscv-xventana.h @@ -11,6 +11,6 @@ #include "disas/riscv.h" -void decode_xventanacondops(rv_decode*, rv_isa); +const rv_opcode_data *decode_xventanacondops(rv_decode*, rv_isa); #endif /* DISAS_RISCV_XVENTANA_H */ diff --git a/disas/riscv.c b/disas/riscv.c index 9d05e86c09..bc86cb866a 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -2846,7 +2846,7 @@ static const char *csr_name(int csrno) /* decode opcode */ -static void decode_inst_opcode(rv_decode *dec, rv_isa isa) +static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; rv_opcode op = rv_op_illegal; @@ -4541,8 +4541,7 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; } - dec->opcode_data = rvi_opcode_data; - dec->op = op; + return op == rv_op_illegal ? NULL : &rvi_opcode_data[op]; } /* decode operands */ @@ -5291,14 +5290,12 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, .inst = inst, .cfg = cfg, }; - const rv_opcode_data *op; + const rv_opcode_data *op = decode_inst_opcode(&dec, isa); - decode_inst_opcode(&dec, isa); - - if (dec.op == rv_op_illegal && cfg) { + if (!op && cfg) { static const struct { bool (*guard_func)(const RISCVCPUConfig *); - void (*decode_func)(rv_decode *, rv_isa); + const rv_opcode_data *(*decode_func)(rv_decode *, rv_isa); } decoders[] = { { has_xtheadba_p, decode_xtheadba }, { has_xtheadbb_p, decode_xtheadbb }, @@ -5317,19 +5314,17 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { if (decoders[i].guard_func(cfg)) { - decoders[i].decode_func(&dec, isa); - if (dec.op != rv_op_illegal) { + op = decoders[i].decode_func(&dec, isa); + if (op) { break; } } } } - - if (dec.op == rv_op_illegal) { - dec.opcode_data = rvi_opcode_data; + if (!op) { + op = &rvi_opcode_data[rv_op_illegal]; } - op = &dec.opcode_data[dec.op]; decode_inst_operands(&dec, isa, op); op = decode_inst_lift_pseudo(&dec, op); return format_inst(24, &dec, op); diff --git a/disas/riscv.h b/disas/riscv.h index ab62c0db94..241dd47d7f 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -182,10 +182,8 @@ typedef struct { const RISCVCPUConfig *cfg; uint64_t pc; uint64_t inst; - const rv_opcode_data *opcode_data; int32_t imm; int32_t imm1; - uint16_t op; uint8_t rd; uint8_t rs1; uint8_t rs2; From 0da84325e472b43169135010b3dd75e85ca37092 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:26 -0700 Subject: [PATCH 551/627] disas/riscv: Skip post-processing of illegal insns Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Message-ID: <20260812223142.349142-37-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index bc86cb866a..75c2fa11e6 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -5321,12 +5321,14 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, } } } - if (!op) { + + if (op) { + decode_inst_operands(&dec, isa, op); + op = decode_inst_lift_pseudo(&dec, op); + } else { op = &rvi_opcode_data[rv_op_illegal]; } - decode_inst_operands(&dec, isa, op); - op = decode_inst_lift_pseudo(&dec, op); return format_inst(24, &dec, op); } From 78f51b0ea5205bda472652b326caf439d92a2c3b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:27 -0700 Subject: [PATCH 552/627] disas/riscv: Reject all of OP-32 and OP-IMM-32 for RV32 These entire base opcodes are RV64. Reject them all at once rather than one at a time. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-38-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index 75c2fa11e6..e650ad7688 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -3311,6 +3311,10 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) } break; case 6: + /* OP-IMM-32 */ + if (isa == rv32) { + break; + } switch ((inst >> 12) & 0b111) { case 0: op = rv_op_addiw; break; case 1: @@ -3557,6 +3561,10 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) break; case 13: op = rv_op_lui; break; case 14: + /* OP-32 */ + if (isa == rv32) { + break; + } switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) { case 0: op = rv_op_addw; break; From d4151cf2675124e26b3383ae06f7352a23f17399 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:28 -0700 Subject: [PATCH 553/627] disas/riscv: Fix rv32 encoding of zext.h For rv64, pack with rs2 = 0 does not encode zext.h. Cc: qemu-stable@nongnu.org Fixes: 02c1b569a15 ("disas/riscv: Add Zb[abcs] instructions") Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-39-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index e650ad7688..5624e7f60a 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -3506,9 +3506,10 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 14: op = rv_op_rem; break; case 15: op = rv_op_remu; break; case 36: - switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_zext_h; break; - default: op = rv_op_pack; break; + if (isa == rv32 && !((inst >> 20) & 0b11111)) { + op = rv_op_zext_h; + } else { + op = rv_op_pack; } break; case 39: op = rv_op_packh; break; From d610e55c8390a8bfd15d0a4f1521d7fc46e4e0b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:29 -0700 Subject: [PATCH 554/627] disas/riscv: Fix isa decoding of rev8 The encoding of rev8 is different for rv32 and rv64. Cc: qemu-stable@nongnu.org Fixes: 02c1b569a15 ("disas/riscv: Add Zb[abcs] instructions") Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-40-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 5624e7f60a..787340e811 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -3292,8 +3292,16 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 0b01100: op = rv_op_rori; break; case 0b01101: switch ((inst >> 20) & 0b1111111) { - case 0b0011000: op = rv_op_rev8; break; - case 0b0111000: op = rv_op_rev8; break; + case 0b0011000: + if (isa == rv32) { + op = rv_op_rev8; + } + break; + case 0b0111000: + if (isa == rv64) { + op = rv_op_rev8; + } + break; case 0b0000111: op = rv_op_brev8; break; } break; From ecbd3a031f12669da98cdf929cbc7dbb88d3450f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:30 -0700 Subject: [PATCH 555/627] disas/riscv: Fix typo in th.lbib format th.lbib should format the same as th.lbia, and the other increment insns, with the address register in parenthesis. Cc: qemu-stable@nongnu.org Fixes: 318df7238b9 ("disas/riscv: Add support for XThead* instructions") Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-41-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xthead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index 428a6380e9..fbc96631fd 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -189,7 +189,7 @@ static const rv_opcode_data xthead_opcode_data[] = { { "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, /* XTheadMemIdx */ { "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml }, + { "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, { "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, { "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, { "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, From 7a1cca6360e39cc26b9e31d7af613270d6a0cf25 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:31 -0700 Subject: [PATCH 556/627] disas/riscv: Split ventana_opcode_data Move the table to riscv-xventana-op.c.inc and massage the lines into OP() form. Drop vt.illegal as unused. Return pointers to objects directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-42-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xventana-op.c.inc | 2 ++ disas/riscv-xventana.c | 21 ++++++--------------- 2 files changed, 8 insertions(+), 15 deletions(-) create mode 100644 disas/riscv-xventana-op.c.inc diff --git a/disas/riscv-xventana-op.c.inc b/disas/riscv-xventana-op.c.inc new file mode 100644 index 0000000000..0fe4666aee --- /dev/null +++ b/disas/riscv-xventana-op.c.inc @@ -0,0 +1,2 @@ +OP(vt_maskc, "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(vt_maskcn, "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2) diff --git a/disas/riscv-xventana.c b/disas/riscv-xventana.c index a4e59312d0..5d2e07865f 100644 --- a/disas/riscv-xventana.c +++ b/disas/riscv-xventana.c @@ -8,35 +8,26 @@ #include "disas/riscv.h" #include "disas/riscv-xventana.h" -typedef enum { - /* 0 is reserved for rv_op_illegal. */ - ventana_op_vt_maskc = 1, - ventana_op_vt_maskcn = 2, -} rv_ventana_op; - -static const rv_opcode_data ventana_opcode_data[] = { - { "vt.illegal", rv_codec_illegal, rv_fmt_none }, - { "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, -}; +#define OP(N, ...) static const rv_opcode_data op_##N = { __VA_ARGS__ }; +#include "riscv-xventana-op.c.inc" +#undef OP const rv_opcode_data *decode_xventanacondops(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: switch (((inst >> 2) & 0b11111)) { case 30: switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) { - case 6: op = ventana_op_vt_maskc; break; - case 7: op = ventana_op_vt_maskcn; break; + case 6: return &op_vt_maskc; + case 7: return &op_vt_maskcn; } break; } break; } - return op == rv_op_illegal ? NULL : &ventana_opcode_data[op]; + return NULL; } From 5fa5e2df676c68def8d0284eb762f7d1ccebfd44 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:32 -0700 Subject: [PATCH 557/627] disas/riscv: Split xlrbr_opcode_data Move the table to riscv-xlrbr-op.c.inc and massage the lines into OP() form. Drop illegal as unused. Return pointers to objects directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-43-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xlrbr-op.c.inc | 8 ++++++ disas/riscv-xlrbr.c | 54 +++++++++----------------------------- 2 files changed, 20 insertions(+), 42 deletions(-) create mode 100644 disas/riscv-xlrbr-op.c.inc diff --git a/disas/riscv-xlrbr-op.c.inc b/disas/riscv-xlrbr-op.c.inc new file mode 100644 index 0000000000..57add37c24 --- /dev/null +++ b/disas/riscv-xlrbr-op.c.inc @@ -0,0 +1,8 @@ +OP(crc32_b, "crc32.b", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32_h, "crc32.h", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32_w, "crc32.w", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32_d, "crc32.d", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32c_b, "crc32c.b", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32c_h, "crc32c.h", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32c_w, "crc32c.w", rv_codec_r, rv_fmt_rd_rs1) +OP(crc32c_d, "crc32c.d", rv_codec_r, rv_fmt_rd_rs1) diff --git a/disas/riscv-xlrbr.c b/disas/riscv-xlrbr.c index b12916c9da..b4229e5c83 100644 --- a/disas/riscv-xlrbr.c +++ b/disas/riscv-xlrbr.c @@ -8,38 +8,16 @@ */ #include "qemu/osdep.h" - #include "disas/riscv.h" #include "disas/riscv-xlrbr.h" -typedef enum { - /* 0 is reserved for rv_op_illegal. */ - rv_op_crc32_b = 1, - rv_op_crc32_h = 2, - rv_op_crc32_w = 3, - rv_op_crc32_d = 4, - rv_op_crc32c_b = 5, - rv_op_crc32c_h = 6, - rv_op_crc32c_w = 7, - rv_op_crc32c_d = 8, -} rv_xlrbr_op; - -static const rv_opcode_data xlrbr_opcode_data[] = { - { "illegal", rv_codec_illegal, rv_fmt_none }, - { "crc32.b", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32.h", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32.w", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32.d", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32c.b", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32c.h", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32c.w", rv_codec_r, rv_fmt_rd_rs1 }, - { "crc32c.d", rv_codec_r, rv_fmt_rd_rs1 }, -}; +#define OP(N, ...) static const rv_opcode_data op_##N = { __VA_ARGS__ }; +#include "riscv-xlrbr-op.c.inc" +#undef OP const rv_opcode_data *decode_xlrbr(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch ((inst >> 0) & 0b1111111) { case 0b0010011: @@ -47,34 +25,26 @@ const rv_opcode_data *decode_xlrbr(rv_decode *dec, rv_isa isa) case 0b001: switch ((inst >> 20 & 0b111111111111)) { case 0b011000010000: - op = rv_op_crc32_b; - break; + return &op_crc32_b; case 0b011000010001: - op = rv_op_crc32_h; - break; + return &op_crc32_h; case 0b011000010010: - op = rv_op_crc32_w; - break; + return &op_crc32_w; case 0b011000010011: - op = rv_op_crc32_d; - break; + return &op_crc32_d; case 0b011000011000: - op = rv_op_crc32c_b; - break; + return &op_crc32c_b; case 0b011000011001: - op = rv_op_crc32c_h; - break; + return &op_crc32c_h; case 0b011000011010: - op = rv_op_crc32c_w; - break; + return &op_crc32c_w; case 0b011000011011: - op = rv_op_crc32c_d; - break; + return &op_crc32c_d; } break; } break; } - return op == rv_op_illegal ? NULL : &xlrbr_opcode_data[op]; + return NULL; } From 282d8cca8b8475885c126a82627e783089e7f520 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:33 -0700 Subject: [PATCH 558/627] disas/riscv: Split xthead_opcode_data Move the table to riscv-xthead-op.c.inc and massage the lines into OP() form. Drop th.illegal as unused. Return pointers to objects directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-44-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-xthead-op.c.inc | 125 ++++++++++ disas/riscv-xthead.c | 481 +++++++++--------------------------- 2 files changed, 243 insertions(+), 363 deletions(-) create mode 100644 disas/riscv-xthead-op.c.inc diff --git a/disas/riscv-xthead-op.c.inc b/disas/riscv-xthead-op.c.inc new file mode 100644 index 0000000000..1e4e0557cd --- /dev/null +++ b/disas/riscv-xthead-op.c.inc @@ -0,0 +1,125 @@ +/* XTheadBa */ +OP(th_addsl, "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) + +/* XTheadBb */ +OP(th_srri, "th.srri", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm) +OP(th_srriw, "th.srriw", rv_codec_r2_imm5, rv_fmt_rd_rs1_imm) +OP(th_ext, "th.ext", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml) +OP(th_extu, "th.extu", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml) +OP(th_ff0, "th.ff0", rv_codec_r2, rv_fmt_rd_rs1) +OP(th_ff1, "th.ff1", rv_codec_r2, rv_fmt_rd_rs1) +OP(th_rev, "th.rev", rv_codec_r2, rv_fmt_rd_rs1) +OP(th_revw, "th.revw", rv_codec_r2, rv_fmt_rd_rs1) +OP(th_tstnbz, "th.tstnbz", rv_codec_r2, rv_fmt_rd_rs1) + +/* XTheadBs */ +OP(th_tst, "th.tst", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm) + +/* XTheadCmo */ +OP(th_dcache_call, "th.dcache.call", rv_codec_none, rv_fmt_none) +OP(th_dcache_ciall, "th.dcache.ciall", rv_codec_none, rv_fmt_none) +OP(th_dcache_iall, "th.dcache.iall", rv_codec_none, rv_fmt_none) +OP(th_dcache_cpa, "th.dcache.cpa", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_cipa, "th.dcache.cipa", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_ipa, "th.dcache.ipa", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_cva, "th.dcache.cva", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_civa, "th.dcache.civa", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_iva, "th.dcache.iva", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_csw, "th.dcache.csw", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_cisw, "th.dcache.cisw", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_isw, "th.dcache.isw", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_cpal1, "th.dcache.cpal1", rv_codec_r, rv_fmt_rs1) +OP(th_dcache_cval1, "th.dcache.cval1", rv_codec_r, rv_fmt_rs1) +OP(th_icache_iall, "th.icache.iall", rv_codec_none, rv_fmt_none) +OP(th_icache_ialls, "th.icache.ialls", rv_codec_none, rv_fmt_none) +OP(th_icache_ipa, "th.icache.ipa", rv_codec_r, rv_fmt_rs1) +OP(th_icache_iva, "th.icache.iva", rv_codec_r, rv_fmt_rs1) +OP(th_l2cache_call, "th.l2cache.call", rv_codec_none, rv_fmt_none) +OP(th_l2cache_ciall, "th.l2cache.ciall", rv_codec_none, rv_fmt_none) +OP(th_l2cache_iall, "th.l2cache.iall", rv_codec_none, rv_fmt_none) + +/* XTheadCondMov */ +OP(th_mveqz, "th.mveqz", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_mvnez, "th.mvnez", rv_codec_r, rv_fmt_rd_rs1_rs2) + +/* XTheadFMemIdx */ +OP(th_flrd, "th.flrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_flrw, "th.flrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_flurd, "th.flurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_flurw, "th.flurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_fsrd, "th.fsrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_fsrw, "th.fsrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_fsurd, "th.fsurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) +OP(th_fsurw, "th.fsurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm) + +/* XTheadFmv */ +OP(th_fmv_hw_x, "th.fmv.hw.x", rv_codec_r, rv_fmt_rd_frs1) +OP(th_fmv_x_hw, "th.fmv.x.hw", rv_codec_r, rv_fmt_rd_frs1) + +/* XTheadMac */ +OP(th_mula, "th.mula", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_mulaw, "th.mulaw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_mulah, "th.mulah", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_muls, "th.muls", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_mulsw, "th.mulsw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(th_mulsh, "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2) + +/* XTheadMemIdx */ +OP(th_lbia, "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lbib, "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lbuia, "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lbuib, "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lhia, "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lhib, "th.lhib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lhuia, "th.lhuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lhuib, "th.lhuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lwia, "th.lwia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lwib, "th.lwib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lwuia, "th.lwuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lwuib, "th.lwuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_ldia, "th.ldia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_ldib, "th.ldib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_sbia, "th.sbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_sbib, "th.sbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_shia, "th.shia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_shib, "th.shib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_swia, "th.swia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_swib, "th.swib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_sdia, "th.sdia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_sdib, "th.sdib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr) +OP(th_lrb, "th.lrb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrbu, "th.lrbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrh, "th.lrh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrhu, "th.lrhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrw, "th.lrw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrwu, "th.lrwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lrd, "th.lrd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_srb, "th.srb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_srh, "th.srh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_srw, "th.srw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_srd, "th.srd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurb, "th.lurb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurbu, "th.lurbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurh, "th.lurh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurhu, "th.lurhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurw, "th.lurw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurwu, "th.lurwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_lurd, "th.lurd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_surb, "th.surb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_surh, "th.surh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_surw, "th.surw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) +OP(th_surd, "th.surd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm) + +/* XTheadMemPair */ +OP(th_ldd, "th.ldd", rv_codec_r_imm2, rv_fmt_rd2_imm) +OP(th_lwd, "th.lwd", rv_codec_r_imm2, rv_fmt_rd2_imm) +OP(th_lwud, "th.lwud", rv_codec_r_imm2, rv_fmt_rd2_imm) +OP(th_sdd, "th.sdd", rv_codec_r_imm2, rv_fmt_rd2_imm) +OP(th_swd, "th.swd", rv_codec_r_imm2, rv_fmt_rd2_imm) + +/* XTheadSync */ +OP(th_sfence_vmas, "th.sfence.vmas", rv_codec_r, rv_fmt_rs1_rs2) +OP(th_sync, "th.sync", rv_codec_none, rv_fmt_none) +OP(th_sync_i, "th.sync.i", rv_codec_none, rv_fmt_none) +OP(th_sync_is, "th.sync.is", rv_codec_none, rv_fmt_none) +OP(th_sync_s, "th.sync.s", rv_codec_none, rv_fmt_none) diff --git a/disas/riscv-xthead.c b/disas/riscv-xthead.c index fbc96631fd..387c22c869 100644 --- a/disas/riscv-xthead.c +++ b/disas/riscv-xthead.c @@ -8,248 +8,13 @@ #include "disas/riscv.h" #include "disas/riscv-xthead.h" -typedef enum { - /* 0 is reserved for rv_op_illegal. */ - /* XTheadBa */ - rv_op_th_addsl = 1, - /* XTheadBb */ - rv_op_th_srri, - rv_op_th_srriw, - rv_op_th_ext, - rv_op_th_extu, - rv_op_th_ff0, - rv_op_th_ff1, - rv_op_th_rev, - rv_op_th_revw, - rv_op_th_tstnbz, - /* XTheadBs */ - rv_op_th_tst, - /* XTheadCmo */ - rv_op_th_dcache_call, - rv_op_th_dcache_ciall, - rv_op_th_dcache_iall, - rv_op_th_dcache_cpa, - rv_op_th_dcache_cipa, - rv_op_th_dcache_ipa, - rv_op_th_dcache_cva, - rv_op_th_dcache_civa, - rv_op_th_dcache_iva, - rv_op_th_dcache_csw, - rv_op_th_dcache_cisw, - rv_op_th_dcache_isw, - rv_op_th_dcache_cpal1, - rv_op_th_dcache_cval1, - rv_op_th_icache_iall, - rv_op_th_icache_ialls, - rv_op_th_icache_ipa, - rv_op_th_icache_iva, - rv_op_th_l2cache_call, - rv_op_th_l2cache_ciall, - rv_op_th_l2cache_iall, - /* XTheadCondMov */ - rv_op_th_mveqz, - rv_op_th_mvnez, - /* XTheadFMemIdx */ - rv_op_th_flrd, - rv_op_th_flrw, - rv_op_th_flurd, - rv_op_th_flurw, - rv_op_th_fsrd, - rv_op_th_fsrw, - rv_op_th_fsurd, - rv_op_th_fsurw, - /* XTheadFmv */ - rv_op_th_fmv_hw_x, - rv_op_th_fmv_x_hw, - /* XTheadMac */ - rv_op_th_mula, - rv_op_th_mulah, - rv_op_th_mulaw, - rv_op_th_muls, - rv_op_th_mulsw, - rv_op_th_mulsh, - /* XTheadMemIdx */ - rv_op_th_lbia, - rv_op_th_lbib, - rv_op_th_lbuia, - rv_op_th_lbuib, - rv_op_th_lhia, - rv_op_th_lhib, - rv_op_th_lhuia, - rv_op_th_lhuib, - rv_op_th_lwia, - rv_op_th_lwib, - rv_op_th_lwuia, - rv_op_th_lwuib, - rv_op_th_ldia, - rv_op_th_ldib, - rv_op_th_sbia, - rv_op_th_sbib, - rv_op_th_shia, - rv_op_th_shib, - rv_op_th_swia, - rv_op_th_swib, - rv_op_th_sdia, - rv_op_th_sdib, - rv_op_th_lrb, - rv_op_th_lrbu, - rv_op_th_lrh, - rv_op_th_lrhu, - rv_op_th_lrw, - rv_op_th_lrwu, - rv_op_th_lrd, - rv_op_th_srb, - rv_op_th_srh, - rv_op_th_srw, - rv_op_th_srd, - rv_op_th_lurb, - rv_op_th_lurbu, - rv_op_th_lurh, - rv_op_th_lurhu, - rv_op_th_lurw, - rv_op_th_lurwu, - rv_op_th_lurd, - rv_op_th_surb, - rv_op_th_surh, - rv_op_th_surw, - rv_op_th_surd, - /* XTheadMemPair */ - rv_op_th_ldd, - rv_op_th_lwd, - rv_op_th_lwud, - rv_op_th_sdd, - rv_op_th_swd, - /* XTheadSync */ - rv_op_th_sfence_vmas, - rv_op_th_sync, - rv_op_th_sync_i, - rv_op_th_sync_is, - rv_op_th_sync_s, -} rv_xthead_op; - -static const rv_opcode_data xthead_opcode_data[] = { - { "th.illegal", rv_codec_illegal, rv_fmt_none }, - /* XTheadBa */ - { "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - /* XTheadBb */ - { "th.srri", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm }, - { "th.srriw", rv_codec_r2_imm5, rv_fmt_rd_rs1_imm }, - { "th.ext", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml }, - { "th.extu", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml }, - { "th.ff0", rv_codec_r2, rv_fmt_rd_rs1 }, - { "th.ff1", rv_codec_r2, rv_fmt_rd_rs1 }, - { "th.rev", rv_codec_r2, rv_fmt_rd_rs1 }, - { "th.revw", rv_codec_r2, rv_fmt_rd_rs1 }, - { "th.tstnbz", rv_codec_r2, rv_fmt_rd_rs1 }, - /* XTheadBs */ - { "th.tst", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm }, - /* XTheadCmo */ - { "th.dcache.call", rv_codec_none, rv_fmt_none }, - { "th.dcache.ciall", rv_codec_none, rv_fmt_none }, - { "th.dcache.iall", rv_codec_none, rv_fmt_none }, - { "th.dcache.cpa", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.cipa", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.ipa", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.cva", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.civa", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.iva", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.csw", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.cisw", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.isw", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.cpal1", rv_codec_r, rv_fmt_rs1 }, - { "th.dcache.cval1", rv_codec_r, rv_fmt_rs1 }, - { "th.icache.iall", rv_codec_none, rv_fmt_none }, - { "th.icache.ialls", rv_codec_none, rv_fmt_none }, - { "th.icache.ipa", rv_codec_r, rv_fmt_rs1 }, - { "th.icache.iva", rv_codec_r, rv_fmt_rs1 }, - { "th.l2cache.call", rv_codec_none, rv_fmt_none }, - { "th.l2cache.ciall", rv_codec_none, rv_fmt_none }, - { "th.l2cache.iall", rv_codec_none, rv_fmt_none }, - /* XTheadCondMov */ - { "th.mveqz", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.mvnez", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - /* XTheadFMemIdx */ - { "th.flrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.flrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.flurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.flurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.fsrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.fsrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.fsurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - { "th.fsurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm }, - /* XTheadFmv */ - { "th.fmv.hw.x", rv_codec_r, rv_fmt_rd_frs1 }, - { "th.fmv.x.hw", rv_codec_r, rv_fmt_rd_frs1 }, - /* XTheadMac */ - { "th.mula", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.mulaw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.mulah", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.muls", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.mulsw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - /* XTheadMemIdx */ - { "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lhib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lhuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lhuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lwia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lwib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lwuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lwuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.ldia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.ldib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.sbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.sbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.shia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.shib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.swia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.swib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.sdia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.sdib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr }, - { "th.lrb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lrd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.srb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.srh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.srw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.srd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.lurd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.surb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.surh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.surw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - { "th.surd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm }, - /* XTheadMemPair */ - { "th.ldd", rv_codec_r_imm2, rv_fmt_rd2_imm }, - { "th.lwd", rv_codec_r_imm2, rv_fmt_rd2_imm }, - { "th.lwud", rv_codec_r_imm2, rv_fmt_rd2_imm }, - { "th.sdd", rv_codec_r_imm2, rv_fmt_rd2_imm }, - { "th.swd", rv_codec_r_imm2, rv_fmt_rd2_imm }, - /* XTheadSync */ - { "th.sfence.vmas", rv_codec_r, rv_fmt_rs1_rs2 }, - { "th.sync", rv_codec_none, rv_fmt_none }, - { "th.sync.i", rv_codec_none, rv_fmt_none }, - { "th.sync.is", rv_codec_none, rv_fmt_none }, - { "th.sync.s", rv_codec_none, rv_fmt_none }, -}; +#define OP(N, ...) static const rv_opcode_data op_##N = { __VA_ARGS__ }; +#include "riscv-xthead-op.c.inc" +#undef OP const rv_opcode_data *decode_xtheadba(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -262,7 +27,7 @@ const rv_opcode_data *decode_xtheadba(rv_decode *dec, rv_isa isa) case 0b0000000: case 0b0000001: case 0b0000010: - case 0b0000011: op = rv_op_th_addsl; break; + case 0b0000011: return &op_th_addsl; } break; } @@ -272,13 +37,12 @@ const rv_opcode_data *decode_xtheadba(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadbb(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -288,41 +52,41 @@ const rv_opcode_data *decode_xtheadbb(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 1: switch ((inst >> 25) & 0b1111111) { - case 0b0001010: op = rv_op_th_srriw; break; + case 0b0001010: return &op_th_srriw; case 0b1000000: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_tstnbz; + return &op_th_tstnbz; } break; case 0b1000001: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_rev; + return &op_th_rev; } break; case 0b1000010: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_ff0; + return &op_th_ff0; } break; case 0b1000011: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_ff1; + return &op_th_ff1; } break; case 0b1000100: case 0b1001000: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_revw; + return &op_th_revw; } break; case 0b0001000: case 0b0001001: - op = rv_op_th_srri; + return &op_th_srri; break; } break; - case 2: op = rv_op_th_ext; break; - case 3: op = rv_op_th_extu; break; + case 2: return &op_th_ext; + case 3: return &op_th_extu; } break; /* custom-0 */ @@ -330,13 +94,12 @@ const rv_opcode_data *decode_xtheadbb(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadbs(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -346,7 +109,7 @@ const rv_opcode_data *decode_xtheadbs(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 1: switch ((inst >> 26) & 0b111111) { - case 0b100010: op = rv_op_th_tst; break; + case 0b100010: return &op_th_tst; } break; } @@ -356,13 +119,12 @@ const rv_opcode_data *decode_xtheadbs(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadcmo(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -374,55 +136,55 @@ const rv_opcode_data *decode_xtheadcmo(rv_decode *dec, rv_isa isa) switch ((inst >> 20 & 0b111111111111)) { case 0b000000000001: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_dcache_call; + return &op_th_dcache_call; } break; case 0b000000000011: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_dcache_ciall; + return &op_th_dcache_ciall; } break; case 0b000000000010: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_dcache_iall; + return &op_th_dcache_iall; } break; - case 0b000000101001: op = rv_op_th_dcache_cpa; break; - case 0b000000101011: op = rv_op_th_dcache_cipa; break; - case 0b000000101010: op = rv_op_th_dcache_ipa; break; - case 0b000000100101: op = rv_op_th_dcache_cva; break; - case 0b000000100111: op = rv_op_th_dcache_civa; break; - case 0b000000100110: op = rv_op_th_dcache_iva; break; - case 0b000000100001: op = rv_op_th_dcache_csw; break; - case 0b000000100011: op = rv_op_th_dcache_cisw; break; - case 0b000000100010: op = rv_op_th_dcache_isw; break; - case 0b000000101000: op = rv_op_th_dcache_cpal1; break; - case 0b000000100100: op = rv_op_th_dcache_cval1; break; + case 0b000000101001: return &op_th_dcache_cpa; + case 0b000000101011: return &op_th_dcache_cipa; + case 0b000000101010: return &op_th_dcache_ipa; + case 0b000000100101: return &op_th_dcache_cva; + case 0b000000100111: return &op_th_dcache_civa; + case 0b000000100110: return &op_th_dcache_iva; + case 0b000000100001: return &op_th_dcache_csw; + case 0b000000100011: return &op_th_dcache_cisw; + case 0b000000100010: return &op_th_dcache_isw; + case 0b000000101000: return &op_th_dcache_cpal1; + case 0b000000100100: return &op_th_dcache_cval1; case 0b000000010000: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_icache_iall; + return &op_th_icache_iall; } break; case 0b000000010001: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_icache_ialls; + return &op_th_icache_ialls; } break; - case 0b000000111000: op = rv_op_th_icache_ipa; break; - case 0b000000110000: op = rv_op_th_icache_iva; break; + case 0b000000111000: return &op_th_icache_ipa; + case 0b000000110000: return &op_th_icache_iva; case 0b000000010101: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_l2cache_call; + return &op_th_l2cache_call; } break; case 0b000000010111: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_l2cache_ciall; + return &op_th_l2cache_ciall; } break; case 0b000000010110: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_l2cache_iall; + return &op_th_l2cache_iall; } break; } @@ -434,13 +196,12 @@ const rv_opcode_data *decode_xtheadcmo(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadcondmov(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -450,8 +211,8 @@ const rv_opcode_data *decode_xtheadcondmov(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 1: switch ((inst >> 25) & 0b1111111) { - case 0b0100000: op = rv_op_th_mveqz; break; - case 0b0100001: op = rv_op_th_mvnez; break; + case 0b0100000: return &op_th_mveqz; + case 0b0100001: return &op_th_mvnez; } break; } @@ -461,13 +222,12 @@ const rv_opcode_data *decode_xtheadcondmov(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -477,18 +237,18 @@ const rv_opcode_data *decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 6: switch ((inst >> 27) & 0b11111) { - case 8: op = rv_op_th_flrw; break; - case 10: op = rv_op_th_flurw; break; - case 12: op = rv_op_th_flrd; break; - case 14: op = rv_op_th_flurd; break; + case 8: return &op_th_flrw; + case 10: return &op_th_flurw; + case 12: return &op_th_flrd; + case 14: return &op_th_flurd; } break; case 7: switch ((inst >> 27) & 0b11111) { - case 8: op = rv_op_th_fsrw; break; - case 10: op = rv_op_th_fsurw; break; - case 12: op = rv_op_th_fsrd; break; - case 14: op = rv_op_th_fsurd; break; + case 8: return &op_th_fsrw; + case 10: return &op_th_fsurw; + case 12: return &op_th_fsrd; + case 14: return &op_th_fsurd; } break; } @@ -498,13 +258,12 @@ const rv_opcode_data *decode_xtheadfmemidx(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadfmv(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -516,12 +275,12 @@ const rv_opcode_data *decode_xtheadfmv(rv_decode *dec, rv_isa isa) switch ((inst >> 25) & 0b1111111) { case 0b1010000: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_fmv_hw_x; + return &op_th_fmv_hw_x; } break; case 0b1100000: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_th_fmv_x_hw; + return &op_th_fmv_x_hw; } break; } @@ -533,13 +292,12 @@ const rv_opcode_data *decode_xtheadfmv(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadmac(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -549,12 +307,12 @@ const rv_opcode_data *decode_xtheadmac(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 1: switch ((inst >> 25) & 0b1111111) { - case 0b0010000: op = rv_op_th_mula; break; - case 0b0010001: op = rv_op_th_muls; break; - case 0b0010010: op = rv_op_th_mulaw; break; - case 0b0010011: op = rv_op_th_mulsw; break; - case 0b0010100: op = rv_op_th_mulah; break; - case 0b0010101: op = rv_op_th_mulsh; break; + case 0b0010000: return &op_th_mula; + case 0b0010001: return &op_th_muls; + case 0b0010010: return &op_th_mulaw; + case 0b0010011: return &op_th_mulsw; + case 0b0010100: return &op_th_mulah; + case 0b0010101: return &op_th_mulsh; } break; } @@ -564,13 +322,12 @@ const rv_opcode_data *decode_xtheadmac(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadmemidx(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -580,54 +337,54 @@ const rv_opcode_data *decode_xtheadmemidx(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 4: switch ((inst >> 27) & 0b11111) { - case 0: op = rv_op_th_lrb; break; - case 1: op = rv_op_th_lbib; break; - case 2: op = rv_op_th_lurb; break; - case 3: op = rv_op_th_lbia; break; - case 4: op = rv_op_th_lrh; break; - case 5: op = rv_op_th_lhib; break; - case 6: op = rv_op_th_lurh; break; - case 7: op = rv_op_th_lhia; break; - case 8: op = rv_op_th_lrw; break; - case 9: op = rv_op_th_lwib; break; - case 10: op = rv_op_th_lurw; break; - case 11: op = rv_op_th_lwia; break; - case 12: op = rv_op_th_lrd; break; - case 13: op = rv_op_th_ldib; break; - case 14: op = rv_op_th_lurd; break; - case 15: op = rv_op_th_ldia; break; - case 16: op = rv_op_th_lrbu; break; - case 17: op = rv_op_th_lbuib; break; - case 18: op = rv_op_th_lurbu; break; - case 19: op = rv_op_th_lbuia; break; - case 20: op = rv_op_th_lrhu; break; - case 21: op = rv_op_th_lhuib; break; - case 22: op = rv_op_th_lurhu; break; - case 23: op = rv_op_th_lhuia; break; - case 24: op = rv_op_th_lrwu; break; - case 25: op = rv_op_th_lwuib; break; - case 26: op = rv_op_th_lurwu; break; - case 27: op = rv_op_th_lwuia; break; + case 0: return &op_th_lrb; + case 1: return &op_th_lbib; + case 2: return &op_th_lurb; + case 3: return &op_th_lbia; + case 4: return &op_th_lrh; + case 5: return &op_th_lhib; + case 6: return &op_th_lurh; + case 7: return &op_th_lhia; + case 8: return &op_th_lrw; + case 9: return &op_th_lwib; + case 10: return &op_th_lurw; + case 11: return &op_th_lwia; + case 12: return &op_th_lrd; + case 13: return &op_th_ldib; + case 14: return &op_th_lurd; + case 15: return &op_th_ldia; + case 16: return &op_th_lrbu; + case 17: return &op_th_lbuib; + case 18: return &op_th_lurbu; + case 19: return &op_th_lbuia; + case 20: return &op_th_lrhu; + case 21: return &op_th_lhuib; + case 22: return &op_th_lurhu; + case 23: return &op_th_lhuia; + case 24: return &op_th_lrwu; + case 25: return &op_th_lwuib; + case 26: return &op_th_lurwu; + case 27: return &op_th_lwuia; } break; case 5: switch ((inst >> 27) & 0b11111) { - case 0: op = rv_op_th_srb; break; - case 1: op = rv_op_th_sbib; break; - case 2: op = rv_op_th_surb; break; - case 3: op = rv_op_th_sbia; break; - case 4: op = rv_op_th_srh; break; - case 5: op = rv_op_th_shib; break; - case 6: op = rv_op_th_surh; break; - case 7: op = rv_op_th_shia; break; - case 8: op = rv_op_th_srw; break; - case 9: op = rv_op_th_swib; break; - case 10: op = rv_op_th_surw; break; - case 11: op = rv_op_th_swia; break; - case 12: op = rv_op_th_srd; break; - case 13: op = rv_op_th_sdib; break; - case 14: op = rv_op_th_surd; break; - case 15: op = rv_op_th_sdia; break; + case 0: return &op_th_srb; + case 1: return &op_th_sbib; + case 2: return &op_th_surb; + case 3: return &op_th_sbia; + case 4: return &op_th_srh; + case 5: return &op_th_shib; + case 6: return &op_th_surh; + case 7: return &op_th_shia; + case 8: return &op_th_srw; + case 9: return &op_th_swib; + case 10: return &op_th_surw; + case 11: return &op_th_swia; + case 12: return &op_th_srd; + case 13: return &op_th_sdib; + case 14: return &op_th_surd; + case 15: return &op_th_sdia; } break; break; @@ -638,13 +395,12 @@ const rv_opcode_data *decode_xtheadmemidx(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadmempair(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -654,15 +410,15 @@ const rv_opcode_data *decode_xtheadmempair(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 4: switch ((inst >> 27) & 0b11111) { - case 28: op = rv_op_th_lwd; break; - case 30: op = rv_op_th_lwud; break; - case 31: op = rv_op_th_ldd; break; + case 28: return &op_th_lwd; + case 30: return &op_th_lwud; + case 31: return &op_th_ldd; } break; case 5: switch ((inst >> 27) & 0b11111) { - case 28: op = rv_op_th_swd; break; - case 31: op = rv_op_th_sdd; break; + case 28: return &op_th_swd; + case 31: return &op_th_sdd; } break; } @@ -672,13 +428,12 @@ const rv_opcode_data *decode_xtheadmempair(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } const rv_opcode_data *decode_xtheadsync(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch (((inst >> 0) & 0b11)) { case 3: @@ -688,13 +443,13 @@ const rv_opcode_data *decode_xtheadsync(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 0: switch ((inst >> 25) & 0b1111111) { - case 0b0000010: op = rv_op_th_sfence_vmas; break; + case 0b0000010: return &op_th_sfence_vmas; case 0b0000000: switch ((inst >> 20) & 0b11111) { - case 0b11000: op = rv_op_th_sync; break; - case 0b11010: op = rv_op_th_sync_i; break; - case 0b11011: op = rv_op_th_sync_is; break; - case 0b11001: op = rv_op_th_sync_s; break; + case 0b11000: return &op_th_sync; + case 0b11010: return &op_th_sync_i; + case 0b11011: return &op_th_sync_is; + case 0b11001: return &op_th_sync_s; } break; } @@ -706,5 +461,5 @@ const rv_opcode_data *decode_xtheadsync(rv_decode *dec, rv_isa isa) break; } - return op == rv_op_illegal ? NULL : &xthead_opcode_data[op]; + return NULL; } From 30bb96e570274aaa7aec6e4174ff686eee623692 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:34 -0700 Subject: [PATCH 559/627] disas/riscv: Move rv_op_illegal to riscv.c illegal is no longer used in other files. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-45-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 2 +- disas/riscv.h | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 787340e811..c3a8cde37d 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -29,7 +29,7 @@ #include "disas/riscv-xlrbr.h" typedef enum { - /* 0 is reserved for rv_op_illegal. */ + rv_op_illegal = 0, rv_op_lui = 1, rv_op_auipc = 2, rv_op_jal = 3, diff --git a/disas/riscv.h b/disas/riscv.h index 241dd47d7f..5ac8c41616 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -200,10 +200,6 @@ typedef struct { uint8_t rlist; } rv_decode; -enum { - rv_op_illegal = 0 -}; - /* instruction formats */ #define rv_fmt_none "O\t" From a722ea32faf045f93a4dbc79f0e8f0bc0ef4b043 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:35 -0700 Subject: [PATCH 560/627] disas/riscv: Split out riscv-op.c.inc Move rvi_opcode_data to riscv-op.c.inc and massage the lines into OP() form. Unlike other files, keep the enumeration and the table intact for now, but build them both from the same source. Adjust the names of rv_*mop to include _op_ to match the general pattern. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-46-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 958 +++++++++++++++++++++ disas/riscv.c | 1931 +----------------------------------------- 2 files changed, 967 insertions(+), 1922 deletions(-) create mode 100644 disas/riscv-op.c.inc diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc new file mode 100644 index 0000000000..3fe934688e --- /dev/null +++ b/disas/riscv-op.c.inc @@ -0,0 +1,958 @@ +OP(illegal, "illegal", rv_codec_none, rv_fmt_none) +OP(lui, "lui", rv_codec_u, rv_fmt_rd_uimm) +OP(auipc, "auipc", rv_codec_u, rv_fmt_rd_uoffset) +OP(jal, "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal) +OP(jalr, "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr) +OP(beq, "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq) +OP(bne, "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne) +OP(blt, "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt) +OP(bge, "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge) +OP(bltu, "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset) +OP(bgeu, "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset) +OP(lb, "lb", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lh, "lh", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lw, "lw", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lbu, "lbu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lhu, "lhu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(sb, "sb", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(sh, "sh", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(sw, "sw", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(addi, "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi) +OP(slti, "slti", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(sltiu, "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu) +OP(xori, "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori) +OP(ori, "ori", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(andi, "andi", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(slli, "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(srli, "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(srai, "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(add, "add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sub, "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub) +OP(sll, "sll", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(slt, "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt) +OP(sltu, "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu) +OP(xor, "xor", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srl, "srl", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sra, "sra", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(or, "or", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(and, "and", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(fence, "fence", rv_codec_r_f, rv_fmt_pred_succ) +OP(fence_i, "fence.i", rv_codec_none, rv_fmt_none) +OP(lwu, "lwu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(ld, "ld", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(sd, "sd", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(addiw, "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw) +OP(slliw, "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(srliw, "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(sraiw, "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(addw, "addw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(subw, "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw) +OP(sllw, "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srlw, "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sraw, "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ldu, "ldu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lq, "lq", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(sq, "sq", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(addid, "addid", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(sllid, "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(srlid, "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(sraid, "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(addd, "addd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(subd, "subd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(slld, "slld", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srld, "srld", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srad, "srad", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mul, "mul", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mulh, "mulh", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mulhsu, "mulhsu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mulhu, "mulhu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(div, "div", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divu, "divu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rem, "rem", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remu, "remu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mulw, "mulw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divw, "divw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divuw, "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remw, "remw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remuw, "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(muld, "muld", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divd, "divd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divud, "divud", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remd, "remd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remud, "remud", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(lr_w, "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(sc_w, "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_w, "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_w, "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_w, "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_w, "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_w, "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_w, "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_w, "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_w, "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_w, "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(lr_d, "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(sc_d, "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_d, "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_d, "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_d, "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_d, "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_d, "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_d, "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_d, "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_d, "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_d, "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(lr_q, "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(sc_q, "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_q, "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_q, "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_q, "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_q, "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_q, "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_q, "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_q, "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_q, "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_q, "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(ecall, "ecall", rv_codec_none, rv_fmt_none) +OP(ebreak, "ebreak", rv_codec_none, rv_fmt_none) +OP(uret, "uret", rv_codec_none, rv_fmt_none) +OP(sret, "sret", rv_codec_none, rv_fmt_none) +OP(hret, "hret", rv_codec_none, rv_fmt_none) +OP(mret, "mret", rv_codec_none, rv_fmt_none) +OP(dret, "dret", rv_codec_none, rv_fmt_none) +OP(sfence_vm, "sfence.vm", rv_codec_r, rv_fmt_rs1) +OP(sfence_vma, "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2) +OP(wfi, "wfi", rv_codec_none, rv_fmt_none) +OP(csrrw, "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrs, "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrc, "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrwi, "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(csrrsi, "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(csrrci, "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(flw, "flw", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fsw, "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fmadd_s, "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmsub_s, "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_s, "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmadd_s, "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fadd_s, "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsub_s, "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmul_s, "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fdiv_s, "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsgnj_s, "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s) +OP(fsgnjn_s, "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s) +OP(fsgnjx_s, "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s) +OP(fmin_s, "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmax_s, "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fsqrt_s, "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fle_s, "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flt_s, "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(feq_s, "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fcvt_w_s, "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_s, "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_s_w, "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_wu, "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fmv_x_s, "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1) +OP(fclass_s, "fclass.s", rv_codec_r, rv_fmt_rd_frs1) +OP(fmv_s_x, "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fcvt_l_s, "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_s, "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_s_l, "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_lu, "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fld, "fld", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fsd, "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fmadd_d, "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmsub_d, "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_d, "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmadd_d, "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fadd_d, "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsub_d, "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmul_d, "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fdiv_d, "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsgnj_d, "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d) +OP(fsgnjn_d, "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d) +OP(fsgnjx_d, "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d) +OP(fmin_d, "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmax_d, "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fcvt_s_d, "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_d_s, "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fsqrt_d, "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fle_d, "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flt_d, "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(feq_d, "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fcvt_w_d, "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_d, "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_d_w, "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_d_wu, "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fclass_d, "fclass.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fcvt_l_d, "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_d, "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fmv_x_d, "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fcvt_d_l, "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_d_lu, "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fmv_d_x, "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1) +OP(flq, "flq", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fsq, "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fmadd_q, "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmsub_q, "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_q, "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmadd_q, "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fadd_q, "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsub_q, "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmul_q, "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fdiv_q, "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsgnj_q, "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q) +OP(fsgnjn_q, "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q) +OP(fsgnjx_q, "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q) +OP(fmin_q, "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmax_q, "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fcvt_s_q, "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_q_s, "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_d_q, "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_q_d, "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fsqrt_q, "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fle_q, "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flt_q, "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(feq_q, "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fcvt_w_q, "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_q, "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_q_w, "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_q_wu, "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fclass_q, "fclass.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fcvt_l_q, "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_q, "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_q_l, "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_q_lu, "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fmv_x_q, "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fmv_q_x, "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1) +OP(c_addi4spn, "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(rv_op_addi)) +OP(c_fld, "c.fld", rv_codec_cl_ld, NULL, DECOMP(rv_op_fld)) +OP(c_lw, "c.lw", rv_codec_cl_lw, NULL, DECOMP(rv_op_lw)) +OP(c_flw, "c.flw", rv_codec_cl_lw, NULL, DECOMP(rv_op_flw)) +OP(c_fsd, "c.fsd", rv_codec_cs_sd, NULL, DECOMP(rv_op_fsd)) +OP(c_sw, "c.sw", rv_codec_cs_sw, NULL, DECOMP(rv_op_sw)) +OP(c_fsw, "c.fsw", rv_codec_cs_sw, NULL, DECOMP(rv_op_fsw)) +OP(c_addi, "c.addi", rv_codec_ci, NULL, DECOMP(rv_op_addi)) +OP(c_jal, "c.jal", rv_codec_cj_jal, NULL, DECOMP(rv_op_jal)) +OP(c_li, "c.li", rv_codec_ci_li, NULL, DECOMP(rv_op_addi)) +OP(c_addi16sp, "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(rv_op_addi)) +OP(c_lui, "c.lui", rv_codec_ci_lui, NULL, DECOMP(rv_op_lui)) +OP(c_srli, "c.srli", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srli)) +OP(c_srai, "c.srai", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srai)) +OP(c_andi, "c.andi", rv_codec_cb_imm, NULL, DECOMP(rv_op_andi)) +OP(c_sub, "c.sub", rv_codec_cs, NULL, DECOMP(rv_op_sub)) +OP(c_xor, "c.xor", rv_codec_cs, NULL, DECOMP(rv_op_xor)) +OP(c_or, "c.or", rv_codec_cs, NULL, DECOMP(rv_op_or)) +OP(c_and, "c.and", rv_codec_cs, NULL, DECOMP(rv_op_and)) +OP(c_subw, "c.subw", rv_codec_cs, NULL, DECOMP(rv_op_subw)) +OP(c_addw, "c.addw", rv_codec_cs, NULL, DECOMP(rv_op_addw)) +OP(c_j, "c.j", rv_codec_cj, NULL, DECOMP(rv_op_j)) +OP(c_beqz, "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beqz)) +OP(c_bnez, "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bnez)) +OP(c_slli, "c.slli", rv_codec_ci_sh6, NULL, DECOMP(rv_op_slli)) +OP(c_fldsp, "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_fld)) +OP(c_lwsp, "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_lw)) +OP(c_flwsp, "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_flw)) +OP(c_jr, "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jr)) +OP(c_mv, "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_mv)) +OP(c_ebreak, "c.ebreak", rv_codec_ci_none, NULL, DECOMP(rv_op_ebreak)) +OP(c_jalr, "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(rv_op_jalr)) +OP(c_add, "c.add", rv_codec_cr, NULL, DECOMP(rv_op_add)) +OP(c_fsdsp, "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_fsd)) +OP(c_swsp, "c.swsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_sw)) +OP(c_fswsp, "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_fsw)) +OP(c_ld, "c.ld", rv_codec_cl_ld, NULL, DECOMP(rv_op_ld)) +OP(c_sd, "c.sd", rv_codec_cs_sd, NULL, DECOMP(rv_op_sd)) +OP(c_addiw, "c.addiw", rv_codec_ci, NULL, DECOMP(rv_op_addiw)) +OP(c_ldsp, "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_ld)) +OP(c_sdsp, "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_sd)) +OP(c_lq, "c.lq", rv_codec_cl_lq, NULL, DECOMP(rv_op_lq)) +OP(c_sq, "c.sq", rv_codec_cs_sq, NULL, DECOMP(rv_op_sq)) +OP(c_lqsp, "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq)) +OP(c_sqsp, "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq)) +OP(nop, "nop", rv_codec_illegal, rv_fmt_none) +OP(mv, "mv", rv_codec_illegal, rv_fmt_rd_rs1, rvcp_mv) +OP(not, "not", rv_codec_illegal, rv_fmt_rd_rs1) +OP(neg, "neg", rv_codec_illegal, rv_fmt_rd_rs2) +OP(negw, "negw", rv_codec_illegal, rv_fmt_rd_rs2) +OP(sext_w, "sext.w", rv_codec_illegal, rv_fmt_rd_rs1) +OP(seqz, "seqz", rv_codec_illegal, rv_fmt_rd_rs1) +OP(snez, "snez", rv_codec_illegal, rv_fmt_rd_rs2) +OP(sltz, "sltz", rv_codec_illegal, rv_fmt_rd_rs1) +OP(sgtz, "sgtz", rv_codec_illegal, rv_fmt_rd_rs2) +OP(fmv_s, "fmv.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fabs_s, "fabs.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fneg_s, "fneg.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fmv_d, "fmv.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fabs_d, "fabs.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fneg_d, "fneg.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fmv_q, "fmv.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fabs_q, "fabs.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fneg_q, "fneg.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(beqz, "beqz", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bnez, "bnez", rv_codec_illegal, rv_fmt_rs1_offset) +OP(blez, "blez", rv_codec_illegal, rv_fmt_rs2_offset) +OP(bgez, "bgez", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bltz, "bltz", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bgtz, "bgtz", rv_codec_illegal, rv_fmt_rs2_offset) +OP(jal_ra, "jal", rv_codec_illegal, rv_fmt_offset) +OP(jalr_ra, "jalr", rv_codec_illegal, rv_fmt_rs1) +OP(j, "j", rv_codec_illegal, rv_fmt_offset) +OP(ret, "ret", rv_codec_illegal, rv_fmt_none) +OP(jr, "jr", rv_codec_illegal, rv_fmt_rs1, rvcp_jr) +OP(rdcycle, "rdcycle", rv_codec_i_csr, rv_fmt_rd) +OP(rdtime, "rdtime", rv_codec_i_csr, rv_fmt_rd) +OP(rdinstret, "rdinstret", rv_codec_i_csr, rv_fmt_rd) +OP(rdcycleh, "rdcycleh", rv_codec_i_csr, rv_fmt_rd) +OP(rdtimeh, "rdtimeh", rv_codec_i_csr, rv_fmt_rd) +OP(rdinstreth, "rdinstreth", rv_codec_i_csr, rv_fmt_rd) +OP(frcsr, "frcsr", rv_codec_i_csr, rv_fmt_rd) +OP(frrm, "frrm", rv_codec_i_csr, rv_fmt_rd) +OP(frflags, "frflags", rv_codec_i_csr, rv_fmt_rd) +OP(fscsr, "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsrm, "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsflags, "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsrmi, "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm) +OP(fsflagsi, "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm) +OP(bseti, "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(bclri, "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(binvi, "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(bexti, "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(rori, "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(clz, "clz", rv_codec_r, rv_fmt_rd_rs1) +OP(ctz, "ctz", rv_codec_r, rv_fmt_rd_rs1) +OP(cpop, "cpop", rv_codec_r, rv_fmt_rd_rs1) +OP(sext_h, "sext.h", rv_codec_r, rv_fmt_rd_rs1) +OP(sext_b, "sext.b", rv_codec_r, rv_fmt_rd_rs1) +OP(xnor, "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(orn, "orn", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(andn, "andn", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rol, "rol", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ror, "ror", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh1add, "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh2add, "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh3add, "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh1add_uw, "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh2add_uw, "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh3add_uw, "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clmul, "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clmulr, "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clmulh, "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(min, "min", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(minu, "minu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(max, "max", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(maxu, "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clzw, "clzw", rv_codec_r, rv_fmt_rd_rs1) +OP(ctzw, "ctzw", rv_codec_r, rv_fmt_rd_rs1) +OP(cpopw, "cpopw", rv_codec_r, rv_fmt_rd_rs1) +OP(slli_uw, "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(add_uw, "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rolw, "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rorw, "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rev8, "rev8", rv_codec_r, rv_fmt_rd_rs1) +OP(zext_h, "zext.h", rv_codec_r, rv_fmt_rd_rs1) +OP(roriw, "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(orc_b, "orc.b", rv_codec_r, rv_fmt_rd_rs1) +OP(bset, "bset", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(bclr, "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(binv, "binv", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(bext, "bext", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes32esmi, "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32esi, "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32dsmi, "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32dsi, "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes64ks1i, "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum) +OP(aes64ks2, "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64im, "aes64im", rv_codec_r, rv_fmt_rd_rs1) +OP(aes64esm, "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64es, "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64dsm, "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64ds, "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha256sig0, "sha256sig0", rv_codec_r, rv_fmt_rd_rs1) +OP(sha256sig1, "sha256sig1", rv_codec_r, rv_fmt_rd_rs1) +OP(sha256sum0, "sha256sum0", rv_codec_r, rv_fmt_rd_rs1) +OP(sha256sum1, "sha256sum1", rv_codec_r, rv_fmt_rd_rs1) +OP(sha512sig0, "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig1, "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum0, "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum1, "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum0r, "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum1r, "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig0l, "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig0h, "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig1l, "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig1h, "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sm3p0, "sm3p0", rv_codec_r, rv_fmt_rd_rs1) +OP(sm3p1, "sm3p1", rv_codec_r, rv_fmt_rd_rs1) +OP(sm4ed, "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(sm4ks, "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(brev8, "brev8", rv_codec_r, rv_fmt_rd_rs1) +OP(pack, "pack", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(packh, "packh", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(packw, "packw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(unzip, "unzip", rv_codec_r, rv_fmt_rd_rs1) +OP(zip, "zip", rv_codec_r, rv_fmt_rd_rs1) +OP(xperm4, "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(xperm8, "xperm8", rv_codec_r, rv_fmt_rd_rs1) +OP(vle8_v, "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle16_v, "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle32_v, "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle64_v, "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse8_v, "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse16_v, "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse32_v, "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse64_v, "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vlm_v, "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vsm_v, "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vlse8_v, "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse16_v, "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse32_v, "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse64_v, "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse8_v, "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse16_v, "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse32_v, "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse64_v, "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vluxei8_v, "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei16_v, "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei32_v, "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei64_v, "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei8_v, "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei16_v, "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei32_v, "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei64_v, "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei16_v, "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei8_v, "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei16_v, "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei32_v, "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei64_v, "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vle8ff_v, "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle16ff_v, "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle32ff_v, "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle64ff_v, "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re8_v, "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re16_v, "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re32_v, "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re64_v, "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re8_v, "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re16_v, "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re32_v, "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re64_v, "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re8_v, "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re16_v, "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re32_v, "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re64_v, "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re8_v, "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re16_v, "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re32_v, "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re64_v, "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs1r_v, "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs2r_v, "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs4r_v, "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs8r_v, "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vadd_vv, "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vadd_vx, "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vadd_vi, "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vsub_vv, "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsub_vx, "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrsub_vx, "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrsub_vi, "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vwaddu_vv, "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwaddu_vx, "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsubu_vv, "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsubu_vx, "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsub_vv, "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsub_vx, "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwaddu_wv, "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwaddu_wx, "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwadd_wx, "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsubu_wv, "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsubu_wx, "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsub_wv, "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsub_wx, "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vmadc_vvm, "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmadc_vxm, "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmadc_vim, "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vsbc_vvm, "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vsbc_vxm, "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmsbc_vvm, "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmsbc_vxm, "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vand_vv, "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vand_vx, "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vand_vi, "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vor_vv, "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vor_vx, "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vor_vi, "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vxor_vv, "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vxor_vx, "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vxor_vi, "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vsll_vv, "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsll_vx, "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsll_vi, "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vsrl_vv, "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsrl_vx, "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsrl_vi, "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vsra_vv, "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsra_vx, "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsra_vi, "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnsrl_wv, "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnsrl_wx, "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnsrl_wi, "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnsra_wv, "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnsra_wx, "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnsra_wi, "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vmseq_vv, "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmseq_vx, "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmseq_vi, "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsne_vv, "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsne_vx, "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsne_vi, "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsltu_vv, "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsltu_vx, "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmslt_vv, "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmslt_vx, "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsleu_vv, "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsleu_vx, "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsleu_vi, "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsle_vv, "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsle_vx, "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsle_vi, "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsgtu_vx, "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsgtu_vi, "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsgt_vx, "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsgt_vi, "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vminu_vv, "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vminu_vx, "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmin_vv, "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmin_vx, "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmaxu_vv, "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmaxu_vx, "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmax_vv, "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmax_vx, "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmul_vv, "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmul_vx, "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulh_vv, "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulh_vx, "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulhu_vv, "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulhu_vx, "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulhsu_vv, "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulhsu_vx, "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vdivu_vv, "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vdivu_vx, "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vdiv_vv, "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vdiv_vx, "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vremu_vv, "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vremu_vx, "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrem_vv, "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrem_vx, "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmulu_vv, "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmulu_vx, "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmulsu_vv, "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmulsu_vx, "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmul_vv, "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmul_vx, "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmacc_vv, "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vmacc_vx, "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vnmsac_vv, "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vnmsac_vx, "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vmadd_vv, "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vmadd_vx, "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vnmsub_vv, "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vnmsub_vx, "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccu_vv, "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmaccu_vx, "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmacc_vv, "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmacc_vx, "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccsu_vv, "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmaccsu_vx, "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccus_vx, "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vmv_v_v, "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1) +OP(vmv_v_x, "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1) +OP(vmv_v_i, "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm) +OP(vmerge_vvm, "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmerge_vxm, "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmerge_vim, "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vsaddu_vv, "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsaddu_vx, "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsaddu_vi, "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vsadd_vv, "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsadd_vx, "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsadd_vi, "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vssubu_vv, "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssubu_vx, "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssub_vv, "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssub_vx, "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vaadd_vv, "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vaadd_vx, "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vaaddu_vv, "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vaaddu_vx, "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vasub_vv, "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vasub_vx, "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vasubu_vv, "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vasubu_vx, "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsmul_vv, "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsmul_vx, "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssrl_vv, "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssrl_vx, "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssrl_vi, "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vssra_vv, "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssra_vx, "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssra_vi, "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnclipu_wv, "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnclipu_wx, "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnclipu_wi, "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnclip_wv, "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnclip_wx, "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnclip_wi, "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vfadd_vv, "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfadd_vf, "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsub_vv, "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsub_vf, "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfrsub_vf, "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwadd_vv, "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwadd_vf, "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwadd_wv, "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwadd_wf, "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwsub_vv, "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwsub_vf, "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwsub_wv, "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwsub_wf, "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmul_vv, "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmul_vf, "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfdiv_vv, "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfdiv_vf, "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfrdiv_vf, "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwmul_vv, "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwmul_vf, "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmacc_vv, "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmacc_vf, "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmacc_vv, "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmacc_vf, "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmsac_vv, "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmsac_vf, "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmsac_vv, "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmsac_vf, "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmadd_vv, "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmadd_vf, "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmadd_vv, "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmadd_vf, "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmsub_vv, "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmsub_vf, "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmsub_vv, "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmsub_vf, "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwmacc_vv, "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmacc_vf, "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwnmacc_vv, "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwnmacc_vf, "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwmsac_vv, "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmsac_vf, "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwnmsac_vv, "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwnmsac_vf, "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfsqrt_v, "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfrsqrt7_v, "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfrec7_v, "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfmin_vv, "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmin_vf, "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmax_vv, "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmax_vf, "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnj_vv, "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsgnj_vf, "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnjn_vv, "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsgnjn_vf, "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnjx_vv, "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsgnjx_vf, "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfslide1up_vf, "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfslide1down_vf, "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfeq_vv, "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmfeq_vf, "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfne_vv, "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmfne_vf, "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmflt_vv, "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmflt_vf, "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfle_vv, "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmfle_vf, "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfgt_vf, "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfge_vf, "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfclass_v, "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfmerge_vfm, "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl) +OP(vfmv_v_f, "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1) +OP(vfcvt_xu_f_v, "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_x_f_v, "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_f_xu_v, "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_f_x_v, "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_rtz_xu_f_v, "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_rtz_x_f_v, "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_xu_f_v, "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_x_f_v, "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_f_xu_v, "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_f_x_v, "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_f_f_v, "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_rtz_xu_f_v, "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_rtz_x_f_v, "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_xu_f_w, "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_x_f_w, "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_f_xu_w, "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_f_x_w, "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_f_f_w, "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rod_f_f_w, "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rtz_xu_f_w, "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rtz_x_f_w, "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vredsum_vs, "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredand_vs, "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredor_vs, "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredxor_vs, "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredminu_vs, "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmin_vs, "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmaxu_vs, "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmax_vs, "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwredsumu_vs, "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwredsum_vs, "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredusum_vs, "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredosum_vs, "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredmin_vs, "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredmax_vs, "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwredusum_vs, "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwredosum_vs, "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmand_mm, "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmnand_mm, "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmandn_mm, "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmxor_mm, "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmor_mm, "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmnor_mm, "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmorn_mm, "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmxnor_mm, "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vcpop_m, "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) +OP(vfirst_m, "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) +OP(vmsbf_m, "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vmsif_m, "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vmsof_m, "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(viota_m, "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vid_v, "vid.v", rv_codec_v_r, rv_fmt_vd_vm) +OP(vmv_x_s, "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2) +OP(vmv_s_x, "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1) +OP(vfmv_f_s, "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2) +OP(vfmv_s_f, "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1) +OP(vslideup_vx, "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslideup_vi, "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vslide1up_vx, "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslidedown_vx, "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslidedown_vi, "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vslide1down_vx, "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrgather_vv, "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrgatherei16_vv, "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrgather_vx, "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrgather_vi, "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vcompress_vm, "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vmv1r_v, "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv2r_v, "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv4r_v, "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv8r_v, "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vzext_vf2, "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vzext_vf4, "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vzext_vf8, "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsext_vf2, "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsext_vf4, "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsext_vf8, "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsetvli, "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli) +OP(vsetivli, "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli) +OP(vsetvl, "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(c_zext_b, "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_sext_b, "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_zext_h, "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_sext_h, "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_zext_w, "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_not, "c.not", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_mul, "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2) +OP(c_lbu, "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) +OP(c_lhu, "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(c_lh, "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(c_sb, "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) +OP(c_sh, "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(cm_push, "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist) +OP(cm_pop, "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_popret, "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_popretz, "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_mva01s, "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) +OP(cm_mvsa01, "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) +OP(cm_jt, "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) +OP(cm_jalt, "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) +OP(czero_eqz, "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(czero_nez, "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(fcvt_bf16_s, "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_s_bf16, "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(vfncvtbf16_f_f_w, "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvtbf16_f_f_v, "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwmaccbf16_vv, "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmaccbf16_vf, "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(flh, "flh", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fsh, "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fmv_h_x, "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fmv_x_h, "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1) +OP(fli_s, "fli.s", rv_codec_fli, rv_fmt_fli) +OP(fli_d, "fli.d", rv_codec_fli, rv_fmt_fli) +OP(fli_q, "fli.q", rv_codec_fli, rv_fmt_fli) +OP(fli_h, "fli.h", rv_codec_fli, rv_fmt_fli) +OP(fminm_s, "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_s, "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_d, "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_d, "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_q, "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_q, "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_h, "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_h, "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fround_s, "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_s, "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_d, "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_d, "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_q, "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_q, "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_h, "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_h, "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvtmod_w_d, "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fmvh_x_d, "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fmvp_d_x, "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2) +OP(fmvh_x_q, "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fmvp_q_x, "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2) +OP(fleq_s, "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_s, "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_d, "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_d, "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_q, "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_q, "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_h, "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_h, "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(vaesdf_vv, "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdf_vs, "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdm_vv, "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdm_vs, "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesef_vv, "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesef_vs, "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesem_vv, "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesem_vs, "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaeskf1_vi, "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vaeskf2_vi, "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vaesz_vs, "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vandn_vv, "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vandn_vx, "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vbrev_v, "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vbrev8_v, "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vclmul_vv, "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vclmul_vx, "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vclmulh_vv, "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vclmulh_vx, "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vclz_v, "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vcpop_v, "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vctz_v, "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vghsh_vv, "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vgmul_vv, "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vrev8_v, "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vrol_vv, "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrol_vx, "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vror_vv, "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vror_vx, "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vror_vi, "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm) +OP(vsha2ch_vv, "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vsha2cl_vv, "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vsha2ms_vv, "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vsm3c_vi, "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vsm3me_vv, "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vsm4k_vi, "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vsm4r_vv, "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vsm4r_vs, "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vwsll_vv, "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsll_vx, "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsll_vi, "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(amocas_w, "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(mop_r_0, "mop.r.0", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_1, "mop.r.1", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_2, "mop.r.2", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_3, "mop.r.3", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_4, "mop.r.4", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_5, "mop.r.5", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_6, "mop.r.6", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_7, "mop.r.7", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_8, "mop.r.8", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_9, "mop.r.9", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_10, "mop.r.10", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_11, "mop.r.11", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_12, "mop.r.12", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_13, "mop.r.13", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_14, "mop.r.14", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_15, "mop.r.15", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_16, "mop.r.16", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_17, "mop.r.17", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_18, "mop.r.18", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_19, "mop.r.19", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_20, "mop.r.20", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_21, "mop.r.21", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_22, "mop.r.22", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_23, "mop.r.23", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_24, "mop.r.24", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_25, "mop.r.25", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_26, "mop.r.26", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_27, "mop.r.27", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_28, "mop.r.28", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_29, "mop.r.29", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_30, "mop.r.30", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r_31, "mop.r.31", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_rr_0, "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_1, "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_2, "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_3, "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_4, "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_5, "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_6, "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr_7, "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(c_mop_1, "c.mop.1", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_3, "c.mop.3", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_5, "c.mop.5", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_7, "c.mop.7", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_9, "c.mop.9", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_11, "c.mop.11", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_13, "c.mop.13", rv_codec_ci_none, rv_fmt_none) +OP(c_mop_15, "c.mop.15", rv_codec_ci_none, rv_fmt_none) +OP(amoswap_b, "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_b, "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_b, "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_b, "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_b, "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_b, "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_b, "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_b, "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_b, "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_h, "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_h, "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_h, "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_h, "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_h, "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_h, "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_h, "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_h, "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_h, "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_b, "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_h, "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(wrs_sto, "wrs.sto", rv_codec_none, rv_fmt_none) +OP(wrs_nto, "wrs.nto", rv_codec_none, rv_fmt_none) +OP(lpad, "lpad", rv_codec_lp, rv_fmt_imm) +OP(sspush, "sspush", rv_codec_r, rv_fmt_rs2) +OP(sspopchk, "sspopchk", rv_codec_r, rv_fmt_rs1) +OP(ssrdp, "ssrdp", rv_codec_r, rv_fmt_rd) +OP(ssamoswap_w, "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(ssamoswap_d, "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(c_sspush, "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspush)) +OP(c_sspopchk, "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspopchk)) +OP(cbo_inval, "cbo.inval", rv_codec_r, rv_fmt_rs1) +OP(cbo_clean, "cbo.clean", rv_codec_r, rv_fmt_rs1) +OP(cbo_flush, "cbo.flush", rv_codec_r, rv_fmt_rs1) +OP(cbo_zero, "cbo.zero", rv_codec_r, rv_fmt_rs1) +OP(mnret, "mnret", rv_codec_none, rv_fmt_none) diff --git a/disas/riscv.c b/disas/riscv.c index c3a8cde37d..8aaad96bf4 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -29,964 +29,9 @@ #include "disas/riscv-xlrbr.h" typedef enum { - rv_op_illegal = 0, - rv_op_lui = 1, - rv_op_auipc = 2, - rv_op_jal = 3, - rv_op_jalr = 4, - rv_op_beq = 5, - rv_op_bne = 6, - rv_op_blt = 7, - rv_op_bge = 8, - rv_op_bltu = 9, - rv_op_bgeu = 10, - rv_op_lb = 11, - rv_op_lh = 12, - rv_op_lw = 13, - rv_op_lbu = 14, - rv_op_lhu = 15, - rv_op_sb = 16, - rv_op_sh = 17, - rv_op_sw = 18, - rv_op_addi = 19, - rv_op_slti = 20, - rv_op_sltiu = 21, - rv_op_xori = 22, - rv_op_ori = 23, - rv_op_andi = 24, - rv_op_slli = 25, - rv_op_srli = 26, - rv_op_srai = 27, - rv_op_add = 28, - rv_op_sub = 29, - rv_op_sll = 30, - rv_op_slt = 31, - rv_op_sltu = 32, - rv_op_xor = 33, - rv_op_srl = 34, - rv_op_sra = 35, - rv_op_or = 36, - rv_op_and = 37, - rv_op_fence = 38, - rv_op_fence_i = 39, - rv_op_lwu = 40, - rv_op_ld = 41, - rv_op_sd = 42, - rv_op_addiw = 43, - rv_op_slliw = 44, - rv_op_srliw = 45, - rv_op_sraiw = 46, - rv_op_addw = 47, - rv_op_subw = 48, - rv_op_sllw = 49, - rv_op_srlw = 50, - rv_op_sraw = 51, - rv_op_ldu = 52, - rv_op_lq = 53, - rv_op_sq = 54, - rv_op_addid = 55, - rv_op_sllid = 56, - rv_op_srlid = 57, - rv_op_sraid = 58, - rv_op_addd = 59, - rv_op_subd = 60, - rv_op_slld = 61, - rv_op_srld = 62, - rv_op_srad = 63, - rv_op_mul = 64, - rv_op_mulh = 65, - rv_op_mulhsu = 66, - rv_op_mulhu = 67, - rv_op_div = 68, - rv_op_divu = 69, - rv_op_rem = 70, - rv_op_remu = 71, - rv_op_mulw = 72, - rv_op_divw = 73, - rv_op_divuw = 74, - rv_op_remw = 75, - rv_op_remuw = 76, - rv_op_muld = 77, - rv_op_divd = 78, - rv_op_divud = 79, - rv_op_remd = 80, - rv_op_remud = 81, - rv_op_lr_w = 82, - rv_op_sc_w = 83, - rv_op_amoswap_w = 84, - rv_op_amoadd_w = 85, - rv_op_amoxor_w = 86, - rv_op_amoor_w = 87, - rv_op_amoand_w = 88, - rv_op_amomin_w = 89, - rv_op_amomax_w = 90, - rv_op_amominu_w = 91, - rv_op_amomaxu_w = 92, - rv_op_lr_d = 93, - rv_op_sc_d = 94, - rv_op_amoswap_d = 95, - rv_op_amoadd_d = 96, - rv_op_amoxor_d = 97, - rv_op_amoor_d = 98, - rv_op_amoand_d = 99, - rv_op_amomin_d = 100, - rv_op_amomax_d = 101, - rv_op_amominu_d = 102, - rv_op_amomaxu_d = 103, - rv_op_lr_q = 104, - rv_op_sc_q = 105, - rv_op_amoswap_q = 106, - rv_op_amoadd_q = 107, - rv_op_amoxor_q = 108, - rv_op_amoor_q = 109, - rv_op_amoand_q = 110, - rv_op_amomin_q = 111, - rv_op_amomax_q = 112, - rv_op_amominu_q = 113, - rv_op_amomaxu_q = 114, - rv_op_ecall = 115, - rv_op_ebreak = 116, - rv_op_uret = 117, - rv_op_sret = 118, - rv_op_hret = 119, - rv_op_mret = 120, - rv_op_dret = 121, - rv_op_sfence_vm = 122, - rv_op_sfence_vma = 123, - rv_op_wfi = 124, - rv_op_csrrw = 125, - rv_op_csrrs = 126, - rv_op_csrrc = 127, - rv_op_csrrwi = 128, - rv_op_csrrsi = 129, - rv_op_csrrci = 130, - rv_op_flw = 131, - rv_op_fsw = 132, - rv_op_fmadd_s = 133, - rv_op_fmsub_s = 134, - rv_op_fnmsub_s = 135, - rv_op_fnmadd_s = 136, - rv_op_fadd_s = 137, - rv_op_fsub_s = 138, - rv_op_fmul_s = 139, - rv_op_fdiv_s = 140, - rv_op_fsgnj_s = 141, - rv_op_fsgnjn_s = 142, - rv_op_fsgnjx_s = 143, - rv_op_fmin_s = 144, - rv_op_fmax_s = 145, - rv_op_fsqrt_s = 146, - rv_op_fle_s = 147, - rv_op_flt_s = 148, - rv_op_feq_s = 149, - rv_op_fcvt_w_s = 150, - rv_op_fcvt_wu_s = 151, - rv_op_fcvt_s_w = 152, - rv_op_fcvt_s_wu = 153, - rv_op_fmv_x_s = 154, - rv_op_fclass_s = 155, - rv_op_fmv_s_x = 156, - rv_op_fcvt_l_s = 157, - rv_op_fcvt_lu_s = 158, - rv_op_fcvt_s_l = 159, - rv_op_fcvt_s_lu = 160, - rv_op_fld = 161, - rv_op_fsd = 162, - rv_op_fmadd_d = 163, - rv_op_fmsub_d = 164, - rv_op_fnmsub_d = 165, - rv_op_fnmadd_d = 166, - rv_op_fadd_d = 167, - rv_op_fsub_d = 168, - rv_op_fmul_d = 169, - rv_op_fdiv_d = 170, - rv_op_fsgnj_d = 171, - rv_op_fsgnjn_d = 172, - rv_op_fsgnjx_d = 173, - rv_op_fmin_d = 174, - rv_op_fmax_d = 175, - rv_op_fcvt_s_d = 176, - rv_op_fcvt_d_s = 177, - rv_op_fsqrt_d = 178, - rv_op_fle_d = 179, - rv_op_flt_d = 180, - rv_op_feq_d = 181, - rv_op_fcvt_w_d = 182, - rv_op_fcvt_wu_d = 183, - rv_op_fcvt_d_w = 184, - rv_op_fcvt_d_wu = 185, - rv_op_fclass_d = 186, - rv_op_fcvt_l_d = 187, - rv_op_fcvt_lu_d = 188, - rv_op_fmv_x_d = 189, - rv_op_fcvt_d_l = 190, - rv_op_fcvt_d_lu = 191, - rv_op_fmv_d_x = 192, - rv_op_flq = 193, - rv_op_fsq = 194, - rv_op_fmadd_q = 195, - rv_op_fmsub_q = 196, - rv_op_fnmsub_q = 197, - rv_op_fnmadd_q = 198, - rv_op_fadd_q = 199, - rv_op_fsub_q = 200, - rv_op_fmul_q = 201, - rv_op_fdiv_q = 202, - rv_op_fsgnj_q = 203, - rv_op_fsgnjn_q = 204, - rv_op_fsgnjx_q = 205, - rv_op_fmin_q = 206, - rv_op_fmax_q = 207, - rv_op_fcvt_s_q = 208, - rv_op_fcvt_q_s = 209, - rv_op_fcvt_d_q = 210, - rv_op_fcvt_q_d = 211, - rv_op_fsqrt_q = 212, - rv_op_fle_q = 213, - rv_op_flt_q = 214, - rv_op_feq_q = 215, - rv_op_fcvt_w_q = 216, - rv_op_fcvt_wu_q = 217, - rv_op_fcvt_q_w = 218, - rv_op_fcvt_q_wu = 219, - rv_op_fclass_q = 220, - rv_op_fcvt_l_q = 221, - rv_op_fcvt_lu_q = 222, - rv_op_fcvt_q_l = 223, - rv_op_fcvt_q_lu = 224, - rv_op_fmv_x_q = 225, - rv_op_fmv_q_x = 226, - rv_op_c_addi4spn = 227, - rv_op_c_fld = 228, - rv_op_c_lw = 229, - rv_op_c_flw = 230, - rv_op_c_fsd = 231, - rv_op_c_sw = 232, - rv_op_c_fsw = 233, - rv_op_c_addi = 235, - rv_op_c_jal = 236, - rv_op_c_li = 237, - rv_op_c_addi16sp = 238, - rv_op_c_lui = 239, - rv_op_c_srli = 240, - rv_op_c_srai = 241, - rv_op_c_andi = 242, - rv_op_c_sub = 243, - rv_op_c_xor = 244, - rv_op_c_or = 245, - rv_op_c_and = 246, - rv_op_c_subw = 247, - rv_op_c_addw = 248, - rv_op_c_j = 249, - rv_op_c_beqz = 250, - rv_op_c_bnez = 251, - rv_op_c_slli = 252, - rv_op_c_fldsp = 253, - rv_op_c_lwsp = 254, - rv_op_c_flwsp = 255, - rv_op_c_jr = 256, - rv_op_c_mv = 257, - rv_op_c_ebreak = 258, - rv_op_c_jalr = 259, - rv_op_c_add = 260, - rv_op_c_fsdsp = 261, - rv_op_c_swsp = 262, - rv_op_c_fswsp = 263, - rv_op_c_ld = 264, - rv_op_c_sd = 265, - rv_op_c_addiw = 266, - rv_op_c_ldsp = 267, - rv_op_c_sdsp = 268, - rv_op_c_lq = 269, - rv_op_c_sq = 270, - rv_op_c_lqsp = 271, - rv_op_c_sqsp = 272, - rv_op_nop = 273, - rv_op_mv = 274, - rv_op_not = 275, - rv_op_neg = 276, - rv_op_negw = 277, - rv_op_sext_w = 278, - rv_op_seqz = 279, - rv_op_snez = 280, - rv_op_sltz = 281, - rv_op_sgtz = 282, - rv_op_fmv_s = 283, - rv_op_fabs_s = 284, - rv_op_fneg_s = 285, - rv_op_fmv_d = 286, - rv_op_fabs_d = 287, - rv_op_fneg_d = 288, - rv_op_fmv_q = 289, - rv_op_fabs_q = 290, - rv_op_fneg_q = 291, - rv_op_beqz = 292, - rv_op_bnez = 293, - rv_op_blez = 294, - rv_op_bgez = 295, - rv_op_bltz = 296, - rv_op_bgtz = 297, - rv_op_jal_ra = 298, - rv_op_jalr_ra = 299, - rv_op_j = 302, - rv_op_ret = 303, - rv_op_jr = 304, - rv_op_rdcycle = 305, - rv_op_rdtime = 306, - rv_op_rdinstret = 307, - rv_op_rdcycleh = 308, - rv_op_rdtimeh = 309, - rv_op_rdinstreth = 310, - rv_op_frcsr = 311, - rv_op_frrm = 312, - rv_op_frflags = 313, - rv_op_fscsr = 314, - rv_op_fsrm = 315, - rv_op_fsflags = 316, - rv_op_fsrmi = 317, - rv_op_fsflagsi = 318, - rv_op_bseti = 319, - rv_op_bclri = 320, - rv_op_binvi = 321, - rv_op_bexti = 322, - rv_op_rori = 323, - rv_op_clz = 324, - rv_op_ctz = 325, - rv_op_cpop = 326, - rv_op_sext_h = 327, - rv_op_sext_b = 328, - rv_op_xnor = 329, - rv_op_orn = 330, - rv_op_andn = 331, - rv_op_rol = 332, - rv_op_ror = 333, - rv_op_sh1add = 334, - rv_op_sh2add = 335, - rv_op_sh3add = 336, - rv_op_sh1add_uw = 337, - rv_op_sh2add_uw = 338, - rv_op_sh3add_uw = 339, - rv_op_clmul = 340, - rv_op_clmulr = 341, - rv_op_clmulh = 342, - rv_op_min = 343, - rv_op_minu = 344, - rv_op_max = 345, - rv_op_maxu = 346, - rv_op_clzw = 347, - rv_op_ctzw = 348, - rv_op_cpopw = 349, - rv_op_slli_uw = 350, - rv_op_add_uw = 351, - rv_op_rolw = 352, - rv_op_rorw = 353, - rv_op_rev8 = 354, - rv_op_zext_h = 355, - rv_op_roriw = 356, - rv_op_orc_b = 357, - rv_op_bset = 358, - rv_op_bclr = 359, - rv_op_binv = 360, - rv_op_bext = 361, - rv_op_aes32esmi = 362, - rv_op_aes32esi = 363, - rv_op_aes32dsmi = 364, - rv_op_aes32dsi = 365, - rv_op_aes64ks1i = 366, - rv_op_aes64ks2 = 367, - rv_op_aes64im = 368, - rv_op_aes64esm = 369, - rv_op_aes64es = 370, - rv_op_aes64dsm = 371, - rv_op_aes64ds = 372, - rv_op_sha256sig0 = 373, - rv_op_sha256sig1 = 374, - rv_op_sha256sum0 = 375, - rv_op_sha256sum1 = 376, - rv_op_sha512sig0 = 377, - rv_op_sha512sig1 = 378, - rv_op_sha512sum0 = 379, - rv_op_sha512sum1 = 380, - rv_op_sha512sum0r = 381, - rv_op_sha512sum1r = 382, - rv_op_sha512sig0l = 383, - rv_op_sha512sig0h = 384, - rv_op_sha512sig1l = 385, - rv_op_sha512sig1h = 386, - rv_op_sm3p0 = 387, - rv_op_sm3p1 = 388, - rv_op_sm4ed = 389, - rv_op_sm4ks = 390, - rv_op_brev8 = 391, - rv_op_pack = 392, - rv_op_packh = 393, - rv_op_packw = 394, - rv_op_unzip = 395, - rv_op_zip = 396, - rv_op_xperm4 = 397, - rv_op_xperm8 = 398, - rv_op_vle8_v = 399, - rv_op_vle16_v = 400, - rv_op_vle32_v = 401, - rv_op_vle64_v = 402, - rv_op_vse8_v = 403, - rv_op_vse16_v = 404, - rv_op_vse32_v = 405, - rv_op_vse64_v = 406, - rv_op_vlm_v = 407, - rv_op_vsm_v = 408, - rv_op_vlse8_v = 409, - rv_op_vlse16_v = 410, - rv_op_vlse32_v = 411, - rv_op_vlse64_v = 412, - rv_op_vsse8_v = 413, - rv_op_vsse16_v = 414, - rv_op_vsse32_v = 415, - rv_op_vsse64_v = 416, - rv_op_vluxei8_v = 417, - rv_op_vluxei16_v = 418, - rv_op_vluxei32_v = 419, - rv_op_vluxei64_v = 420, - rv_op_vloxei8_v = 421, - rv_op_vloxei16_v = 422, - rv_op_vloxei32_v = 423, - rv_op_vloxei64_v = 424, - rv_op_vsuxei8_v = 425, - rv_op_vsuxei16_v = 426, - rv_op_vsuxei32_v = 427, - rv_op_vsuxei64_v = 428, - rv_op_vsoxei8_v = 429, - rv_op_vsoxei16_v = 430, - rv_op_vsoxei32_v = 431, - rv_op_vsoxei64_v = 432, - rv_op_vle8ff_v = 433, - rv_op_vle16ff_v = 434, - rv_op_vle32ff_v = 435, - rv_op_vle64ff_v = 436, - rv_op_vl1re8_v = 437, - rv_op_vl1re16_v = 438, - rv_op_vl1re32_v = 439, - rv_op_vl1re64_v = 440, - rv_op_vl2re8_v = 441, - rv_op_vl2re16_v = 442, - rv_op_vl2re32_v = 443, - rv_op_vl2re64_v = 444, - rv_op_vl4re8_v = 445, - rv_op_vl4re16_v = 446, - rv_op_vl4re32_v = 447, - rv_op_vl4re64_v = 448, - rv_op_vl8re8_v = 449, - rv_op_vl8re16_v = 450, - rv_op_vl8re32_v = 451, - rv_op_vl8re64_v = 452, - rv_op_vs1r_v = 453, - rv_op_vs2r_v = 454, - rv_op_vs4r_v = 455, - rv_op_vs8r_v = 456, - rv_op_vadd_vv = 457, - rv_op_vadd_vx = 458, - rv_op_vadd_vi = 459, - rv_op_vsub_vv = 460, - rv_op_vsub_vx = 461, - rv_op_vrsub_vx = 462, - rv_op_vrsub_vi = 463, - rv_op_vwaddu_vv = 464, - rv_op_vwaddu_vx = 465, - rv_op_vwadd_vv = 466, - rv_op_vwadd_vx = 467, - rv_op_vwsubu_vv = 468, - rv_op_vwsubu_vx = 469, - rv_op_vwsub_vv = 470, - rv_op_vwsub_vx = 471, - rv_op_vwaddu_wv = 472, - rv_op_vwaddu_wx = 473, - rv_op_vwadd_wv = 474, - rv_op_vwadd_wx = 475, - rv_op_vwsubu_wv = 476, - rv_op_vwsubu_wx = 477, - rv_op_vwsub_wv = 478, - rv_op_vwsub_wx = 479, - rv_op_vadc_vvm = 480, - rv_op_vadc_vxm = 481, - rv_op_vadc_vim = 482, - rv_op_vmadc_vvm = 483, - rv_op_vmadc_vxm = 484, - rv_op_vmadc_vim = 485, - rv_op_vsbc_vvm = 486, - rv_op_vsbc_vxm = 487, - rv_op_vmsbc_vvm = 488, - rv_op_vmsbc_vxm = 489, - rv_op_vand_vv = 490, - rv_op_vand_vx = 491, - rv_op_vand_vi = 492, - rv_op_vor_vv = 493, - rv_op_vor_vx = 494, - rv_op_vor_vi = 495, - rv_op_vxor_vv = 496, - rv_op_vxor_vx = 497, - rv_op_vxor_vi = 498, - rv_op_vsll_vv = 499, - rv_op_vsll_vx = 500, - rv_op_vsll_vi = 501, - rv_op_vsrl_vv = 502, - rv_op_vsrl_vx = 503, - rv_op_vsrl_vi = 504, - rv_op_vsra_vv = 505, - rv_op_vsra_vx = 506, - rv_op_vsra_vi = 507, - rv_op_vnsrl_wv = 508, - rv_op_vnsrl_wx = 509, - rv_op_vnsrl_wi = 510, - rv_op_vnsra_wv = 511, - rv_op_vnsra_wx = 512, - rv_op_vnsra_wi = 513, - rv_op_vmseq_vv = 514, - rv_op_vmseq_vx = 515, - rv_op_vmseq_vi = 516, - rv_op_vmsne_vv = 517, - rv_op_vmsne_vx = 518, - rv_op_vmsne_vi = 519, - rv_op_vmsltu_vv = 520, - rv_op_vmsltu_vx = 521, - rv_op_vmslt_vv = 522, - rv_op_vmslt_vx = 523, - rv_op_vmsleu_vv = 524, - rv_op_vmsleu_vx = 525, - rv_op_vmsleu_vi = 526, - rv_op_vmsle_vv = 527, - rv_op_vmsle_vx = 528, - rv_op_vmsle_vi = 529, - rv_op_vmsgtu_vx = 530, - rv_op_vmsgtu_vi = 531, - rv_op_vmsgt_vx = 532, - rv_op_vmsgt_vi = 533, - rv_op_vminu_vv = 534, - rv_op_vminu_vx = 535, - rv_op_vmin_vv = 536, - rv_op_vmin_vx = 537, - rv_op_vmaxu_vv = 538, - rv_op_vmaxu_vx = 539, - rv_op_vmax_vv = 540, - rv_op_vmax_vx = 541, - rv_op_vmul_vv = 542, - rv_op_vmul_vx = 543, - rv_op_vmulh_vv = 544, - rv_op_vmulh_vx = 545, - rv_op_vmulhu_vv = 546, - rv_op_vmulhu_vx = 547, - rv_op_vmulhsu_vv = 548, - rv_op_vmulhsu_vx = 549, - rv_op_vdivu_vv = 550, - rv_op_vdivu_vx = 551, - rv_op_vdiv_vv = 552, - rv_op_vdiv_vx = 553, - rv_op_vremu_vv = 554, - rv_op_vremu_vx = 555, - rv_op_vrem_vv = 556, - rv_op_vrem_vx = 557, - rv_op_vwmulu_vv = 558, - rv_op_vwmulu_vx = 559, - rv_op_vwmulsu_vv = 560, - rv_op_vwmulsu_vx = 561, - rv_op_vwmul_vv = 562, - rv_op_vwmul_vx = 563, - rv_op_vmacc_vv = 564, - rv_op_vmacc_vx = 565, - rv_op_vnmsac_vv = 566, - rv_op_vnmsac_vx = 567, - rv_op_vmadd_vv = 568, - rv_op_vmadd_vx = 569, - rv_op_vnmsub_vv = 570, - rv_op_vnmsub_vx = 571, - rv_op_vwmaccu_vv = 572, - rv_op_vwmaccu_vx = 573, - rv_op_vwmacc_vv = 574, - rv_op_vwmacc_vx = 575, - rv_op_vwmaccsu_vv = 576, - rv_op_vwmaccsu_vx = 577, - rv_op_vwmaccus_vx = 578, - rv_op_vmv_v_v = 579, - rv_op_vmv_v_x = 580, - rv_op_vmv_v_i = 581, - rv_op_vmerge_vvm = 582, - rv_op_vmerge_vxm = 583, - rv_op_vmerge_vim = 584, - rv_op_vsaddu_vv = 585, - rv_op_vsaddu_vx = 586, - rv_op_vsaddu_vi = 587, - rv_op_vsadd_vv = 588, - rv_op_vsadd_vx = 589, - rv_op_vsadd_vi = 590, - rv_op_vssubu_vv = 591, - rv_op_vssubu_vx = 592, - rv_op_vssub_vv = 593, - rv_op_vssub_vx = 594, - rv_op_vaadd_vv = 595, - rv_op_vaadd_vx = 596, - rv_op_vaaddu_vv = 597, - rv_op_vaaddu_vx = 598, - rv_op_vasub_vv = 599, - rv_op_vasub_vx = 600, - rv_op_vasubu_vv = 601, - rv_op_vasubu_vx = 602, - rv_op_vsmul_vv = 603, - rv_op_vsmul_vx = 604, - rv_op_vssrl_vv = 605, - rv_op_vssrl_vx = 606, - rv_op_vssrl_vi = 607, - rv_op_vssra_vv = 608, - rv_op_vssra_vx = 609, - rv_op_vssra_vi = 610, - rv_op_vnclipu_wv = 611, - rv_op_vnclipu_wx = 612, - rv_op_vnclipu_wi = 613, - rv_op_vnclip_wv = 614, - rv_op_vnclip_wx = 615, - rv_op_vnclip_wi = 616, - rv_op_vfadd_vv = 617, - rv_op_vfadd_vf = 618, - rv_op_vfsub_vv = 619, - rv_op_vfsub_vf = 620, - rv_op_vfrsub_vf = 621, - rv_op_vfwadd_vv = 622, - rv_op_vfwadd_vf = 623, - rv_op_vfwadd_wv = 624, - rv_op_vfwadd_wf = 625, - rv_op_vfwsub_vv = 626, - rv_op_vfwsub_vf = 627, - rv_op_vfwsub_wv = 628, - rv_op_vfwsub_wf = 629, - rv_op_vfmul_vv = 630, - rv_op_vfmul_vf = 631, - rv_op_vfdiv_vv = 632, - rv_op_vfdiv_vf = 633, - rv_op_vfrdiv_vf = 634, - rv_op_vfwmul_vv = 635, - rv_op_vfwmul_vf = 636, - rv_op_vfmacc_vv = 637, - rv_op_vfmacc_vf = 638, - rv_op_vfnmacc_vv = 639, - rv_op_vfnmacc_vf = 640, - rv_op_vfmsac_vv = 641, - rv_op_vfmsac_vf = 642, - rv_op_vfnmsac_vv = 643, - rv_op_vfnmsac_vf = 644, - rv_op_vfmadd_vv = 645, - rv_op_vfmadd_vf = 646, - rv_op_vfnmadd_vv = 647, - rv_op_vfnmadd_vf = 648, - rv_op_vfmsub_vv = 649, - rv_op_vfmsub_vf = 650, - rv_op_vfnmsub_vv = 651, - rv_op_vfnmsub_vf = 652, - rv_op_vfwmacc_vv = 653, - rv_op_vfwmacc_vf = 654, - rv_op_vfwnmacc_vv = 655, - rv_op_vfwnmacc_vf = 656, - rv_op_vfwmsac_vv = 657, - rv_op_vfwmsac_vf = 658, - rv_op_vfwnmsac_vv = 659, - rv_op_vfwnmsac_vf = 660, - rv_op_vfsqrt_v = 661, - rv_op_vfrsqrt7_v = 662, - rv_op_vfrec7_v = 663, - rv_op_vfmin_vv = 664, - rv_op_vfmin_vf = 665, - rv_op_vfmax_vv = 666, - rv_op_vfmax_vf = 667, - rv_op_vfsgnj_vv = 668, - rv_op_vfsgnj_vf = 669, - rv_op_vfsgnjn_vv = 670, - rv_op_vfsgnjn_vf = 671, - rv_op_vfsgnjx_vv = 672, - rv_op_vfsgnjx_vf = 673, - rv_op_vfslide1up_vf = 674, - rv_op_vfslide1down_vf = 675, - rv_op_vmfeq_vv = 676, - rv_op_vmfeq_vf = 677, - rv_op_vmfne_vv = 678, - rv_op_vmfne_vf = 679, - rv_op_vmflt_vv = 680, - rv_op_vmflt_vf = 681, - rv_op_vmfle_vv = 682, - rv_op_vmfle_vf = 683, - rv_op_vmfgt_vf = 684, - rv_op_vmfge_vf = 685, - rv_op_vfclass_v = 686, - rv_op_vfmerge_vfm = 687, - rv_op_vfmv_v_f = 688, - rv_op_vfcvt_xu_f_v = 689, - rv_op_vfcvt_x_f_v = 690, - rv_op_vfcvt_f_xu_v = 691, - rv_op_vfcvt_f_x_v = 692, - rv_op_vfcvt_rtz_xu_f_v = 693, - rv_op_vfcvt_rtz_x_f_v = 694, - rv_op_vfwcvt_xu_f_v = 695, - rv_op_vfwcvt_x_f_v = 696, - rv_op_vfwcvt_f_xu_v = 697, - rv_op_vfwcvt_f_x_v = 698, - rv_op_vfwcvt_f_f_v = 699, - rv_op_vfwcvt_rtz_xu_f_v = 700, - rv_op_vfwcvt_rtz_x_f_v = 701, - rv_op_vfncvt_xu_f_w = 702, - rv_op_vfncvt_x_f_w = 703, - rv_op_vfncvt_f_xu_w = 704, - rv_op_vfncvt_f_x_w = 705, - rv_op_vfncvt_f_f_w = 706, - rv_op_vfncvt_rod_f_f_w = 707, - rv_op_vfncvt_rtz_xu_f_w = 708, - rv_op_vfncvt_rtz_x_f_w = 709, - rv_op_vredsum_vs = 710, - rv_op_vredand_vs = 711, - rv_op_vredor_vs = 712, - rv_op_vredxor_vs = 713, - rv_op_vredminu_vs = 714, - rv_op_vredmin_vs = 715, - rv_op_vredmaxu_vs = 716, - rv_op_vredmax_vs = 717, - rv_op_vwredsumu_vs = 718, - rv_op_vwredsum_vs = 719, - rv_op_vfredusum_vs = 720, - rv_op_vfredosum_vs = 721, - rv_op_vfredmin_vs = 722, - rv_op_vfredmax_vs = 723, - rv_op_vfwredusum_vs = 724, - rv_op_vfwredosum_vs = 725, - rv_op_vmand_mm = 726, - rv_op_vmnand_mm = 727, - rv_op_vmandn_mm = 728, - rv_op_vmxor_mm = 729, - rv_op_vmor_mm = 730, - rv_op_vmnor_mm = 731, - rv_op_vmorn_mm = 732, - rv_op_vmxnor_mm = 733, - rv_op_vcpop_m = 734, - rv_op_vfirst_m = 735, - rv_op_vmsbf_m = 736, - rv_op_vmsif_m = 737, - rv_op_vmsof_m = 738, - rv_op_viota_m = 739, - rv_op_vid_v = 740, - rv_op_vmv_x_s = 741, - rv_op_vmv_s_x = 742, - rv_op_vfmv_f_s = 743, - rv_op_vfmv_s_f = 744, - rv_op_vslideup_vx = 745, - rv_op_vslideup_vi = 746, - rv_op_vslide1up_vx = 747, - rv_op_vslidedown_vx = 748, - rv_op_vslidedown_vi = 749, - rv_op_vslide1down_vx = 750, - rv_op_vrgather_vv = 751, - rv_op_vrgatherei16_vv = 752, - rv_op_vrgather_vx = 753, - rv_op_vrgather_vi = 754, - rv_op_vcompress_vm = 755, - rv_op_vmv1r_v = 756, - rv_op_vmv2r_v = 757, - rv_op_vmv4r_v = 758, - rv_op_vmv8r_v = 759, - rv_op_vzext_vf2 = 760, - rv_op_vzext_vf4 = 761, - rv_op_vzext_vf8 = 762, - rv_op_vsext_vf2 = 763, - rv_op_vsext_vf4 = 764, - rv_op_vsext_vf8 = 765, - rv_op_vsetvli = 766, - rv_op_vsetivli = 767, - rv_op_vsetvl = 768, - rv_op_c_zext_b = 769, - rv_op_c_sext_b = 770, - rv_op_c_zext_h = 771, - rv_op_c_sext_h = 772, - rv_op_c_zext_w = 773, - rv_op_c_not = 774, - rv_op_c_mul = 775, - rv_op_c_lbu = 776, - rv_op_c_lhu = 777, - rv_op_c_lh = 778, - rv_op_c_sb = 779, - rv_op_c_sh = 780, - rv_op_cm_push = 781, - rv_op_cm_pop = 782, - rv_op_cm_popret = 783, - rv_op_cm_popretz = 784, - rv_op_cm_mva01s = 785, - rv_op_cm_mvsa01 = 786, - rv_op_cm_jt = 787, - rv_op_cm_jalt = 788, - rv_op_czero_eqz = 789, - rv_op_czero_nez = 790, - rv_op_fcvt_bf16_s = 791, - rv_op_fcvt_s_bf16 = 792, - rv_op_vfncvtbf16_f_f_w = 793, - rv_op_vfwcvtbf16_f_f_v = 794, - rv_op_vfwmaccbf16_vv = 795, - rv_op_vfwmaccbf16_vf = 796, - rv_op_flh = 797, - rv_op_fsh = 798, - rv_op_fmv_h_x = 799, - rv_op_fmv_x_h = 800, - rv_op_fli_s = 801, - rv_op_fli_d = 802, - rv_op_fli_q = 803, - rv_op_fli_h = 804, - rv_op_fminm_s = 805, - rv_op_fmaxm_s = 806, - rv_op_fminm_d = 807, - rv_op_fmaxm_d = 808, - rv_op_fminm_q = 809, - rv_op_fmaxm_q = 810, - rv_op_fminm_h = 811, - rv_op_fmaxm_h = 812, - rv_op_fround_s = 813, - rv_op_froundnx_s = 814, - rv_op_fround_d = 815, - rv_op_froundnx_d = 816, - rv_op_fround_q = 817, - rv_op_froundnx_q = 818, - rv_op_fround_h = 819, - rv_op_froundnx_h = 820, - rv_op_fcvtmod_w_d = 821, - rv_op_fmvh_x_d = 822, - rv_op_fmvp_d_x = 823, - rv_op_fmvh_x_q = 824, - rv_op_fmvp_q_x = 825, - rv_op_fleq_s = 826, - rv_op_fltq_s = 827, - rv_op_fleq_d = 828, - rv_op_fltq_d = 829, - rv_op_fleq_q = 830, - rv_op_fltq_q = 831, - rv_op_fleq_h = 832, - rv_op_fltq_h = 833, - rv_op_vaesdf_vv = 834, - rv_op_vaesdf_vs = 835, - rv_op_vaesdm_vv = 836, - rv_op_vaesdm_vs = 837, - rv_op_vaesef_vv = 838, - rv_op_vaesef_vs = 839, - rv_op_vaesem_vv = 840, - rv_op_vaesem_vs = 841, - rv_op_vaeskf1_vi = 842, - rv_op_vaeskf2_vi = 843, - rv_op_vaesz_vs = 844, - rv_op_vandn_vv = 845, - rv_op_vandn_vx = 846, - rv_op_vbrev_v = 847, - rv_op_vbrev8_v = 848, - rv_op_vclmul_vv = 849, - rv_op_vclmul_vx = 850, - rv_op_vclmulh_vv = 851, - rv_op_vclmulh_vx = 852, - rv_op_vclz_v = 853, - rv_op_vcpop_v = 854, - rv_op_vctz_v = 855, - rv_op_vghsh_vv = 856, - rv_op_vgmul_vv = 857, - rv_op_vrev8_v = 858, - rv_op_vrol_vv = 859, - rv_op_vrol_vx = 860, - rv_op_vror_vv = 861, - rv_op_vror_vx = 862, - rv_op_vror_vi = 863, - rv_op_vsha2ch_vv = 864, - rv_op_vsha2cl_vv = 865, - rv_op_vsha2ms_vv = 866, - rv_op_vsm3c_vi = 867, - rv_op_vsm3me_vv = 868, - rv_op_vsm4k_vi = 869, - rv_op_vsm4r_vv = 870, - rv_op_vsm4r_vs = 871, - rv_op_vwsll_vv = 872, - rv_op_vwsll_vx = 873, - rv_op_vwsll_vi = 874, - rv_op_amocas_w = 875, - rv_op_amocas_d = 876, - rv_op_amocas_q = 877, - rv_mop_r_0 = 878, - rv_mop_r_1 = 879, - rv_mop_r_2 = 880, - rv_mop_r_3 = 881, - rv_mop_r_4 = 882, - rv_mop_r_5 = 883, - rv_mop_r_6 = 884, - rv_mop_r_7 = 885, - rv_mop_r_8 = 886, - rv_mop_r_9 = 887, - rv_mop_r_10 = 888, - rv_mop_r_11 = 889, - rv_mop_r_12 = 890, - rv_mop_r_13 = 891, - rv_mop_r_14 = 892, - rv_mop_r_15 = 893, - rv_mop_r_16 = 894, - rv_mop_r_17 = 895, - rv_mop_r_18 = 896, - rv_mop_r_19 = 897, - rv_mop_r_20 = 898, - rv_mop_r_21 = 899, - rv_mop_r_22 = 900, - rv_mop_r_23 = 901, - rv_mop_r_24 = 902, - rv_mop_r_25 = 903, - rv_mop_r_26 = 904, - rv_mop_r_27 = 905, - rv_mop_r_28 = 906, - rv_mop_r_29 = 907, - rv_mop_r_30 = 908, - rv_mop_r_31 = 909, - rv_mop_rr_0 = 910, - rv_mop_rr_1 = 911, - rv_mop_rr_2 = 912, - rv_mop_rr_3 = 913, - rv_mop_rr_4 = 914, - rv_mop_rr_5 = 915, - rv_mop_rr_6 = 916, - rv_mop_rr_7 = 917, - rv_c_mop_1 = 918, - rv_c_mop_3 = 919, - rv_c_mop_5 = 920, - rv_c_mop_7 = 921, - rv_c_mop_9 = 922, - rv_c_mop_11 = 923, - rv_c_mop_13 = 924, - rv_c_mop_15 = 925, - rv_op_amoswap_b = 926, - rv_op_amoadd_b = 927, - rv_op_amoxor_b = 928, - rv_op_amoor_b = 929, - rv_op_amoand_b = 930, - rv_op_amomin_b = 931, - rv_op_amomax_b = 932, - rv_op_amominu_b = 933, - rv_op_amomaxu_b = 934, - rv_op_amoswap_h = 935, - rv_op_amoadd_h = 936, - rv_op_amoxor_h = 937, - rv_op_amoor_h = 938, - rv_op_amoand_h = 939, - rv_op_amomin_h = 940, - rv_op_amomax_h = 941, - rv_op_amominu_h = 942, - rv_op_amomaxu_h = 943, - rv_op_amocas_b = 944, - rv_op_amocas_h = 945, - rv_op_wrs_sto = 946, - rv_op_wrs_nto = 947, - rv_op_lpad = 948, - rv_op_sspush = 949, - rv_op_sspopchk = 950, - rv_op_ssrdp = 951, - rv_op_ssamoswap_w = 952, - rv_op_ssamoswap_d = 953, - rv_op_c_sspush = 954, - rv_op_c_sspopchk = 955, - rv_op_cbo_inval = 956, - rv_op_cbo_clean = 957, - rv_op_cbo_flush = 958, - rv_op_cbo_zero = 959, - rv_op_mnret = 960, +#define OP(N, ...) rv_op_##N, +#include "riscv-op.c.inc" +#undef OP } rv_op; /* register names */ @@ -1601,967 +646,9 @@ static uint32_t operand_lpl(rv_inst inst) /* instruction metadata */ static const rv_opcode_data rvi_opcode_data[] = { - { "illegal", rv_codec_none, rv_fmt_none }, - { "lui", rv_codec_u, rv_fmt_rd_uimm }, - { "auipc", rv_codec_u, rv_fmt_rd_uoffset }, - { "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal }, - { "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr }, - { "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq }, - { "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne }, - { "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt }, - { "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge }, - { "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset }, - { "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset }, - { "lb", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "lh", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "lw", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "lbu", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "lhu", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "sb", rv_codec_s, rv_fmt_rs2_offset_rs1 }, - { "sh", rv_codec_s, rv_fmt_rs2_offset_rs1 }, - { "sw", rv_codec_s, rv_fmt_rs2_offset_rs1 }, - { "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi }, - { "slti", rv_codec_i, rv_fmt_rd_rs1_imm }, - { "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu }, - { "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori }, - { "ori", rv_codec_i, rv_fmt_rd_rs1_imm }, - { "andi", rv_codec_i, rv_fmt_rd_rs1_imm }, - { "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub }, - { "sll", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt }, - { "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu }, - { "xor", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "srl", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sra", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "or", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "and", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "fence", rv_codec_r_f, rv_fmt_pred_succ }, - { "fence.i", rv_codec_none, rv_fmt_none }, - { "lwu", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "ld", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "sd", rv_codec_s, rv_fmt_rs2_offset_rs1 }, - { "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw }, - { "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, - { "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, - { "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, - { "addw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw }, - { "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "ldu", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "lq", rv_codec_i, rv_fmt_rd_offset_rs1 }, - { "sq", rv_codec_s, rv_fmt_rs2_offset_rs1 }, - { "addid", rv_codec_i, rv_fmt_rd_rs1_imm }, - { "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, - { "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, - { "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, - { "addd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "subd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "slld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "srld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "srad", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mul", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mulh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mulhsu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mulhu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "div", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "divu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "rem", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "remu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mulw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "divw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "remw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "muld", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "divd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "divud", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "remd", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "remud", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, - { "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, - { "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1 }, - { "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "ecall", rv_codec_none, rv_fmt_none }, - { "ebreak", rv_codec_none, rv_fmt_none }, - { "uret", rv_codec_none, rv_fmt_none }, - { "sret", rv_codec_none, rv_fmt_none }, - { "hret", rv_codec_none, rv_fmt_none }, - { "mret", rv_codec_none, rv_fmt_none }, - { "dret", rv_codec_none, rv_fmt_none }, - { "sfence.vm", rv_codec_r, rv_fmt_rs1 }, - { "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2 }, - { "wfi", rv_codec_none, rv_fmt_none }, - { "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, - { "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, - { "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1 }, - { "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, - { "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, - { "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm }, - { "flw", rv_codec_i, rv_fmt_frd_offset_rs1 }, - { "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1 }, - { "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s }, - { "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s }, - { "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s }, - { "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1 }, - { "fclass.s", rv_codec_r, rv_fmt_rd_frs1 }, - { "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fld", rv_codec_i, rv_fmt_frd_offset_rs1 }, - { "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1 }, - { "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d }, - { "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d }, - { "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d }, - { "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fclass.d", rv_codec_r, rv_fmt_rd_frs1 }, - { "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1 }, - { "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "flq", rv_codec_i, rv_fmt_frd_offset_rs1 }, - { "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1 }, - { "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3 }, - { "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2 }, - { "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q }, - { "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q }, - { "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q }, - { "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fclass.q", rv_codec_r, rv_fmt_rd_frs1 }, - { "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1 }, - { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1 }, - { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(rv_op_addi) }, - { "c.fld", rv_codec_cl_ld, NULL, DECOMP(rv_op_fld) }, - { "c.lw", rv_codec_cl_lw, NULL, DECOMP(rv_op_lw) }, - { "c.flw", rv_codec_cl_lw, NULL, DECOMP(rv_op_flw) }, - { "c.fsd", rv_codec_cs_sd, NULL, DECOMP(rv_op_fsd) }, - { "c.sw", rv_codec_cs_sw, NULL, DECOMP(rv_op_sw) }, - { "c.fsw", rv_codec_cs_sw, NULL, DECOMP(rv_op_fsw) }, - { }, - { "c.addi", rv_codec_ci, NULL, DECOMP(rv_op_addi) }, - { "c.jal", rv_codec_cj_jal, NULL, DECOMP(rv_op_jal) }, - { "c.li", rv_codec_ci_li, NULL, DECOMP(rv_op_addi) }, - { "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(rv_op_addi) }, - { "c.lui", rv_codec_ci_lui, NULL, DECOMP(rv_op_lui) }, - { "c.srli", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srli) }, - { "c.srai", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srai) }, - { "c.andi", rv_codec_cb_imm, NULL, DECOMP(rv_op_andi) }, - { "c.sub", rv_codec_cs, NULL, DECOMP(rv_op_sub) }, - { "c.xor", rv_codec_cs, NULL, DECOMP(rv_op_xor) }, - { "c.or", rv_codec_cs, NULL, DECOMP(rv_op_or) }, - { "c.and", rv_codec_cs, NULL, DECOMP(rv_op_and) }, - { "c.subw", rv_codec_cs, NULL, DECOMP(rv_op_subw) }, - { "c.addw", rv_codec_cs, NULL, DECOMP(rv_op_addw) }, - { "c.j", rv_codec_cj, NULL, DECOMP(rv_op_j) }, - { "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beqz) }, - { "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bnez) }, - { "c.slli", rv_codec_ci_sh6, NULL, DECOMP(rv_op_slli) }, - { "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_fld) }, - { "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_lw) }, - { "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_flw) }, - { "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jr) }, - { "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_mv) }, - { "c.ebreak", rv_codec_ci_none, NULL, DECOMP(rv_op_ebreak) }, - { "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(rv_op_jalr) }, - { "c.add", rv_codec_cr, NULL, DECOMP(rv_op_add) }, - { "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_fsd) }, - { "c.swsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_sw) }, - { "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_fsw) }, - { "c.ld", rv_codec_cl_ld, NULL, DECOMP(rv_op_ld) }, - { "c.sd", rv_codec_cs_sd, NULL, DECOMP(rv_op_sd) }, - { "c.addiw", rv_codec_ci, NULL, DECOMP(rv_op_addiw) }, - { "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_ld) }, - { "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_sd) }, - { "c.lq", rv_codec_cl_lq, NULL, DECOMP(rv_op_lq) }, - { "c.sq", rv_codec_cs_sq, NULL, DECOMP(rv_op_sq) }, - { "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq) }, - { "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq) }, - { "nop", rv_codec_illegal, rv_fmt_none }, - { "mv", rv_codec_illegal, rv_fmt_rd_rs1, rvcp_mv }, - { "not", rv_codec_illegal, rv_fmt_rd_rs1 }, - { "neg", rv_codec_illegal, rv_fmt_rd_rs2 }, - { "negw", rv_codec_illegal, rv_fmt_rd_rs2 }, - { "sext.w", rv_codec_illegal, rv_fmt_rd_rs1 }, - { "seqz", rv_codec_illegal, rv_fmt_rd_rs1 }, - { "snez", rv_codec_illegal, rv_fmt_rd_rs2 }, - { "sltz", rv_codec_illegal, rv_fmt_rd_rs1 }, - { "sgtz", rv_codec_illegal, rv_fmt_rd_rs2 }, - { "fmv.s", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fabs.s", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fneg.s", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fmv.d", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fabs.d", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fneg.d", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fmv.q", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fabs.q", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "fneg.q", rv_codec_illegal, rv_fmt_frd_frs1 }, - { "beqz", rv_codec_illegal, rv_fmt_rs1_offset }, - { "bnez", rv_codec_illegal, rv_fmt_rs1_offset }, - { "blez", rv_codec_illegal, rv_fmt_rs2_offset }, - { "bgez", rv_codec_illegal, rv_fmt_rs1_offset }, - { "bltz", rv_codec_illegal, rv_fmt_rs1_offset }, - { "bgtz", rv_codec_illegal, rv_fmt_rs2_offset }, - { "jal", rv_codec_illegal, rv_fmt_offset }, /* rv_op_jal_ra */ - { "jalr", rv_codec_illegal, rv_fmt_rs1 }, /* rv_op_jalr_ra */ - { }, - { }, - { "j", rv_codec_illegal, rv_fmt_offset }, - { "ret", rv_codec_illegal, rv_fmt_none }, - { "jr", rv_codec_illegal, rv_fmt_rs1, rvcp_jr }, - { "rdcycle", rv_codec_i_csr, rv_fmt_rd }, - { "rdtime", rv_codec_i_csr, rv_fmt_rd }, - { "rdinstret", rv_codec_i_csr, rv_fmt_rd }, - { "rdcycleh", rv_codec_i_csr, rv_fmt_rd }, - { "rdtimeh", rv_codec_i_csr, rv_fmt_rd }, - { "rdinstreth", rv_codec_i_csr, rv_fmt_rd }, - { "frcsr", rv_codec_i_csr, rv_fmt_rd }, - { "frrm", rv_codec_i_csr, rv_fmt_rd }, - { "frflags", rv_codec_i_csr, rv_fmt_rd }, - { "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1 }, - { "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1 }, - { "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1 }, - { "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm }, - { "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm }, - { "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm }, - { "clz", rv_codec_r, rv_fmt_rd_rs1 }, - { "ctz", rv_codec_r, rv_fmt_rd_rs1 }, - { "cpop", rv_codec_r, rv_fmt_rd_rs1 }, - { "sext.h", rv_codec_r, rv_fmt_rd_rs1 }, - { "sext.b", rv_codec_r, rv_fmt_rd_rs1 }, - { "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "orn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "andn", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "rol", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "ror", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "min", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "minu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "max", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "clzw", rv_codec_r, rv_fmt_rd_rs1 }, - { "ctzw", rv_codec_r, rv_fmt_rd_rs1 }, - { "cpopw", rv_codec_r, rv_fmt_rd_rs1 }, - { "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm }, - { "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "rev8", rv_codec_r, rv_fmt_rd_rs1 }, - { "zext.h", rv_codec_r, rv_fmt_rd_rs1 }, - { "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm }, - { "orc.b", rv_codec_r, rv_fmt_rd_rs1 }, - { "bset", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "binv", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "bext", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum }, - { "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "aes64im", rv_codec_r, rv_fmt_rd_rs1 }, - { "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha256sig0", rv_codec_r, rv_fmt_rd_rs1 }, - { "sha256sig1", rv_codec_r, rv_fmt_rd_rs1 }, - { "sha256sum0", rv_codec_r, rv_fmt_rd_rs1 }, - { "sha256sum1", rv_codec_r, rv_fmt_rd_rs1 }, - { "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "sm3p0", rv_codec_r, rv_fmt_rd_rs1 }, - { "sm3p1", rv_codec_r, rv_fmt_rd_rs1 }, - { "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs }, - { "brev8", rv_codec_r, rv_fmt_rd_rs1 }, - { "pack", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "packh", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "packw", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "unzip", rv_codec_r, rv_fmt_rd_rs1 }, - { "zip", rv_codec_r, rv_fmt_rd_rs1 }, - { "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "xperm8", rv_codec_r, rv_fmt_rd_rs1 }, - { "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm }, - { "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm }, - { "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm }, - { "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, - { "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, - { "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, - { "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, - { "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, - { "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, - { "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, - { "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, - { "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, - { "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, - { "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm }, - { "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1 }, - { "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1 }, - { "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm }, - { "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl }, - { "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl }, - { "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl }, - { "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm }, - { "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm }, - { "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl }, - { "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1 }, - { "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm }, - { "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm }, - { "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vid.v", rv_codec_v_r, rv_fmt_vd_vm }, - { "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2 }, - { "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1 }, - { "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2 }, - { "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1 }, - { "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli }, - { "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli }, - { "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.not", rv_codec_zcb_ext, rv_fmt_rd }, - { "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2 }, - { "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst }, - { "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, - { "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, - { "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst }, - { "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst }, - { "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist }, - { "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, - { "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, - { "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist }, - { "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2 }, - { "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2 }, - { "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index }, - { "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index }, - { "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm }, - { "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm }, - { "flh", rv_codec_i, rv_fmt_frd_offset_rs1 }, - { "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1 }, - { "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1 }, - { "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1 }, - { "fli.s", rv_codec_fli, rv_fmt_fli }, - { "fli.d", rv_codec_fli, rv_fmt_fli }, - { "fli.q", rv_codec_fli, rv_fmt_fli }, - { "fli.h", rv_codec_fli, rv_fmt_fli }, - { "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2 }, - { "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1 }, - { "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1 }, - { "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1 }, - { "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2 }, - { "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1 }, - { "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2 }, - { "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2 }, - { "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, - { "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, - { "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm }, - { "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm }, - { "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, - { "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1 }, - { "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm }, - { "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2 }, - { "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm }, - { "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm }, - { "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm }, - { "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "mop.r.0", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.1", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.2", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.3", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.4", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.5", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.6", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.7", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.8", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.9", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.10", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.11", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.12", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.13", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.14", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.15", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.16", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.17", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.18", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.19", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.20", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.21", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.22", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.23", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.24", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.25", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.26", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.27", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.28", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.29", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.30", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.r.31", rv_codec_r, rv_fmt_rd_rs1 }, - { "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2 }, - { "c.mop.1", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.3", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.5", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.7", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.9", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.11", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.13", rv_codec_ci_none, rv_fmt_none }, - { "c.mop.15", rv_codec_ci_none, rv_fmt_none }, - { "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "wrs.sto", rv_codec_none, rv_fmt_none }, - { "wrs.nto", rv_codec_none, rv_fmt_none }, - { "lpad", rv_codec_lp, rv_fmt_imm }, - { "sspush", rv_codec_r, rv_fmt_rs2 }, - { "sspopchk", rv_codec_r, rv_fmt_rs1 }, - { "ssrdp", rv_codec_r, rv_fmt_rd }, - { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1 }, - { "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspush) }, - { "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspopchk) }, - { "cbo.inval", rv_codec_r, rv_fmt_rs1 }, - { "cbo.clean", rv_codec_r, rv_fmt_rs1 }, - { "cbo.flush", rv_codec_r, rv_fmt_rs1 }, - { "cbo.zero", rv_codec_r, rv_fmt_rs1 }, - { "mnret", rv_codec_none, rv_fmt_none }, +#define OP(N, ...) { __VA_ARGS__ }, +#include "riscv-op.c.inc" +#undef OP }; /* CSR names */ @@ -2928,7 +1015,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) (((inst >> 11) & 0b11) == 0b0)) { unsigned int cmop_code = 0; cmop_code = ((inst >> 8) & 0b111); - op = rv_c_mop_1 + cmop_code; + op = rv_op_c_mop_1 + cmop_code; if (dec->cfg->ext_zicfiss) { op = (cmop_code == 0) ? rv_op_c_sspush : op; op = (cmop_code == 2) ? rv_op_c_sspopchk : op; @@ -4459,7 +2546,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) 2, 2, extract32(inst, 26, 2)), 4, 1, extract32(inst, 30, 1)); - op = rv_mop_r_0 + imm_mop5; + op = rv_op_mop_r_0 + imm_mop5; /* if zicfiss enabled and mop5 is shadow stack */ if (dec->cfg->ext_zicfiss && ((imm_mop5 & 0b11100) == 0b11100)) { @@ -4478,7 +2565,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) == 0b1000001) { imm_mop3 = deposit32(extract32(inst, 26, 2), 2, 1, extract32(inst, 30, 1)); - op = rv_mop_rr_0 + imm_mop3; + op = rv_op_mop_rr_0 + imm_mop3; /* if zicfiss enabled and mop3 is shadow stack */ if (dec->cfg->ext_zicfiss && ((imm_mop3 & 0b111) == 0b111)) { From 1a13fad072fb39876627b3a20b1a423a92813688 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:36 -0700 Subject: [PATCH 561/627] disas/riscv: Merge all mop.r.n to one pattern Avoid performing arithmetic on rv_op_mop_r_0. Treat the 'n' as an immediate. Create a codec and format to match. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-47-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 33 +-------------------------------- disas/riscv.c | 15 ++++++++++++++- disas/riscv.h | 2 ++ 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index 3fe934688e..222d249a70 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -873,38 +873,7 @@ OP(vwsll_vi, "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) OP(amocas_w, "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(mop_r_0, "mop.r.0", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_1, "mop.r.1", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_2, "mop.r.2", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_3, "mop.r.3", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_4, "mop.r.4", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_5, "mop.r.5", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_6, "mop.r.6", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_7, "mop.r.7", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_8, "mop.r.8", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_9, "mop.r.9", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_10, "mop.r.10", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_11, "mop.r.11", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_12, "mop.r.12", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_13, "mop.r.13", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_14, "mop.r.14", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_15, "mop.r.15", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_16, "mop.r.16", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_17, "mop.r.17", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_18, "mop.r.18", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_19, "mop.r.19", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_20, "mop.r.20", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_21, "mop.r.21", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_22, "mop.r.22", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_23, "mop.r.23", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_24, "mop.r.24", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_25, "mop.r.25", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_26, "mop.r.26", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_27, "mop.r.27", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_28, "mop.r.28", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_29, "mop.r.29", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_30, "mop.r.30", rv_codec_r, rv_fmt_rd_rs1) -OP(mop_r_31, "mop.r.31", rv_codec_r, rv_fmt_rd_rs1) +OP(mop_r, "mop.r", rv_codec_mop_r, rv_fmt_mop_r) OP(mop_rr_0, "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mop_rr_1, "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mop_rr_2, "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2) diff --git a/disas/riscv.c b/disas/riscv.c index 8aaad96bf4..0751f1a841 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -643,6 +643,13 @@ static uint32_t operand_lpl(rv_inst inst) return extract32(inst, 12, 20); } +static uint32_t operand_mop_r_imm(rv_inst inst) +{ + return (extract32(inst, 30, 1) << 4) | + (extract32(inst, 26, 2) << 2) | + extract32(inst, 20, 2); +} + /* instruction metadata */ static const rv_opcode_data rvi_opcode_data[] = { @@ -2546,7 +2553,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) 2, 2, extract32(inst, 26, 2)), 4, 1, extract32(inst, 30, 1)); - op = rv_op_mop_r_0 + imm_mop5; + op = rv_op_mop_r; /* if zicfiss enabled and mop5 is shadow stack */ if (dec->cfg->ext_zicfiss && ((imm_mop5 & 0b11100) == 0b11100)) { @@ -3049,6 +3056,11 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, dec->rs1 = dec->rs2 = operand_crs1(inst); dec->imm = 0; break; + case rv_codec_mop_r: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->imm = operand_mop_r_imm(inst); + break; default: g_assert_not_reached(); } @@ -3134,6 +3146,7 @@ static GString *format_inst(size_t tab, rv_decode *dec, g_string_append(buf, op->name); break; case '(': + case '.': case ',': case ')': case '-': diff --git a/disas/riscv.h b/disas/riscv.h index 5ac8c41616..b47a7f0150 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -160,6 +160,7 @@ typedef enum { rv_codec_fli, rv_codec_lp, rv_codec_cmop_ss, + rv_codec_mop_r, } rv_codec; /* structures */ @@ -284,5 +285,6 @@ typedef struct { #define rv_fmt_rd_rs1_immh_imml_addr "O\t0,(1),i,j" #define rv_fmt_rd2_imm "O\t0,2,(1),i" #define rv_fmt_fli "O\t3,h" +#define rv_fmt_mop_r "O.i\t0,1" #endif /* DISAS_RISCV_H */ From e2851825f44e107c1092fca916ee9800ac86380a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:37 -0700 Subject: [PATCH 562/627] disas/riscv: Merge all mop.rr.n to one pattern Avoid performing arithmetic on rv_op_mop_rr_0. Treat the 'n' as an immediate. Create a codec and format to match. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-48-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 9 +-------- disas/riscv.c | 13 ++++++++++++- disas/riscv.h | 2 ++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index 222d249a70..2100e54475 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -874,14 +874,7 @@ OP(amocas_w, "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(mop_r, "mop.r", rv_codec_mop_r, rv_fmt_mop_r) -OP(mop_rr_0, "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_1, "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_2, "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_3, "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_4, "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_5, "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_6, "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(mop_rr_7, "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mop_rr, "mop.rr", rv_codec_mop_rr, rv_fmt_mop_rr) OP(c_mop_1, "c.mop.1", rv_codec_ci_none, rv_fmt_none) OP(c_mop_3, "c.mop.3", rv_codec_ci_none, rv_fmt_none) OP(c_mop_5, "c.mop.5", rv_codec_ci_none, rv_fmt_none) diff --git a/disas/riscv.c b/disas/riscv.c index 0751f1a841..22104638e1 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -650,6 +650,11 @@ static uint32_t operand_mop_r_imm(rv_inst inst) extract32(inst, 20, 2); } +static uint32_t operand_mop_rr_imm(rv_inst inst) +{ + return (extract32(inst, 30, 1) << 2) | extract32(inst, 26, 2); +} + /* instruction metadata */ static const rv_opcode_data rvi_opcode_data[] = { @@ -2572,7 +2577,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) == 0b1000001) { imm_mop3 = deposit32(extract32(inst, 26, 2), 2, 1, extract32(inst, 30, 1)); - op = rv_op_mop_rr_0 + imm_mop3; + op = rv_op_mop_rr; /* if zicfiss enabled and mop3 is shadow stack */ if (dec->cfg->ext_zicfiss && ((imm_mop3 & 0b111) == 0b111)) { @@ -3061,6 +3066,12 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, dec->rs1 = operand_rs1(inst); dec->imm = operand_mop_r_imm(inst); break; + case rv_codec_mop_rr: + dec->rd = operand_rd(inst); + dec->rs1 = operand_rs1(inst); + dec->rs2 = operand_rs2(inst); + dec->imm = operand_mop_rr_imm(inst); + break; default: g_assert_not_reached(); } diff --git a/disas/riscv.h b/disas/riscv.h index b47a7f0150..47647f750f 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -161,6 +161,7 @@ typedef enum { rv_codec_lp, rv_codec_cmop_ss, rv_codec_mop_r, + rv_codec_mop_rr, } rv_codec; /* structures */ @@ -286,5 +287,6 @@ typedef struct { #define rv_fmt_rd2_imm "O\t0,2,(1),i" #define rv_fmt_fli "O\t3,h" #define rv_fmt_mop_r "O.i\t0,1" +#define rv_fmt_mop_rr "O.i\t0,1,2" #endif /* DISAS_RISCV_H */ From 59acf4d4e1a723ebb57d008cdf68a2cc8aa72a65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:38 -0700 Subject: [PATCH 563/627] disas/riscv: Merge all c.mop.n to one pattern Avoid performing arithmetic on rv_op_c_mop_1. Treat the 'n' as an immediate. Create a codec and format to match. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-49-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 9 +-------- disas/riscv.c | 10 +++++++++- disas/riscv.h | 2 ++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index 2100e54475..802a521bca 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -875,14 +875,7 @@ OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(mop_r, "mop.r", rv_codec_mop_r, rv_fmt_mop_r) OP(mop_rr, "mop.rr", rv_codec_mop_rr, rv_fmt_mop_rr) -OP(c_mop_1, "c.mop.1", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_3, "c.mop.3", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_5, "c.mop.5", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_7, "c.mop.7", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_9, "c.mop.9", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_11, "c.mop.11", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_13, "c.mop.13", rv_codec_ci_none, rv_fmt_none) -OP(c_mop_15, "c.mop.15", rv_codec_ci_none, rv_fmt_none) +OP(c_mop, "c.mop", rv_codec_cmop, rv_fmt_cmop) OP(amoswap_b, "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amoadd_b, "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(amoxor_b, "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) diff --git a/disas/riscv.c b/disas/riscv.c index 22104638e1..39235e5bc7 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -643,6 +643,11 @@ static uint32_t operand_lpl(rv_inst inst) return extract32(inst, 12, 20); } +static uint32_t operand_cmop_imm(rv_inst inst) +{ + return extract32(inst, 8, 3) * 2 + 1; +} + static uint32_t operand_mop_r_imm(rv_inst inst) { return (extract32(inst, 30, 1) << 4) | @@ -1027,7 +1032,7 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) (((inst >> 11) & 0b11) == 0b0)) { unsigned int cmop_code = 0; cmop_code = ((inst >> 8) & 0b111); - op = rv_op_c_mop_1 + cmop_code; + op = rv_op_c_mop; if (dec->cfg->ext_zicfiss) { op = (cmop_code == 0) ? rv_op_c_sspush : op; op = (cmop_code == 2) ? rv_op_c_sspopchk : op; @@ -3056,6 +3061,9 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa, case rv_codec_lp: dec->imm = operand_lpl(inst); break; + case rv_codec_cmop: + dec->imm = operand_cmop_imm(inst); + break; case rv_codec_cmop_ss: dec->rd = rv_ireg_zero; dec->rs1 = dec->rs2 = operand_crs1(inst); diff --git a/disas/riscv.h b/disas/riscv.h index 47647f750f..b0269bb709 100644 --- a/disas/riscv.h +++ b/disas/riscv.h @@ -159,6 +159,7 @@ typedef enum { rv_codec_r2_imm2_imm5, rv_codec_fli, rv_codec_lp, + rv_codec_cmop, rv_codec_cmop_ss, rv_codec_mop_r, rv_codec_mop_rr, @@ -286,6 +287,7 @@ typedef struct { #define rv_fmt_rd_rs1_immh_imml_addr "O\t0,(1),i,j" #define rv_fmt_rd2_imm "O\t0,2,(1),i" #define rv_fmt_fli "O\t3,h" +#define rv_fmt_cmop "O.i" #define rv_fmt_mop_r "O.i\t0,1" #define rv_fmt_mop_rr "O.i\t0,1,2" From bf9281b1b0cddda53f00ce28082bb6e7b0d86034 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:39 -0700 Subject: [PATCH 564/627] disas/riscv: Tidy decode of c.mop.n Merge nested if's. Reuse operand_cmop_imm for zicfiss decode. Return pointers directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-50-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 39235e5bc7..197eaa43b1 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -1027,18 +1027,17 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) break; case 2: op = rv_op_c_li; break; case 3: - if (dec->cfg && dec->cfg->ext_zcmop) { - if ((((inst >> 2) & 0b111111) == 0b100000) && - (((inst >> 11) & 0b11) == 0b0)) { - unsigned int cmop_code = 0; - cmop_code = ((inst >> 8) & 0b111); - op = rv_op_c_mop; - if (dec->cfg->ext_zicfiss) { - op = (cmop_code == 0) ? rv_op_c_sspush : op; - op = (cmop_code == 2) ? rv_op_c_sspopchk : op; + if (dec->cfg + && dec->cfg->ext_zcmop + && ((inst >> 2) & 0b111111) == 0b100000 + && ((inst >> 11) & 0b11) == 0) { + if (dec->cfg->ext_zicfiss) { + switch (operand_cmop_imm(inst)) { + case 1: return &rvi_opcode_data[rv_op_c_sspush]; + case 5: return &rvi_opcode_data[rv_op_c_sspopchk]; } - break; } + return &rvi_opcode_data[rv_op_c_mop]; } if (inst & ((1 << 12) | (0x1f << 2))) { switch ((inst >> 7) & 0b11111) { From ef25a26b7dc29ba4b78a70d22a6a806dd4637537 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:40 -0700 Subject: [PATCH 565/627] disas/riscv: Tidy decode of mop.r.n and mop.rr.n Merge nested if's. Reuse operand_mop_{r,rr}_imm for zicfiss decode. Return pointers directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-51-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv.c | 59 +++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/disas/riscv.c b/disas/riscv.c index 197eaa43b1..7ea65ba2e7 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -2555,44 +2555,33 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 3: op = rv_op_csrrc; break; case 4: if (dec->cfg && dec->cfg->ext_zimop) { - int imm_mop5, imm_mop3, reg_num; - if ((extract32(inst, 22, 10) & 0b1011001111) - == 0b1000000111) { - imm_mop5 = deposit32(deposit32(extract32(inst, 20, 2), - 2, 2, - extract32(inst, 26, 2)), - 4, 1, extract32(inst, 30, 1)); - op = rv_op_mop_r; - /* if zicfiss enabled and mop5 is shadow stack */ - if (dec->cfg->ext_zicfiss && - ((imm_mop5 & 0b11100) == 0b11100)) { - /* rs1=0 means ssrdp */ - if ((inst & (0b011111 << 15)) == 0) { - op = rv_op_ssrdp; - } - /* rd=0 means sspopchk */ - reg_num = (inst >> 15) & 0b011111; - if (((inst & (0b011111 << 7)) == 0) && - ((reg_num == 1) || (reg_num == 5))) { - op = rv_op_sspopchk; + if (((inst >> 22) & 0b1011001111) == 0b1000000111) { + if (dec->cfg->ext_zicfiss + && operand_mop_r_imm(inst) == 28) { + switch (operand_rs1(inst)) { + case 0: + return &rvi_opcode_data[rv_op_ssrdp]; + case 1: + case 5: + if (operand_rd(inst) == 0) { + return &rvi_opcode_data[rv_op_sspopchk]; } + } } - } else if ((extract32(inst, 25, 7) & 0b1011001) - == 0b1000001) { - imm_mop3 = deposit32(extract32(inst, 26, 2), - 2, 1, extract32(inst, 30, 1)); - op = rv_op_mop_rr; - /* if zicfiss enabled and mop3 is shadow stack */ - if (dec->cfg->ext_zicfiss && - ((imm_mop3 & 0b111) == 0b111)) { - /* rs1=0 and rd=0 means sspush */ - reg_num = (inst >> 20) & 0b011111; - if (((inst & (0b011111 << 15)) == 0) && - ((inst & (0b011111 << 7)) == 0) && - ((reg_num == 1) || (reg_num == 5))) { - op = rv_op_sspush; - } + return &rvi_opcode_data[rv_op_mop_r]; + } + if (((inst >> 25) & 0b1011001) == 0b1000001) { + if (dec->cfg->ext_zicfiss + && operand_mop_rr_imm(inst) == 7 + && operand_rd(inst) == 0 + && operand_rs1(inst) == 0) { + switch (operand_rs2(inst)) { + case 1: + case 5: + return &rvi_opcode_data[rv_op_sspush]; + } } + return &rvi_opcode_data[rv_op_mop_rr]; } } break; From 4fec981f18fd13adc44d2c58ccfd502612f10dc8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:41 -0700 Subject: [PATCH 566/627] disas/riscv: Split rvi_opcode_data Generate separate objects for OP() instead of collecting in a table. Return pointers to objects directly. Reviewed-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-52-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 94 +- disas/riscv.c | 1981 +++++++++++++++++++++--------------------- 2 files changed, 1048 insertions(+), 1027 deletions(-) diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index 802a521bca..cc939f557f 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -225,51 +225,51 @@ OP(fcvt_q_l, "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) OP(fcvt_q_lu, "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) OP(fmv_x_q, "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1) OP(fmv_q_x, "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1) -OP(c_addi4spn, "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(rv_op_addi)) -OP(c_fld, "c.fld", rv_codec_cl_ld, NULL, DECOMP(rv_op_fld)) -OP(c_lw, "c.lw", rv_codec_cl_lw, NULL, DECOMP(rv_op_lw)) -OP(c_flw, "c.flw", rv_codec_cl_lw, NULL, DECOMP(rv_op_flw)) -OP(c_fsd, "c.fsd", rv_codec_cs_sd, NULL, DECOMP(rv_op_fsd)) -OP(c_sw, "c.sw", rv_codec_cs_sw, NULL, DECOMP(rv_op_sw)) -OP(c_fsw, "c.fsw", rv_codec_cs_sw, NULL, DECOMP(rv_op_fsw)) -OP(c_addi, "c.addi", rv_codec_ci, NULL, DECOMP(rv_op_addi)) -OP(c_jal, "c.jal", rv_codec_cj_jal, NULL, DECOMP(rv_op_jal)) -OP(c_li, "c.li", rv_codec_ci_li, NULL, DECOMP(rv_op_addi)) -OP(c_addi16sp, "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(rv_op_addi)) -OP(c_lui, "c.lui", rv_codec_ci_lui, NULL, DECOMP(rv_op_lui)) -OP(c_srli, "c.srli", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srli)) -OP(c_srai, "c.srai", rv_codec_cb_sh6, NULL, DECOMP(rv_op_srai)) -OP(c_andi, "c.andi", rv_codec_cb_imm, NULL, DECOMP(rv_op_andi)) -OP(c_sub, "c.sub", rv_codec_cs, NULL, DECOMP(rv_op_sub)) -OP(c_xor, "c.xor", rv_codec_cs, NULL, DECOMP(rv_op_xor)) -OP(c_or, "c.or", rv_codec_cs, NULL, DECOMP(rv_op_or)) -OP(c_and, "c.and", rv_codec_cs, NULL, DECOMP(rv_op_and)) -OP(c_subw, "c.subw", rv_codec_cs, NULL, DECOMP(rv_op_subw)) -OP(c_addw, "c.addw", rv_codec_cs, NULL, DECOMP(rv_op_addw)) -OP(c_j, "c.j", rv_codec_cj, NULL, DECOMP(rv_op_j)) -OP(c_beqz, "c.beqz", rv_codec_cb, NULL, DECOMP(rv_op_beqz)) -OP(c_bnez, "c.bnez", rv_codec_cb, NULL, DECOMP(rv_op_bnez)) -OP(c_slli, "c.slli", rv_codec_ci_sh6, NULL, DECOMP(rv_op_slli)) -OP(c_fldsp, "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_fld)) -OP(c_lwsp, "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_lw)) -OP(c_flwsp, "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(rv_op_flw)) -OP(c_jr, "c.jr", rv_codec_cr_jr, NULL, DECOMP(rv_op_jr)) -OP(c_mv, "c.mv", rv_codec_cr_mv, NULL, DECOMP(rv_op_mv)) -OP(c_ebreak, "c.ebreak", rv_codec_ci_none, NULL, DECOMP(rv_op_ebreak)) -OP(c_jalr, "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(rv_op_jalr)) -OP(c_add, "c.add", rv_codec_cr, NULL, DECOMP(rv_op_add)) -OP(c_fsdsp, "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_fsd)) -OP(c_swsp, "c.swsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_sw)) -OP(c_fswsp, "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(rv_op_fsw)) -OP(c_ld, "c.ld", rv_codec_cl_ld, NULL, DECOMP(rv_op_ld)) -OP(c_sd, "c.sd", rv_codec_cs_sd, NULL, DECOMP(rv_op_sd)) -OP(c_addiw, "c.addiw", rv_codec_ci, NULL, DECOMP(rv_op_addiw)) -OP(c_ldsp, "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(rv_op_ld)) -OP(c_sdsp, "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(rv_op_sd)) -OP(c_lq, "c.lq", rv_codec_cl_lq, NULL, DECOMP(rv_op_lq)) -OP(c_sq, "c.sq", rv_codec_cs_sq, NULL, DECOMP(rv_op_sq)) -OP(c_lqsp, "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(rv_op_lq)) -OP(c_sqsp, "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(rv_op_sq)) +OP(c_addi4spn, "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(op_addi)) +OP(c_fld, "c.fld", rv_codec_cl_ld, NULL, DECOMP(op_fld)) +OP(c_lw, "c.lw", rv_codec_cl_lw, NULL, DECOMP(op_lw)) +OP(c_flw, "c.flw", rv_codec_cl_lw, NULL, DECOMP(op_flw)) +OP(c_fsd, "c.fsd", rv_codec_cs_sd, NULL, DECOMP(op_fsd)) +OP(c_sw, "c.sw", rv_codec_cs_sw, NULL, DECOMP(op_sw)) +OP(c_fsw, "c.fsw", rv_codec_cs_sw, NULL, DECOMP(op_fsw)) +OP(c_addi, "c.addi", rv_codec_ci, NULL, DECOMP(op_addi)) +OP(c_jal, "c.jal", rv_codec_cj_jal, NULL, DECOMP(op_jal)) +OP(c_li, "c.li", rv_codec_ci_li, NULL, DECOMP(op_addi)) +OP(c_addi16sp, "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(op_addi)) +OP(c_lui, "c.lui", rv_codec_ci_lui, NULL, DECOMP(op_lui)) +OP(c_srli, "c.srli", rv_codec_cb_sh6, NULL, DECOMP(op_srli)) +OP(c_srai, "c.srai", rv_codec_cb_sh6, NULL, DECOMP(op_srai)) +OP(c_andi, "c.andi", rv_codec_cb_imm, NULL, DECOMP(op_andi)) +OP(c_sub, "c.sub", rv_codec_cs, NULL, DECOMP(op_sub)) +OP(c_xor, "c.xor", rv_codec_cs, NULL, DECOMP(op_xor)) +OP(c_or, "c.or", rv_codec_cs, NULL, DECOMP(op_or)) +OP(c_and, "c.and", rv_codec_cs, NULL, DECOMP(op_and)) +OP(c_subw, "c.subw", rv_codec_cs, NULL, DECOMP(op_subw)) +OP(c_addw, "c.addw", rv_codec_cs, NULL, DECOMP(op_addw)) +OP(c_j, "c.j", rv_codec_cj, NULL, DECOMP(op_j)) +OP(c_beqz, "c.beqz", rv_codec_cb, NULL, DECOMP(op_beqz)) +OP(c_bnez, "c.bnez", rv_codec_cb, NULL, DECOMP(op_bnez)) +OP(c_slli, "c.slli", rv_codec_ci_sh6, NULL, DECOMP(op_slli)) +OP(c_fldsp, "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_fld)) +OP(c_lwsp, "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_lw)) +OP(c_flwsp, "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_flw)) +OP(c_jr, "c.jr", rv_codec_cr_jr, NULL, DECOMP(op_jr)) +OP(c_mv, "c.mv", rv_codec_cr_mv, NULL, DECOMP(op_mv)) +OP(c_ebreak, "c.ebreak", rv_codec_ci_none, NULL, DECOMP(op_ebreak)) +OP(c_jalr, "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(op_jalr)) +OP(c_add, "c.add", rv_codec_cr, NULL, DECOMP(op_add)) +OP(c_fsdsp, "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(op_fsd)) +OP(c_swsp, "c.swsp", rv_codec_css_swsp, NULL, DECOMP(op_sw)) +OP(c_fswsp, "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(op_fsw)) +OP(c_ld, "c.ld", rv_codec_cl_ld, NULL, DECOMP(op_ld)) +OP(c_sd, "c.sd", rv_codec_cs_sd, NULL, DECOMP(op_sd)) +OP(c_addiw, "c.addiw", rv_codec_ci, NULL, DECOMP(op_addiw)) +OP(c_ldsp, "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_ld)) +OP(c_sdsp, "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(op_sd)) +OP(c_lq, "c.lq", rv_codec_cl_lq, NULL, DECOMP(op_lq)) +OP(c_sq, "c.sq", rv_codec_cs_sq, NULL, DECOMP(op_sq)) +OP(c_lqsp, "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(op_lq)) +OP(c_sqsp, "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(op_sq)) OP(nop, "nop", rv_codec_illegal, rv_fmt_none) OP(mv, "mv", rv_codec_illegal, rv_fmt_rd_rs1, rvcp_mv) OP(not, "not", rv_codec_illegal, rv_fmt_rd_rs1) @@ -904,8 +904,8 @@ OP(sspopchk, "sspopchk", rv_codec_r, rv_fmt_rs1) OP(ssrdp, "ssrdp", rv_codec_r, rv_fmt_rd) OP(ssamoswap_w, "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(ssamoswap_d, "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(c_sspush, "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspush)) -OP(c_sspopchk, "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(rv_op_sspopchk)) +OP(c_sspush, "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(op_sspush)) +OP(c_sspopchk, "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(op_sspopchk)) OP(cbo_inval, "cbo.inval", rv_codec_r, rv_fmt_rs1) OP(cbo_clean, "cbo.clean", rv_codec_r, rv_fmt_rs1) OP(cbo_flush, "cbo.flush", rv_codec_r, rv_fmt_rs1) diff --git a/disas/riscv.c b/disas/riscv.c index 7ea65ba2e7..b8099cbdf8 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -28,12 +28,6 @@ #include "disas/riscv-xventana.h" #include "disas/riscv-xlrbr.h" -typedef enum { -#define OP(N, ...) rv_op_##N, -#include "riscv-op.c.inc" -#undef OP -} rv_op; - /* register names */ static const char rv_ireg_name_sym[32][5] = { @@ -113,140 +107,143 @@ static const rvc_constraint rvcc_true[] = { rvc_end }; /* pseudo-instruction metadata */ -static const rv_opcode_data rvi_opcode_data[]; +/* Forward declare the all the opcodes so that we may link them. */ +#define OP(N, ...) static const rv_opcode_data op_##N; +#include "riscv-op.c.inc" +#undef OP static const rv_comp_data rvcp_jal[] = { - { &rvi_opcode_data[rv_op_j], rvcc_j }, - { &rvi_opcode_data[rv_op_jal_ra], rvcc_jal_ra }, + { &op_j, rvcc_j }, + { &op_jal_ra, rvcc_jal_ra }, { }, }; static const rv_comp_data rvcp_jalr[] = { - { &rvi_opcode_data[rv_op_jr], rvcc_jr }, - { &rvi_opcode_data[rv_op_jalr_ra], rvcc_jalr_ra }, + { &op_jr, rvcc_jr }, + { &op_jalr_ra, rvcc_jalr_ra }, { }, }; static const rv_comp_data rvcp_jr[] = { - { &rvi_opcode_data[rv_op_ret], rvcc_ret }, + { &op_ret, rvcc_ret }, { }, }; static const rv_comp_data rvcp_beq[] = { - { &rvi_opcode_data[rv_op_beqz], rvcc_beqz }, + { &op_beqz, rvcc_beqz }, { }, }; static const rv_comp_data rvcp_bne[] = { - { &rvi_opcode_data[rv_op_bnez], rvcc_bnez }, + { &op_bnez, rvcc_bnez }, { }, }; static const rv_comp_data rvcp_blt[] = { - { &rvi_opcode_data[rv_op_bltz], rvcc_bltz }, - { &rvi_opcode_data[rv_op_bgtz], rvcc_bgtz }, + { &op_bltz, rvcc_bltz }, + { &op_bgtz, rvcc_bgtz }, { }, }; static const rv_comp_data rvcp_bge[] = { - { &rvi_opcode_data[rv_op_blez], rvcc_blez }, - { &rvi_opcode_data[rv_op_bgez], rvcc_bgez }, + { &op_blez, rvcc_blez }, + { &op_bgez, rvcc_bgez }, { }, }; static const rv_comp_data rvcp_addi[] = { - { &rvi_opcode_data[rv_op_mv], rvcc_mv }, + { &op_mv, rvcc_mv }, { }, }; static const rv_comp_data rvcp_mv[] = { - { &rvi_opcode_data[rv_op_nop], rvcc_nop }, + { &op_nop, rvcc_nop }, { }, }; static const rv_comp_data rvcp_sltiu[] = { - { &rvi_opcode_data[rv_op_seqz], rvcc_seqz }, + { &op_seqz, rvcc_seqz }, { }, }; static const rv_comp_data rvcp_xori[] = { - { &rvi_opcode_data[rv_op_not], rvcc_not }, + { &op_not, rvcc_not }, { }, }; static const rv_comp_data rvcp_sub[] = { - { &rvi_opcode_data[rv_op_neg], rvcc_neg }, + { &op_neg, rvcc_neg }, { }, }; static const rv_comp_data rvcp_slt[] = { - { &rvi_opcode_data[rv_op_sltz], rvcc_sltz }, - { &rvi_opcode_data[rv_op_sgtz], rvcc_sgtz }, + { &op_sltz, rvcc_sltz }, + { &op_sgtz, rvcc_sgtz }, { }, }; static const rv_comp_data rvcp_sltu[] = { - { &rvi_opcode_data[rv_op_snez], rvcc_snez }, + { &op_snez, rvcc_snez }, { }, }; static const rv_comp_data rvcp_addiw[] = { - { &rvi_opcode_data[rv_op_sext_w], rvcc_sext_w }, + { &op_sext_w, rvcc_sext_w }, { }, }; static const rv_comp_data rvcp_subw[] = { - { &rvi_opcode_data[rv_op_negw], rvcc_negw }, + { &op_negw, rvcc_negw }, { }, }; static const rv_comp_data rvcp_fsgnj_s[] = { - { &rvi_opcode_data[rv_op_fmv_s], rvcc_fmv_s }, + { &op_fmv_s, rvcc_fmv_s }, { }, }; static const rv_comp_data rvcp_fsgnjn_s[] = { - { &rvi_opcode_data[rv_op_fneg_s], rvcc_fneg_s }, + { &op_fneg_s, rvcc_fneg_s }, { }, }; static const rv_comp_data rvcp_fsgnjx_s[] = { - { &rvi_opcode_data[rv_op_fabs_s], rvcc_fabs_s }, + { &op_fabs_s, rvcc_fabs_s }, { }, }; static const rv_comp_data rvcp_fsgnj_d[] = { - { &rvi_opcode_data[rv_op_fmv_d], rvcc_fmv_d }, + { &op_fmv_d, rvcc_fmv_d }, { }, }; static const rv_comp_data rvcp_fsgnjn_d[] = { - { &rvi_opcode_data[rv_op_fneg_d], rvcc_fneg_d }, + { &op_fneg_d, rvcc_fneg_d }, { }, }; static const rv_comp_data rvcp_fsgnjx_d[] = { - { &rvi_opcode_data[rv_op_fabs_d], rvcc_fabs_d }, + { &op_fabs_d, rvcc_fabs_d }, { }, }; static const rv_comp_data rvcp_fsgnj_q[] = { - { &rvi_opcode_data[rv_op_fmv_q], rvcc_fmv_q }, + { &op_fmv_q, rvcc_fmv_q }, { }, }; static const rv_comp_data rvcp_fsgnjn_q[] = { - { &rvi_opcode_data[rv_op_fneg_q], rvcc_fneg_q }, + { &op_fneg_q, rvcc_fneg_q }, { }, }; static const rv_comp_data rvcp_fsgnjx_q[] = { - { &rvi_opcode_data[rv_op_fabs_q], rvcc_fabs_q }, + { &op_fabs_q, rvcc_fabs_q }, { }, }; /* Convert compressed insns into normal insns via pseudo expansion. */ -#define DECOMP(X) &(const rv_comp_data){ &rvi_opcode_data[X], rvcc_true } +#define DECOMP(X) &(const rv_comp_data){ &X, rvcc_true } /* operand extractors */ @@ -662,11 +659,9 @@ static uint32_t operand_mop_rr_imm(rv_inst inst) /* instruction metadata */ -static const rv_opcode_data rvi_opcode_data[] = { -#define OP(N, ...) { __VA_ARGS__ }, +#define OP(N, ...) static const rv_opcode_data op_##N = { __VA_ARGS__ }; #include "riscv-op.c.inc" #undef OP -}; /* CSR names */ @@ -953,79 +948,65 @@ static const char *csr_name(int csrno) static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) { rv_inst inst = dec->inst; - rv_opcode op = rv_op_illegal; switch ((inst >> 0) & 0b11) { case 0: switch ((inst >> 13) & 0b111) { case 0: if ((inst >> 5) & 0xff) { - op = rv_op_c_addi4spn; + return &op_c_addi4spn; } break; case 1: if (isa == rv128) { - op = rv_op_c_lq; - } else { - op = rv_op_c_fld; + return &op_c_lq; } - break; - case 2: op = rv_op_c_lw; break; + return &op_c_fld; + case 2: return &op_c_lw; case 3: if (isa == rv32) { - op = rv_op_c_flw; - } else { - op = rv_op_c_ld; + return &op_c_flw; } - break; + return &op_c_ld; case 4: switch ((inst >> 10) & 0b111) { - case 0: op = rv_op_c_lbu; break; + case 0: return &op_c_lbu; case 1: if (((inst >> 6) & 1) == 0) { - op = rv_op_c_lhu; - } else { - op = rv_op_c_lh; + return &op_c_lhu; } - break; - case 2: op = rv_op_c_sb; break; + return &op_c_lh; + case 2: return &op_c_sb; case 3: if (((inst >> 6) & 1) == 0) { - op = rv_op_c_sh; + return &op_c_sh; } break; } break; case 5: if (isa == rv128) { - op = rv_op_c_sq; - } else { - op = rv_op_c_fsd; + return &op_c_sq; } - break; - case 6: op = rv_op_c_sw; break; + return &op_c_fsd; + case 6: return &op_c_sw; case 7: if (isa == rv32) { - op = rv_op_c_fsw; - } else { - op = rv_op_c_sd; + return &op_c_fsw; } - break; + return &op_c_sd; } break; case 1: switch ((inst >> 13) & 0b111) { case 0: - op = rv_op_c_addi; /* or unspecified HINT */ - break; + return &op_c_addi; /* or unspecified HINT */ case 1: if (isa == rv32) { - op = rv_op_c_jal; - } else { - op = rv_op_c_addiw; + return &op_c_jal; } - break; - case 2: op = rv_op_c_li; break; + return &op_c_addiw; + case 2: return &op_c_li; case 3: if (dec->cfg && dec->cfg->ext_zcmop @@ -1033,16 +1014,16 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) && ((inst >> 11) & 0b11) == 0) { if (dec->cfg->ext_zicfiss) { switch (operand_cmop_imm(inst)) { - case 1: return &rvi_opcode_data[rv_op_c_sspush]; - case 5: return &rvi_opcode_data[rv_op_c_sspopchk]; + case 1: return &op_c_sspush; + case 5: return &op_c_sspopchk; } } - return &rvi_opcode_data[rv_op_c_mop]; + return &op_c_mop; } if (inst & ((1 << 12) | (0x1f << 2))) { switch ((inst >> 7) & 0b11111) { - case 2: op = rv_op_c_addi16sp; break; - default: op = rv_op_c_lui; break; + case 2: return &op_c_addi16sp; + default: return &op_c_lui; } } break; @@ -1051,261 +1032,252 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 0: /* For rv32, shamt[5]=1 is designated for custom extensions. */ if (isa != rv32 || (inst & 0x1000) == 0) { - op = rv_op_c_srli; /* or unspecified HINT */ + return &op_c_srli; /* or unspecified HINT */ } break; case 1: /* For rv32, shamt[5]=1 is designated for custom extensions. */ if (isa != rv32 || (inst & 0x1000) == 0) { - op = rv_op_c_srai; /* or unspecified HINT */ + return &op_c_srai; /* or unspecified HINT */ } break; - case 2: op = rv_op_c_andi; break; + case 2: return &op_c_andi; case 3: switch (((inst >> 10) & 0b100) | ((inst >> 5) & 0b011)) { - case 0: op = rv_op_c_sub; break; - case 1: op = rv_op_c_xor; break; - case 2: op = rv_op_c_or; break; - case 3: op = rv_op_c_and; break; + case 0: return &op_c_sub; + case 1: return &op_c_xor; + case 2: return &op_c_or; + case 3: return &op_c_and; case 4: if (isa != rv32) { - op = rv_op_c_subw; + return &op_c_subw; } break; case 5: if (isa != rv32) { - op = rv_op_c_addw; + return &op_c_addw; } break; - case 6: op = rv_op_c_mul; break; + case 6: return &op_c_mul; case 7: switch ((inst >> 2) & 0b111) { - case 0: op = rv_op_c_zext_b; break; - case 1: op = rv_op_c_sext_b; break; - case 2: op = rv_op_c_zext_h; break; - case 3: op = rv_op_c_sext_h; break; - case 4: op = rv_op_c_zext_w; break; - case 5: op = rv_op_c_not; break; + case 0: return &op_c_zext_b; + case 1: return &op_c_sext_b; + case 2: return &op_c_zext_h; + case 3: return &op_c_sext_h; + case 4: return &op_c_zext_w; + case 5: return &op_c_not; } break; } break; } break; - case 5: op = rv_op_c_j; break; - case 6: op = rv_op_c_beqz; break; - case 7: op = rv_op_c_bnez; break; + case 5: return &op_c_j; + case 6: return &op_c_beqz; + case 7: return &op_c_bnez; } break; case 2: switch ((inst >> 13) & 0b111) { case 0: if (isa != rv32 || (inst & 0x1000) == 0) { - op = rv_op_c_slli; /* or unspecified HINT */ + return &op_c_slli; /* or unspecified HINT */ } break; case 1: if (isa == rv128) { - op = rv_op_c_lqsp; - } else { - op = rv_op_c_fldsp; + return &op_c_lqsp; } - break; - case 2: op = rv_op_c_lwsp; break; + return &op_c_fldsp; + case 2: return &op_c_lwsp; case 3: if (isa == rv32) { - op = rv_op_c_flwsp; - } else { - op = rv_op_c_ldsp; + return &op_c_flwsp; } - break; + return &op_c_ldsp; case 4: switch ((inst >> 12) & 0b1) { case 0: switch ((inst >> 2) & 0b11111) { - case 0: op = rv_op_c_jr; break; - default: op = rv_op_c_mv; break; + case 0: return &op_c_jr; + default: return &op_c_mv; } break; case 1: switch ((inst >> 2) & 0b11111) { case 0: switch ((inst >> 7) & 0b11111) { - case 0: op = rv_op_c_ebreak; break; - default: op = rv_op_c_jalr; break; + case 0: return &op_c_ebreak; + default: return &op_c_jalr; } break; - default: op = rv_op_c_add; break; + default: return &op_c_add; } break; } break; case 5: if (isa == rv128) { - op = rv_op_c_sqsp; - } else { - op = rv_op_c_fsdsp; - if (dec->cfg && dec->cfg->ext_zcmp && ((inst >> 12) & 0b01)) { + return &op_c_sqsp; + } + if (dec->cfg) { + if (dec->cfg->ext_zcmp && ((inst >> 12) & 0b01)) { switch ((inst >> 8) & 0b01111) { case 8: if (((inst >> 4) & 0b01111) >= 4) { - op = rv_op_cm_push; + return &op_cm_push; } break; case 10: if (((inst >> 4) & 0b01111) >= 4) { - op = rv_op_cm_pop; + return &op_cm_pop; } break; case 12: if (((inst >> 4) & 0b01111) >= 4) { - op = rv_op_cm_popretz; + return &op_cm_popretz; } break; case 14: if (((inst >> 4) & 0b01111) >= 4) { - op = rv_op_cm_popret; - } - break; - } - } else { - switch ((inst >> 10) & 0b011) { - case 0: - if (dec->cfg && !dec->cfg->ext_zcmt) { - break; - } - if (((inst >> 2) & 0xFF) >= 32) { - op = rv_op_cm_jalt; - } else { - op = rv_op_cm_jt; - } - break; - case 3: - if (dec->cfg && !dec->cfg->ext_zcmp) { - break; - } - switch ((inst >> 5) & 0b011) { - case 1: op = rv_op_cm_mvsa01; break; - case 3: op = rv_op_cm_mva01s; break; + return &op_cm_popret; } break; } } + switch ((inst >> 10) & 0b011) { + case 0: + if (!dec->cfg->ext_zcmt) { + break; + } + if (((inst >> 2) & 0xFF) >= 32) { + return &op_cm_jalt; + } + return &op_cm_jt; + case 3: + if (!dec->cfg->ext_zcmp) { + break; + } + switch ((inst >> 5) & 0b011) { + case 1: return &op_cm_mvsa01; + case 3: return &op_cm_mva01s; + } + break; + } } - break; - case 6: op = rv_op_c_swsp; break; + return &op_c_fsdsp; + case 6: return &op_c_swsp; case 7: if (isa == rv32) { - op = rv_op_c_fswsp; - } else { - op = rv_op_c_sdsp; + return &op_c_fswsp; } - break; + return &op_c_sdsp; } break; case 3: switch ((inst >> 2) & 0b11111) { case 0: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_lb; break; - case 1: op = rv_op_lh; break; - case 2: op = rv_op_lw; break; - case 3: op = rv_op_ld; break; - case 4: op = rv_op_lbu; break; - case 5: op = rv_op_lhu; break; - case 6: op = rv_op_lwu; break; - case 7: op = rv_op_ldu; break; + case 0: return &op_lb; + case 1: return &op_lh; + case 2: return &op_lw; + case 3: return &op_ld; + case 4: return &op_lbu; + case 5: return &op_lhu; + case 6: return &op_lwu; + case 7: return &op_ldu; } break; case 1: switch ((inst >> 12) & 0b111) { case 0: switch ((inst >> 20) & 0b111111111111) { - case 40: op = rv_op_vl1re8_v; break; - case 552: op = rv_op_vl2re8_v; break; - case 1576: op = rv_op_vl4re8_v; break; - case 3624: op = rv_op_vl8re8_v; break; + case 40: return &op_vl1re8_v; + case 552: return &op_vl2re8_v; + case 1576: return &op_vl4re8_v; + case 3624: return &op_vl8re8_v; } switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vle8_v; break; - case 11: op = rv_op_vlm_v; break; - case 16: op = rv_op_vle8ff_v; break; + case 0: return &op_vle8_v; + case 11: return &op_vlm_v; + case 16: return &op_vle8ff_v; } break; - case 1: op = rv_op_vluxei8_v; break; - case 2: op = rv_op_vlse8_v; break; - case 3: op = rv_op_vloxei8_v; break; + case 1: return &op_vluxei8_v; + case 2: return &op_vlse8_v; + case 3: return &op_vloxei8_v; } break; - case 1: op = rv_op_flh; break; - case 2: op = rv_op_flw; break; - case 3: op = rv_op_fld; break; - case 4: op = rv_op_flq; break; + case 1: return &op_flh; + case 2: return &op_flw; + case 3: return &op_fld; + case 4: return &op_flq; case 5: switch ((inst >> 20) & 0b111111111111) { - case 40: op = rv_op_vl1re16_v; break; - case 552: op = rv_op_vl2re16_v; break; - case 1576: op = rv_op_vl4re16_v; break; - case 3624: op = rv_op_vl8re16_v; break; + case 40: return &op_vl1re16_v; + case 552: return &op_vl2re16_v; + case 1576: return &op_vl4re16_v; + case 3624: return &op_vl8re16_v; } switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vle16_v; break; - case 16: op = rv_op_vle16ff_v; break; + case 0: return &op_vle16_v; + case 16: return &op_vle16ff_v; } break; - case 1: op = rv_op_vluxei16_v; break; - case 2: op = rv_op_vlse16_v; break; - case 3: op = rv_op_vloxei16_v; break; + case 1: return &op_vluxei16_v; + case 2: return &op_vlse16_v; + case 3: return &op_vloxei16_v; } break; case 6: switch ((inst >> 20) & 0b111111111111) { - case 40: op = rv_op_vl1re32_v; break; - case 552: op = rv_op_vl2re32_v; break; - case 1576: op = rv_op_vl4re32_v; break; - case 3624: op = rv_op_vl8re32_v; break; + case 40: return &op_vl1re32_v; + case 552: return &op_vl2re32_v; + case 1576: return &op_vl4re32_v; + case 3624: return &op_vl8re32_v; } switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vle32_v; break; - case 16: op = rv_op_vle32ff_v; break; + case 0: return &op_vle32_v; + case 16: return &op_vle32ff_v; } break; - case 1: op = rv_op_vluxei32_v; break; - case 2: op = rv_op_vlse32_v; break; - case 3: op = rv_op_vloxei32_v; break; + case 1: return &op_vluxei32_v; + case 2: return &op_vlse32_v; + case 3: return &op_vloxei32_v; } break; case 7: switch ((inst >> 20) & 0b111111111111) { - case 40: op = rv_op_vl1re64_v; break; - case 552: op = rv_op_vl2re64_v; break; - case 1576: op = rv_op_vl4re64_v; break; - case 3624: op = rv_op_vl8re64_v; break; + case 40: return &op_vl1re64_v; + case 552: return &op_vl2re64_v; + case 1576: return &op_vl4re64_v; + case 3624: return &op_vl8re64_v; } switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vle64_v; break; - case 16: op = rv_op_vle64ff_v; break; + case 0: return &op_vle64_v; + case 16: return &op_vle64ff_v; } break; - case 1: op = rv_op_vluxei64_v; break; - case 2: op = rv_op_vlse64_v; break; - case 3: op = rv_op_vloxei64_v; break; + case 1: return &op_vluxei64_v; + case 2: return &op_vlse64_v; + case 3: return &op_vloxei64_v; } break; } break; case 3: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fence; break; - case 1: op = rv_op_fence_i; break; + case 0: return &op_fence; + case 1: return &op_fence_i; case 2: /* * 'lq' shares the "(...) 010 ..... 0001111" opcode space @@ -1320,204 +1292,203 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) * Anything that doesn't match these will default to 'lq'. */ switch ((inst >> 17) & 0b11111) { - case 0: op = rv_op_cbo_inval; break; - case 1: op = rv_op_cbo_clean; break; - case 2: op = rv_op_cbo_flush; break; - case 4: op = rv_op_cbo_zero; break; - default: op = rv_op_lq; break; + case 0: return &op_cbo_inval; + case 1: return &op_cbo_clean; + case 2: return &op_cbo_flush; + case 4: return &op_cbo_zero; + default: return &op_lq; } } break; case 4: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_addi; break; + case 0: return &op_addi; case 1: switch ((inst >> 27) & 0b11111) { - case 0b00000: op = rv_op_slli; break; + case 0b00000: return &op_slli; case 0b00001: switch ((inst >> 20) & 0b1111111) { - case 0b0001111: op = rv_op_zip; break; + case 0b0001111: return &op_zip; } break; case 0b00010: switch ((inst >> 20) & 0b1111111) { - case 0b0000000: op = rv_op_sha256sum0; break; - case 0b0000001: op = rv_op_sha256sum1; break; - case 0b0000010: op = rv_op_sha256sig0; break; - case 0b0000011: op = rv_op_sha256sig1; break; - case 0b0000100: op = rv_op_sha512sum0; break; - case 0b0000101: op = rv_op_sha512sum1; break; - case 0b0000110: op = rv_op_sha512sig0; break; - case 0b0000111: op = rv_op_sha512sig1; break; - case 0b0001000: op = rv_op_sm3p0; break; - case 0b0001001: op = rv_op_sm3p1; break; + case 0b0000000: return &op_sha256sum0; + case 0b0000001: return &op_sha256sum1; + case 0b0000010: return &op_sha256sig0; + case 0b0000011: return &op_sha256sig1; + case 0b0000100: return &op_sha512sum0; + case 0b0000101: return &op_sha512sum1; + case 0b0000110: return &op_sha512sig0; + case 0b0000111: return &op_sha512sig1; + case 0b0001000: return &op_sm3p0; + case 0b0001001: return &op_sm3p1; } break; - case 0b00101: op = rv_op_bseti; break; + case 0b00101: return &op_bseti; case 0b00110: switch ((inst >> 20) & 0b1111111) { - case 0b0000000: op = rv_op_aes64im; break; + case 0b0000000: return &op_aes64im; default: if (((inst >> 24) & 0b0111) == 0b001) { - op = rv_op_aes64ks1i; + return &op_aes64ks1i; } break; } break; - case 0b01001: op = rv_op_bclri; break; - case 0b01101: op = rv_op_binvi; break; + case 0b01001: return &op_bclri; + case 0b01101: return &op_binvi; case 0b01100: switch ((inst >> 20) & 0b1111111) { - case 0b0000000: op = rv_op_clz; break; - case 0b0000001: op = rv_op_ctz; break; - case 0b0000010: op = rv_op_cpop; break; + case 0b0000000: return &op_clz; + case 0b0000001: return &op_ctz; + case 0b0000010: return &op_cpop; /* 0b0000011 */ - case 0b0000100: op = rv_op_sext_b; break; - case 0b0000101: op = rv_op_sext_h; break; + case 0b0000100: return &op_sext_b; + case 0b0000101: return &op_sext_h; } break; } break; - case 2: op = rv_op_slti; break; - case 3: op = rv_op_sltiu; break; - case 4: op = rv_op_xori; break; + case 2: return &op_slti; + case 3: return &op_sltiu; + case 4: return &op_xori; case 5: switch ((inst >> 27) & 0b11111) { - case 0b00000: op = rv_op_srli; break; + case 0b00000: return &op_srli; case 0b00001: switch ((inst >> 20) & 0b1111111) { - case 0b0001111: op = rv_op_unzip; break; + case 0b0001111: return &op_unzip; } break; - case 0b00101: op = rv_op_orc_b; break; - case 0b01000: op = rv_op_srai; break; - case 0b01001: op = rv_op_bexti; break; - case 0b01100: op = rv_op_rori; break; + case 0b00101: return &op_orc_b; + case 0b01000: return &op_srai; + case 0b01001: return &op_bexti; + case 0b01100: return &op_rori; case 0b01101: switch ((inst >> 20) & 0b1111111) { case 0b0011000: if (isa == rv32) { - op = rv_op_rev8; + return &op_rev8; } break; case 0b0111000: if (isa == rv64) { - op = rv_op_rev8; + return &op_rev8; } break; - case 0b0000111: op = rv_op_brev8; break; + case 0b0000111: return &op_brev8; } break; } break; - case 6: op = rv_op_ori; break; - case 7: op = rv_op_andi; break; + case 6: return &op_ori; + case 7: return &op_andi; } break; case 5: - op = rv_op_auipc; if (dec->cfg && dec->cfg->ext_zicfilp && (((inst >> 7) & 0b11111) == 0b00000)) { - op = rv_op_lpad; + return &op_lpad; } - break; + return &op_auipc; case 6: /* OP-IMM-32 */ if (isa == rv32) { break; } switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_addiw; break; + case 0: return &op_addiw; case 1: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_slliw; break; - case 2: op = rv_op_slli_uw; break; + case 0: return &op_slliw; + case 2: return &op_slli_uw; case 24: switch ((inst >> 20) & 0b11111) { - case 0b00000: op = rv_op_clzw; break; - case 0b00001: op = rv_op_ctzw; break; - case 0b00010: op = rv_op_cpopw; break; + case 0b00000: return &op_clzw; + case 0b00001: return &op_ctzw; + case 0b00010: return &op_cpopw; } break; } break; case 5: switch ((inst >> 25) & 0b1111111) { - case 0: op = rv_op_srliw; break; - case 32: op = rv_op_sraiw; break; - case 48: op = rv_op_roriw; break; + case 0: return &op_srliw; + case 32: return &op_sraiw; + case 48: return &op_roriw; } break; } break; case 8: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_sb; break; - case 1: op = rv_op_sh; break; - case 2: op = rv_op_sw; break; - case 3: op = rv_op_sd; break; - case 4: op = rv_op_sq; break; + case 0: return &op_sb; + case 1: return &op_sh; + case 2: return &op_sw; + case 3: return &op_sd; + case 4: return &op_sq; } break; case 9: switch ((inst >> 12) & 0b111) { case 0: switch ((inst >> 20) & 0b111111111111) { - case 40: op = rv_op_vs1r_v; break; - case 552: op = rv_op_vs2r_v; break; - case 1576: op = rv_op_vs4r_v; break; - case 3624: op = rv_op_vs8r_v; break; + case 40: return &op_vs1r_v; + case 552: return &op_vs2r_v; + case 1576: return &op_vs4r_v; + case 3624: return &op_vs8r_v; } switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vse8_v; break; - case 11: op = rv_op_vsm_v; break; + case 0: return &op_vse8_v; + case 11: return &op_vsm_v; } break; - case 1: op = rv_op_vsuxei8_v; break; - case 2: op = rv_op_vsse8_v; break; - case 3: op = rv_op_vsoxei8_v; break; + case 1: return &op_vsuxei8_v; + case 2: return &op_vsse8_v; + case 3: return &op_vsoxei8_v; } break; - case 1: op = rv_op_fsh; break; - case 2: op = rv_op_fsw; break; - case 3: op = rv_op_fsd; break; - case 4: op = rv_op_fsq; break; + case 1: return &op_fsh; + case 2: return &op_fsw; + case 3: return &op_fsd; + case 4: return &op_fsq; case 5: switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vse16_v; break; + case 0: return &op_vse16_v; } break; - case 1: op = rv_op_vsuxei16_v; break; - case 2: op = rv_op_vsse16_v; break; - case 3: op = rv_op_vsoxei16_v; break; + case 1: return &op_vsuxei16_v; + case 2: return &op_vsse16_v; + case 3: return &op_vsoxei16_v; } break; case 6: switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vse32_v; break; + case 0: return &op_vse32_v; } break; - case 1: op = rv_op_vsuxei32_v; break; - case 2: op = rv_op_vsse32_v; break; - case 3: op = rv_op_vsoxei32_v; break; + case 1: return &op_vsuxei32_v; + case 2: return &op_vsse32_v; + case 3: return &op_vsoxei32_v; } break; case 7: switch ((inst >> 26) & 0b111) { case 0: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_vse64_v; break; + case 0: return &op_vse64_v; } break; - case 1: op = rv_op_vsuxei64_v; break; - case 2: op = rv_op_vsse64_v; break; - case 3: op = rv_op_vsoxei64_v; break; + case 1: return &op_vsuxei64_v; + case 2: return &op_vsse64_v; + case 3: return &op_vsoxei64_v; } break; } @@ -1525,153 +1496,150 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) case 11: switch (((inst >> 24) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_amoadd_b; break; - case 1: op = rv_op_amoadd_h; break; - case 2: op = rv_op_amoadd_w; break; - case 3: op = rv_op_amoadd_d; break; - case 4: op = rv_op_amoadd_q; break; - case 8: op = rv_op_amoswap_b; break; - case 9: op = rv_op_amoswap_h; break; - case 10: op = rv_op_amoswap_w; break; - case 11: op = rv_op_amoswap_d; break; - case 12: op = rv_op_amoswap_q; break; + case 0: return &op_amoadd_b; + case 1: return &op_amoadd_h; + case 2: return &op_amoadd_w; + case 3: return &op_amoadd_d; + case 4: return &op_amoadd_q; + case 8: return &op_amoswap_b; + case 9: return &op_amoswap_h; + case 10: return &op_amoswap_w; + case 11: return &op_amoswap_d; + case 12: return &op_amoswap_q; case 18: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_lr_w; break; + case 0: return &op_lr_w; } break; case 19: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_lr_d; break; + case 0: return &op_lr_d; } break; case 20: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_lr_q; break; + case 0: return &op_lr_q; } break; - case 26: op = rv_op_sc_w; break; - case 27: op = rv_op_sc_d; break; - case 28: op = rv_op_sc_q; break; - case 32: op = rv_op_amoxor_b; break; - case 33: op = rv_op_amoxor_h; break; - case 34: op = rv_op_amoxor_w; break; - case 35: op = rv_op_amoxor_d; break; - case 36: op = rv_op_amoxor_q; break; - case 40: op = rv_op_amocas_b; break; - case 41: op = rv_op_amocas_h; break; - case 42: op = rv_op_amocas_w; break; - case 43: op = rv_op_amocas_d; break; - case 44: op = rv_op_amocas_q; break; - case 64: op = rv_op_amoor_b; break; - case 65: op = rv_op_amoor_h; break; - case 66: op = rv_op_amoor_w; break; - case 67: op = rv_op_amoor_d; break; - case 68: op = rv_op_amoor_q; break; - case 74: op = rv_op_ssamoswap_w; break; - case 75: op = rv_op_ssamoswap_d; break; - case 96: op = rv_op_amoand_b; break; - case 97: op = rv_op_amoand_h; break; - case 98: op = rv_op_amoand_w; break; - case 99: op = rv_op_amoand_d; break; - case 100: op = rv_op_amoand_q; break; - case 128: op = rv_op_amomin_b; break; - case 129: op = rv_op_amomin_h; break; - case 130: op = rv_op_amomin_w; break; - case 131: op = rv_op_amomin_d; break; - case 132: op = rv_op_amomin_q; break; - case 160: op = rv_op_amomax_b; break; - case 161: op = rv_op_amomax_h; break; - case 162: op = rv_op_amomax_w; break; - case 163: op = rv_op_amomax_d; break; - case 164: op = rv_op_amomax_q; break; - case 192: op = rv_op_amominu_b; break; - case 193: op = rv_op_amominu_h; break; - case 194: op = rv_op_amominu_w; break; - case 195: op = rv_op_amominu_d; break; - case 196: op = rv_op_amominu_q; break; - case 224: op = rv_op_amomaxu_b; break; - case 225: op = rv_op_amomaxu_h; break; - case 226: op = rv_op_amomaxu_w; break; - case 227: op = rv_op_amomaxu_d; break; - case 228: op = rv_op_amomaxu_q; break; + case 26: return &op_sc_w; + case 27: return &op_sc_d; + case 28: return &op_sc_q; + case 32: return &op_amoxor_b; + case 33: return &op_amoxor_h; + case 34: return &op_amoxor_w; + case 35: return &op_amoxor_d; + case 36: return &op_amoxor_q; + case 40: return &op_amocas_b; + case 41: return &op_amocas_h; + case 42: return &op_amocas_w; + case 43: return &op_amocas_d; + case 44: return &op_amocas_q; + case 64: return &op_amoor_b; + case 65: return &op_amoor_h; + case 66: return &op_amoor_w; + case 67: return &op_amoor_d; + case 68: return &op_amoor_q; + case 74: return &op_ssamoswap_w; + case 75: return &op_ssamoswap_d; + case 96: return &op_amoand_b; + case 97: return &op_amoand_h; + case 98: return &op_amoand_w; + case 99: return &op_amoand_d; + case 100: return &op_amoand_q; + case 128: return &op_amomin_b; + case 129: return &op_amomin_h; + case 130: return &op_amomin_w; + case 131: return &op_amomin_d; + case 132: return &op_amomin_q; + case 160: return &op_amomax_b; + case 161: return &op_amomax_h; + case 162: return &op_amomax_w; + case 163: return &op_amomax_d; + case 164: return &op_amomax_q; + case 192: return &op_amominu_b; + case 193: return &op_amominu_h; + case 194: return &op_amominu_w; + case 195: return &op_amominu_d; + case 196: return &op_amominu_q; + case 224: return &op_amomaxu_b; + case 225: return &op_amomaxu_h; + case 226: return &op_amomaxu_w; + case 227: return &op_amomaxu_d; + case 228: return &op_amomaxu_q; } break; case 12: switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) { - case 0: op = rv_op_add; break; - case 1: op = rv_op_sll; break; - case 2: op = rv_op_slt; break; - case 3: op = rv_op_sltu; break; - case 4: op = rv_op_xor; break; - case 5: op = rv_op_srl; break; - case 6: op = rv_op_or; break; - case 7: op = rv_op_and; break; - case 8: op = rv_op_mul; break; - case 9: op = rv_op_mulh; break; - case 10: op = rv_op_mulhsu; break; - case 11: op = rv_op_mulhu; break; - case 12: op = rv_op_div; break; - case 13: op = rv_op_divu; break; - case 14: op = rv_op_rem; break; - case 15: op = rv_op_remu; break; + case 0: return &op_add; + case 1: return &op_sll; + case 2: return &op_slt; + case 3: return &op_sltu; + case 4: return &op_xor; + case 5: return &op_srl; + case 6: return &op_or; + case 7: return &op_and; + case 8: return &op_mul; + case 9: return &op_mulh; + case 10: return &op_mulhsu; + case 11: return &op_mulhu; + case 12: return &op_div; + case 13: return &op_divu; + case 14: return &op_rem; + case 15: return &op_remu; case 36: if (isa == rv32 && !((inst >> 20) & 0b11111)) { - op = rv_op_zext_h; - } else { - op = rv_op_pack; + return &op_zext_h; } - break; - case 39: op = rv_op_packh; break; - - case 41: op = rv_op_clmul; break; - case 42: op = rv_op_clmulr; break; - case 43: op = rv_op_clmulh; break; - case 44: op = rv_op_min; break; - case 45: op = rv_op_minu; break; - case 46: op = rv_op_max; break; - case 47: op = rv_op_maxu; break; - case 075: op = rv_op_czero_eqz; break; - case 077: op = rv_op_czero_nez; break; - case 130: op = rv_op_sh1add; break; - case 132: op = rv_op_sh2add; break; - case 134: op = rv_op_sh3add; break; - case 161: op = rv_op_bset; break; - case 162: op = rv_op_xperm4; break; - case 164: op = rv_op_xperm8; break; - case 200: op = rv_op_aes64es; break; - case 216: op = rv_op_aes64esm; break; - case 232: op = rv_op_aes64ds; break; - case 248: op = rv_op_aes64dsm; break; - case 256: op = rv_op_sub; break; - case 260: op = rv_op_xnor; break; - case 261: op = rv_op_sra; break; - case 262: op = rv_op_orn; break; - case 263: op = rv_op_andn; break; - case 289: op = rv_op_bclr; break; - case 293: op = rv_op_bext; break; - case 320: op = rv_op_sha512sum0r; break; - case 328: op = rv_op_sha512sum1r; break; - case 336: op = rv_op_sha512sig0l; break; - case 344: op = rv_op_sha512sig1l; break; - case 368: op = rv_op_sha512sig0h; break; - case 376: op = rv_op_sha512sig1h; break; - case 385: op = rv_op_rol; break; - case 389: op = rv_op_ror; break; - case 417: op = rv_op_binv; break; - case 504: op = rv_op_aes64ks2; break; + return &op_pack; + case 39: return &op_packh; + case 41: return &op_clmul; + case 42: return &op_clmulr; + case 43: return &op_clmulh; + case 44: return &op_min; + case 45: return &op_minu; + case 46: return &op_max; + case 47: return &op_maxu; + case 075: return &op_czero_eqz; + case 077: return &op_czero_nez; + case 130: return &op_sh1add; + case 132: return &op_sh2add; + case 134: return &op_sh3add; + case 161: return &op_bset; + case 162: return &op_xperm4; + case 164: return &op_xperm8; + case 200: return &op_aes64es; + case 216: return &op_aes64esm; + case 232: return &op_aes64ds; + case 248: return &op_aes64dsm; + case 256: return &op_sub; + case 260: return &op_xnor; + case 261: return &op_sra; + case 262: return &op_orn; + case 263: return &op_andn; + case 289: return &op_bclr; + case 293: return &op_bext; + case 320: return &op_sha512sum0r; + case 328: return &op_sha512sum1r; + case 336: return &op_sha512sig0l; + case 344: return &op_sha512sig1l; + case 368: return &op_sha512sig0h; + case 376: return &op_sha512sig1h; + case 385: return &op_rol; + case 389: return &op_ror; + case 417: return &op_binv; + case 504: return &op_aes64ks2; } switch ((inst >> 25) & 0b0011111) { - case 17: op = rv_op_aes32esi; break; - case 19: op = rv_op_aes32esmi; break; - case 21: op = rv_op_aes32dsi; break; - case 23: op = rv_op_aes32dsmi; break; - case 24: op = rv_op_sm4ed; break; - case 26: op = rv_op_sm4ks; break; + case 17: return &op_aes32esi; + case 19: return &op_aes32esmi; + case 21: return &op_aes32dsi; + case 23: return &op_aes32dsmi; + case 24: return &op_sm4ed; + case 26: return &op_sm4ks; } break; - case 13: op = rv_op_lui; break; + case 13: return &op_lui; case 14: /* OP-32 */ if (isa == rv32) { @@ -1679,317 +1647,317 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) } switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) { - case 0: op = rv_op_addw; break; - case 1: op = rv_op_sllw; break; - case 5: op = rv_op_srlw; break; - case 8: op = rv_op_mulw; break; - case 12: op = rv_op_divw; break; - case 13: op = rv_op_divuw; break; - case 14: op = rv_op_remw; break; - case 15: op = rv_op_remuw; break; - case 32: op = rv_op_add_uw; break; + case 0: return &op_addw; + case 1: return &op_sllw; + case 5: return &op_srlw; + case 8: return &op_mulw; + case 12: return &op_divw; + case 13: return &op_divuw; + case 14: return &op_remw; + case 15: return &op_remuw; + case 32: return &op_add_uw; case 36: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_zext_h; break; - default: op = rv_op_packw; break; + case 0: return &op_zext_h; + default: return &op_packw; } break; - case 130: op = rv_op_sh1add_uw; break; - case 132: op = rv_op_sh2add_uw; break; - case 134: op = rv_op_sh3add_uw; break; - case 256: op = rv_op_subw; break; - case 261: op = rv_op_sraw; break; - case 385: op = rv_op_rolw; break; - case 389: op = rv_op_rorw; break; + case 130: return &op_sh1add_uw; + case 132: return &op_sh2add_uw; + case 134: return &op_sh3add_uw; + case 256: return &op_subw; + case 261: return &op_sraw; + case 385: return &op_rolw; + case 389: return &op_rorw; } break; case 16: switch ((inst >> 25) & 0b11) { - case 0: op = rv_op_fmadd_s; break; - case 1: op = rv_op_fmadd_d; break; - case 3: op = rv_op_fmadd_q; break; + case 0: return &op_fmadd_s; + case 1: return &op_fmadd_d; + case 3: return &op_fmadd_q; } break; case 17: switch ((inst >> 25) & 0b11) { - case 0: op = rv_op_fmsub_s; break; - case 1: op = rv_op_fmsub_d; break; - case 3: op = rv_op_fmsub_q; break; + case 0: return &op_fmsub_s; + case 1: return &op_fmsub_d; + case 3: return &op_fmsub_q; } break; case 18: switch ((inst >> 25) & 0b11) { - case 0: op = rv_op_fnmsub_s; break; - case 1: op = rv_op_fnmsub_d; break; - case 3: op = rv_op_fnmsub_q; break; + case 0: return &op_fnmsub_s; + case 1: return &op_fnmsub_d; + case 3: return &op_fnmsub_q; } break; case 19: switch ((inst >> 25) & 0b11) { - case 0: op = rv_op_fnmadd_s; break; - case 1: op = rv_op_fnmadd_d; break; - case 3: op = rv_op_fnmadd_q; break; + case 0: return &op_fnmadd_s; + case 1: return &op_fnmadd_d; + case 3: return &op_fnmadd_q; } break; case 20: switch ((inst >> 25) & 0b1111111) { - case 0: op = rv_op_fadd_s; break; - case 1: op = rv_op_fadd_d; break; - case 3: op = rv_op_fadd_q; break; - case 4: op = rv_op_fsub_s; break; - case 5: op = rv_op_fsub_d; break; - case 7: op = rv_op_fsub_q; break; - case 8: op = rv_op_fmul_s; break; - case 9: op = rv_op_fmul_d; break; - case 11: op = rv_op_fmul_q; break; - case 12: op = rv_op_fdiv_s; break; - case 13: op = rv_op_fdiv_d; break; - case 15: op = rv_op_fdiv_q; break; + case 0: return &op_fadd_s; + case 1: return &op_fadd_d; + case 3: return &op_fadd_q; + case 4: return &op_fsub_s; + case 5: return &op_fsub_d; + case 7: return &op_fsub_q; + case 8: return &op_fmul_s; + case 9: return &op_fmul_d; + case 11: return &op_fmul_q; + case 12: return &op_fdiv_s; + case 13: return &op_fdiv_d; + case 15: return &op_fdiv_q; case 16: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fsgnj_s; break; - case 1: op = rv_op_fsgnjn_s; break; - case 2: op = rv_op_fsgnjx_s; break; + case 0: return &op_fsgnj_s; + case 1: return &op_fsgnjn_s; + case 2: return &op_fsgnjx_s; } break; case 17: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fsgnj_d; break; - case 1: op = rv_op_fsgnjn_d; break; - case 2: op = rv_op_fsgnjx_d; break; + case 0: return &op_fsgnj_d; + case 1: return &op_fsgnjn_d; + case 2: return &op_fsgnjx_d; } break; case 19: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fsgnj_q; break; - case 1: op = rv_op_fsgnjn_q; break; - case 2: op = rv_op_fsgnjx_q; break; + case 0: return &op_fsgnj_q; + case 1: return &op_fsgnjn_q; + case 2: return &op_fsgnjx_q; } break; case 20: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fmin_s; break; - case 1: op = rv_op_fmax_s; break; - case 2: op = rv_op_fminm_s; break; - case 3: op = rv_op_fmaxm_s; break; + case 0: return &op_fmin_s; + case 1: return &op_fmax_s; + case 2: return &op_fminm_s; + case 3: return &op_fmaxm_s; } break; case 21: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fmin_d; break; - case 1: op = rv_op_fmax_d; break; - case 2: op = rv_op_fminm_d; break; - case 3: op = rv_op_fmaxm_d; break; + case 0: return &op_fmin_d; + case 1: return &op_fmax_d; + case 2: return &op_fminm_d; + case 3: return &op_fmaxm_d; } break; case 22: switch (((inst >> 12) & 0b111)) { - case 2: op = rv_op_fminm_h; break; - case 3: op = rv_op_fmaxm_h; break; + case 2: return &op_fminm_h; + case 3: return &op_fmaxm_h; } break; case 23: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fmin_q; break; - case 1: op = rv_op_fmax_q; break; - case 2: op = rv_op_fminm_q; break; - case 3: op = rv_op_fmaxm_q; break; + case 0: return &op_fmin_q; + case 1: return &op_fmax_q; + case 2: return &op_fminm_q; + case 3: return &op_fmaxm_q; } break; case 32: switch ((inst >> 20) & 0b11111) { - case 1: op = rv_op_fcvt_s_d; break; - case 3: op = rv_op_fcvt_s_q; break; - case 4: op = rv_op_fround_s; break; - case 5: op = rv_op_froundnx_s; break; - case 6: op = rv_op_fcvt_s_bf16; break; + case 1: return &op_fcvt_s_d; + case 3: return &op_fcvt_s_q; + case 4: return &op_fround_s; + case 5: return &op_froundnx_s; + case 6: return &op_fcvt_s_bf16; } break; case 33: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_d_s; break; - case 3: op = rv_op_fcvt_d_q; break; - case 4: op = rv_op_fround_d; break; - case 5: op = rv_op_froundnx_d; break; + case 0: return &op_fcvt_d_s; + case 3: return &op_fcvt_d_q; + case 4: return &op_fround_d; + case 5: return &op_froundnx_d; } break; case 34: switch (((inst >> 20) & 0b11111)) { - case 4: op = rv_op_fround_h; break; - case 5: op = rv_op_froundnx_h; break; - case 8: op = rv_op_fcvt_bf16_s; break; + case 4: return &op_fround_h; + case 5: return &op_froundnx_h; + case 8: return &op_fcvt_bf16_s; } break; case 35: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_q_s; break; - case 1: op = rv_op_fcvt_q_d; break; - case 4: op = rv_op_fround_q; break; - case 5: op = rv_op_froundnx_q; break; + case 0: return &op_fcvt_q_s; + case 1: return &op_fcvt_q_d; + case 4: return &op_fround_q; + case 5: return &op_froundnx_q; } break; case 44: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fsqrt_s; break; + case 0: return &op_fsqrt_s; } break; case 45: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fsqrt_d; break; + case 0: return &op_fsqrt_d; } break; case 47: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fsqrt_q; break; + case 0: return &op_fsqrt_q; } break; case 80: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fle_s; break; - case 1: op = rv_op_flt_s; break; - case 2: op = rv_op_feq_s; break; - case 4: op = rv_op_fleq_s; break; - case 5: op = rv_op_fltq_s; break; + case 0: return &op_fle_s; + case 1: return &op_flt_s; + case 2: return &op_feq_s; + case 4: return &op_fleq_s; + case 5: return &op_fltq_s; } break; case 81: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fle_d; break; - case 1: op = rv_op_flt_d; break; - case 2: op = rv_op_feq_d; break; - case 4: op = rv_op_fleq_d; break; - case 5: op = rv_op_fltq_d; break; + case 0: return &op_fle_d; + case 1: return &op_flt_d; + case 2: return &op_feq_d; + case 4: return &op_fleq_d; + case 5: return &op_fltq_d; } break; case 82: switch (((inst >> 12) & 0b111)) { - case 4: op = rv_op_fleq_h; break; - case 5: op = rv_op_fltq_h; break; + case 4: return &op_fleq_h; + case 5: return &op_fltq_h; } break; case 83: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_fle_q; break; - case 1: op = rv_op_flt_q; break; - case 2: op = rv_op_feq_q; break; - case 4: op = rv_op_fleq_q; break; - case 5: op = rv_op_fltq_q; break; + case 0: return &op_fle_q; + case 1: return &op_flt_q; + case 2: return &op_feq_q; + case 4: return &op_fleq_q; + case 5: return &op_fltq_q; } break; case 89: switch (((inst >> 12) & 0b111)) { - case 0: op = rv_op_fmvp_d_x; break; + case 0: return &op_fmvp_d_x; } break; case 91: switch (((inst >> 12) & 0b111)) { - case 0: op = rv_op_fmvp_q_x; break; + case 0: return &op_fmvp_q_x; } break; case 96: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_w_s; break; - case 1: op = rv_op_fcvt_wu_s; break; - case 2: op = rv_op_fcvt_l_s; break; - case 3: op = rv_op_fcvt_lu_s; break; + case 0: return &op_fcvt_w_s; + case 1: return &op_fcvt_wu_s; + case 2: return &op_fcvt_l_s; + case 3: return &op_fcvt_lu_s; } break; case 97: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_w_d; break; - case 1: op = rv_op_fcvt_wu_d; break; - case 2: op = rv_op_fcvt_l_d; break; - case 3: op = rv_op_fcvt_lu_d; break; - case 8: op = rv_op_fcvtmod_w_d; break; + case 0: return &op_fcvt_w_d; + case 1: return &op_fcvt_wu_d; + case 2: return &op_fcvt_l_d; + case 3: return &op_fcvt_lu_d; + case 8: return &op_fcvtmod_w_d; } break; case 99: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_w_q; break; - case 1: op = rv_op_fcvt_wu_q; break; - case 2: op = rv_op_fcvt_l_q; break; - case 3: op = rv_op_fcvt_lu_q; break; + case 0: return &op_fcvt_w_q; + case 1: return &op_fcvt_wu_q; + case 2: return &op_fcvt_l_q; + case 3: return &op_fcvt_lu_q; } break; case 104: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_s_w; break; - case 1: op = rv_op_fcvt_s_wu; break; - case 2: op = rv_op_fcvt_s_l; break; - case 3: op = rv_op_fcvt_s_lu; break; + case 0: return &op_fcvt_s_w; + case 1: return &op_fcvt_s_wu; + case 2: return &op_fcvt_s_l; + case 3: return &op_fcvt_s_lu; } break; case 105: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_d_w; break; - case 1: op = rv_op_fcvt_d_wu; break; - case 2: op = rv_op_fcvt_d_l; break; - case 3: op = rv_op_fcvt_d_lu; break; + case 0: return &op_fcvt_d_w; + case 1: return &op_fcvt_d_wu; + case 2: return &op_fcvt_d_l; + case 3: return &op_fcvt_d_lu; } break; case 107: switch ((inst >> 20) & 0b11111) { - case 0: op = rv_op_fcvt_q_w; break; - case 1: op = rv_op_fcvt_q_wu; break; - case 2: op = rv_op_fcvt_q_l; break; - case 3: op = rv_op_fcvt_q_lu; break; + case 0: return &op_fcvt_q_w; + case 1: return &op_fcvt_q_wu; + case 2: return &op_fcvt_q_l; + case 3: return &op_fcvt_q_lu; } break; case 112: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_x_s; break; - case 1: op = rv_op_fclass_s; break; + case 0: return &op_fmv_x_s; + case 1: return &op_fclass_s; } break; case 113: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_x_d; break; - case 1: op = rv_op_fclass_d; break; - case 8: op = rv_op_fmvh_x_d; break; + case 0: return &op_fmv_x_d; + case 1: return &op_fclass_d; + case 8: return &op_fmvh_x_d; } break; case 114: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_x_h; break; + case 0: return &op_fmv_x_h; } break; case 115: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_x_q; break; - case 1: op = rv_op_fclass_q; break; - case 8: op = rv_op_fmvh_x_q; break; + case 0: return &op_fmv_x_q; + case 1: return &op_fclass_q; + case 8: return &op_fmvh_x_q; } break; case 120: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_s_x; break; - case 8: op = rv_op_fli_s; break; + case 0: return &op_fmv_s_x; + case 8: return &op_fli_s; } break; case 121: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_d_x; break; - case 8: op = rv_op_fli_d; break; + case 0: return &op_fmv_d_x; + case 8: return &op_fli_d; } break; case 122: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_h_x; break; - case 8: op = rv_op_fli_h; break; + case 0: return &op_fmv_h_x; + case 8: return &op_fli_h; } break; case 123: switch (((inst >> 17) & 0b11111000) | ((inst >> 12) & 0b00000111)) { - case 0: op = rv_op_fmv_q_x; break; - case 8: op = rv_op_fli_q; break; + case 0: return &op_fmv_q_x; + case 8: return &op_fli_q; } break; } @@ -1998,484 +1966,537 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) switch ((inst >> 12) & 0b111) { case 0: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vadd_vv; break; - case 1: op = rv_op_vandn_vv; break; - case 2: op = rv_op_vsub_vv; break; - case 4: op = rv_op_vminu_vv; break; - case 5: op = rv_op_vmin_vv; break; - case 6: op = rv_op_vmaxu_vv; break; - case 7: op = rv_op_vmax_vv; break; - case 9: op = rv_op_vand_vv; break; - case 10: op = rv_op_vor_vv; break; - case 11: op = rv_op_vxor_vv; break; - case 12: op = rv_op_vrgather_vv; break; - case 14: op = rv_op_vrgatherei16_vv; break; + case 0: return &op_vadd_vv; + case 1: return &op_vandn_vv; + case 2: return &op_vsub_vv; + case 4: return &op_vminu_vv; + case 5: return &op_vmin_vv; + case 6: return &op_vmaxu_vv; + case 7: return &op_vmax_vv; + case 9: return &op_vand_vv; + case 10: return &op_vor_vv; + case 11: return &op_vxor_vv; + case 12: return &op_vrgather_vv; + case 14: return &op_vrgatherei16_vv; case 16: if (((inst >> 25) & 1) == 0) { - op = rv_op_vadc_vvm; + return &op_vadc_vvm; } break; - case 17: op = rv_op_vmadc_vvm; break; + case 17: return &op_vmadc_vvm; case 18: if (((inst >> 25) & 1) == 0) { - op = rv_op_vsbc_vvm; + return &op_vsbc_vvm; } break; - case 19: op = rv_op_vmsbc_vvm; break; - case 20: op = rv_op_vror_vv; break; - case 21: op = rv_op_vrol_vv; break; + case 19: return &op_vmsbc_vvm; + case 20: return &op_vror_vv; + case 21: return &op_vrol_vv; case 23: - if (((inst >> 20) & 0b111111) == 32) - op = rv_op_vmv_v_v; - else if (((inst >> 25) & 1) == 0) - op = rv_op_vmerge_vvm; + if (((inst >> 20) & 0b111111) == 32) { + return &op_vmv_v_v; + } else if (((inst >> 25) & 1) == 0) { + return &op_vmerge_vvm; + } break; - case 24: op = rv_op_vmseq_vv; break; - case 25: op = rv_op_vmsne_vv; break; - case 26: op = rv_op_vmsltu_vv; break; - case 27: op = rv_op_vmslt_vv; break; - case 28: op = rv_op_vmsleu_vv; break; - case 29: op = rv_op_vmsle_vv; break; - case 32: op = rv_op_vsaddu_vv; break; - case 33: op = rv_op_vsadd_vv; break; - case 34: op = rv_op_vssubu_vv; break; - case 35: op = rv_op_vssub_vv; break; - case 37: op = rv_op_vsll_vv; break; - case 39: op = rv_op_vsmul_vv; break; - case 40: op = rv_op_vsrl_vv; break; - case 41: op = rv_op_vsra_vv; break; - case 42: op = rv_op_vssrl_vv; break; - case 43: op = rv_op_vssra_vv; break; - case 44: op = rv_op_vnsrl_wv; break; - case 45: op = rv_op_vnsra_wv; break; - case 46: op = rv_op_vnclipu_wv; break; - case 47: op = rv_op_vnclip_wv; break; - case 48: op = rv_op_vwredsumu_vs; break; - case 49: op = rv_op_vwredsum_vs; break; - case 53: op = rv_op_vwsll_vv; break; + case 24: return &op_vmseq_vv; + case 25: return &op_vmsne_vv; + case 26: return &op_vmsltu_vv; + case 27: return &op_vmslt_vv; + case 28: return &op_vmsleu_vv; + case 29: return &op_vmsle_vv; + case 32: return &op_vsaddu_vv; + case 33: return &op_vsadd_vv; + case 34: return &op_vssubu_vv; + case 35: return &op_vssub_vv; + case 37: return &op_vsll_vv; + case 39: return &op_vsmul_vv; + case 40: return &op_vsrl_vv; + case 41: return &op_vsra_vv; + case 42: return &op_vssrl_vv; + case 43: return &op_vssra_vv; + case 44: return &op_vnsrl_wv; + case 45: return &op_vnsra_wv; + case 46: return &op_vnclipu_wv; + case 47: return &op_vnclip_wv; + case 48: return &op_vwredsumu_vs; + case 49: return &op_vwredsum_vs; + case 53: return &op_vwsll_vv; } break; case 1: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vfadd_vv; break; - case 1: op = rv_op_vfredusum_vs; break; - case 2: op = rv_op_vfsub_vv; break; - case 3: op = rv_op_vfredosum_vs; break; - case 4: op = rv_op_vfmin_vv; break; - case 5: op = rv_op_vfredmin_vs; break; - case 6: op = rv_op_vfmax_vv; break; - case 7: op = rv_op_vfredmax_vs; break; - case 8: op = rv_op_vfsgnj_vv; break; - case 9: op = rv_op_vfsgnjn_vv; break; - case 10: op = rv_op_vfsgnjx_vv; break; + case 0: return &op_vfadd_vv; + case 1: return &op_vfredusum_vs; + case 2: return &op_vfsub_vv; + case 3: return &op_vfredosum_vs; + case 4: return &op_vfmin_vv; + case 5: return &op_vfredmin_vs; + case 6: return &op_vfmax_vv; + case 7: return &op_vfredmax_vs; + case 8: return &op_vfsgnj_vv; + case 9: return &op_vfsgnjn_vv; + case 10: return &op_vfsgnjx_vv; case 16: switch ((inst >> 15) & 0b11111) { - case 0: if ((inst >> 25) & 1) op = rv_op_vfmv_f_s; break; + case 0: + if ((inst >> 25) & 1) { + return &op_vfmv_f_s; + } } break; case 18: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_vfcvt_xu_f_v; break; - case 1: op = rv_op_vfcvt_x_f_v; break; - case 2: op = rv_op_vfcvt_f_xu_v; break; - case 3: op = rv_op_vfcvt_f_x_v; break; - case 6: op = rv_op_vfcvt_rtz_xu_f_v; break; - case 7: op = rv_op_vfcvt_rtz_x_f_v; break; - case 8: op = rv_op_vfwcvt_xu_f_v; break; - case 9: op = rv_op_vfwcvt_x_f_v; break; - case 10: op = rv_op_vfwcvt_f_xu_v; break; - case 11: op = rv_op_vfwcvt_f_x_v; break; - case 12: op = rv_op_vfwcvt_f_f_v; break; - case 13: op = rv_op_vfwcvtbf16_f_f_v; break; - case 14: op = rv_op_vfwcvt_rtz_xu_f_v; break; - case 15: op = rv_op_vfwcvt_rtz_x_f_v; break; - case 16: op = rv_op_vfncvt_xu_f_w; break; - case 17: op = rv_op_vfncvt_x_f_w; break; - case 18: op = rv_op_vfncvt_f_xu_w; break; - case 19: op = rv_op_vfncvt_f_x_w; break; - case 20: op = rv_op_vfncvt_f_f_w; break; - case 21: op = rv_op_vfncvt_rod_f_f_w; break; - case 22: op = rv_op_vfncvt_rtz_xu_f_w; break; - case 23: op = rv_op_vfncvt_rtz_x_f_w; break; - case 29: op = rv_op_vfncvtbf16_f_f_w; break; + case 0: return &op_vfcvt_xu_f_v; + case 1: return &op_vfcvt_x_f_v; + case 2: return &op_vfcvt_f_xu_v; + case 3: return &op_vfcvt_f_x_v; + case 6: return &op_vfcvt_rtz_xu_f_v; + case 7: return &op_vfcvt_rtz_x_f_v; + case 8: return &op_vfwcvt_xu_f_v; + case 9: return &op_vfwcvt_x_f_v; + case 10: return &op_vfwcvt_f_xu_v; + case 11: return &op_vfwcvt_f_x_v; + case 12: return &op_vfwcvt_f_f_v; + case 13: return &op_vfwcvtbf16_f_f_v; + case 14: return &op_vfwcvt_rtz_xu_f_v; + case 15: return &op_vfwcvt_rtz_x_f_v; + case 16: return &op_vfncvt_xu_f_w; + case 17: return &op_vfncvt_x_f_w; + case 18: return &op_vfncvt_f_xu_w; + case 19: return &op_vfncvt_f_x_w; + case 20: return &op_vfncvt_f_f_w; + case 21: return &op_vfncvt_rod_f_f_w; + case 22: return &op_vfncvt_rtz_xu_f_w; + case 23: return &op_vfncvt_rtz_x_f_w; + case 29: return &op_vfncvtbf16_f_f_w; } break; case 19: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_vfsqrt_v; break; - case 4: op = rv_op_vfrsqrt7_v; break; - case 5: op = rv_op_vfrec7_v; break; - case 16: op = rv_op_vfclass_v; break; + case 0: return &op_vfsqrt_v; + case 4: return &op_vfrsqrt7_v; + case 5: return &op_vfrec7_v; + case 16: return &op_vfclass_v; } break; - case 24: op = rv_op_vmfeq_vv; break; - case 25: op = rv_op_vmfle_vv; break; - case 27: op = rv_op_vmflt_vv; break; - case 28: op = rv_op_vmfne_vv; break; - case 32: op = rv_op_vfdiv_vv; break; - case 36: op = rv_op_vfmul_vv; break; - case 40: op = rv_op_vfmadd_vv; break; - case 41: op = rv_op_vfnmadd_vv; break; - case 42: op = rv_op_vfmsub_vv; break; - case 43: op = rv_op_vfnmsub_vv; break; - case 44: op = rv_op_vfmacc_vv; break; - case 45: op = rv_op_vfnmacc_vv; break; - case 46: op = rv_op_vfmsac_vv; break; - case 47: op = rv_op_vfnmsac_vv; break; - case 48: op = rv_op_vfwadd_vv; break; - case 49: op = rv_op_vfwredusum_vs; break; - case 50: op = rv_op_vfwsub_vv; break; - case 51: op = rv_op_vfwredosum_vs; break; - case 52: op = rv_op_vfwadd_wv; break; - case 54: op = rv_op_vfwsub_wv; break; - case 56: op = rv_op_vfwmul_vv; break; - case 59: op = rv_op_vfwmaccbf16_vv; break; - case 60: op = rv_op_vfwmacc_vv; break; - case 61: op = rv_op_vfwnmacc_vv; break; - case 62: op = rv_op_vfwmsac_vv; break; - case 63: op = rv_op_vfwnmsac_vv; break; + case 24: return &op_vmfeq_vv; + case 25: return &op_vmfle_vv; + case 27: return &op_vmflt_vv; + case 28: return &op_vmfne_vv; + case 32: return &op_vfdiv_vv; + case 36: return &op_vfmul_vv; + case 40: return &op_vfmadd_vv; + case 41: return &op_vfnmadd_vv; + case 42: return &op_vfmsub_vv; + case 43: return &op_vfnmsub_vv; + case 44: return &op_vfmacc_vv; + case 45: return &op_vfnmacc_vv; + case 46: return &op_vfmsac_vv; + case 47: return &op_vfnmsac_vv; + case 48: return &op_vfwadd_vv; + case 49: return &op_vfwredusum_vs; + case 50: return &op_vfwsub_vv; + case 51: return &op_vfwredosum_vs; + case 52: return &op_vfwadd_wv; + case 54: return &op_vfwsub_wv; + case 56: return &op_vfwmul_vv; + case 59: return &op_vfwmaccbf16_vv; + case 60: return &op_vfwmacc_vv; + case 61: return &op_vfwnmacc_vv; + case 62: return &op_vfwmsac_vv; + case 63: return &op_vfwnmsac_vv; } break; case 2: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vredsum_vs; break; - case 1: op = rv_op_vredand_vs; break; - case 2: op = rv_op_vredor_vs; break; - case 3: op = rv_op_vredxor_vs; break; - case 4: op = rv_op_vredminu_vs; break; - case 5: op = rv_op_vredmin_vs; break; - case 6: op = rv_op_vredmaxu_vs; break; - case 7: op = rv_op_vredmax_vs; break; - case 8: op = rv_op_vaaddu_vv; break; - case 9: op = rv_op_vaadd_vv; break; - case 10: op = rv_op_vasubu_vv; break; - case 11: op = rv_op_vasub_vv; break; - case 12: op = rv_op_vclmul_vv; break; - case 13: op = rv_op_vclmulh_vv; break; + case 0: return &op_vredsum_vs; + case 1: return &op_vredand_vs; + case 2: return &op_vredor_vs; + case 3: return &op_vredxor_vs; + case 4: return &op_vredminu_vs; + case 5: return &op_vredmin_vs; + case 6: return &op_vredmaxu_vs; + case 7: return &op_vredmax_vs; + case 8: return &op_vaaddu_vv; + case 9: return &op_vaadd_vv; + case 10: return &op_vasubu_vv; + case 11: return &op_vasub_vv; + case 12: return &op_vclmul_vv; + case 13: return &op_vclmulh_vv; case 16: switch ((inst >> 15) & 0b11111) { - case 0: if ((inst >> 25) & 1) op = rv_op_vmv_x_s; break; - case 16: op = rv_op_vcpop_m; break; - case 17: op = rv_op_vfirst_m; break; + case 0: + if ((inst >> 25) & 1) { + return &op_vmv_x_s; + } + break; + case 16: return &op_vcpop_m; + case 17: return &op_vfirst_m; } break; case 18: switch ((inst >> 15) & 0b11111) { - case 2: op = rv_op_vzext_vf8; break; - case 3: op = rv_op_vsext_vf8; break; - case 4: op = rv_op_vzext_vf4; break; - case 5: op = rv_op_vsext_vf4; break; - case 6: op = rv_op_vzext_vf2; break; - case 7: op = rv_op_vsext_vf2; break; - case 8: op = rv_op_vbrev8_v; break; - case 9: op = rv_op_vrev8_v; break; - case 10: op = rv_op_vbrev_v; break; - case 12: op = rv_op_vclz_v; break; - case 13: op = rv_op_vctz_v; break; - case 14: op = rv_op_vcpop_v; break; + case 2: return &op_vzext_vf8; + case 3: return &op_vsext_vf8; + case 4: return &op_vzext_vf4; + case 5: return &op_vsext_vf4; + case 6: return &op_vzext_vf2; + case 7: return &op_vsext_vf2; + case 8: return &op_vbrev8_v; + case 9: return &op_vrev8_v; + case 10: return &op_vbrev_v; + case 12: return &op_vclz_v; + case 13: return &op_vctz_v; + case 14: return &op_vcpop_v; } break; case 20: switch ((inst >> 15) & 0b11111) { - case 1: op = rv_op_vmsbf_m; break; - case 2: op = rv_op_vmsof_m; break; - case 3: op = rv_op_vmsif_m; break; - case 16: op = rv_op_viota_m; break; + case 1: return &op_vmsbf_m; break; + case 2: return &op_vmsof_m; + case 3: return &op_vmsif_m; + case 16: return &op_viota_m; case 17: if (((inst >> 20) & 0b11111) == 0) { - op = rv_op_vid_v; + return &op_vid_v; } break; } break; - case 23: if ((inst >> 25) & 1) op = rv_op_vcompress_vm; break; - case 24: if ((inst >> 25) & 1) op = rv_op_vmandn_mm; break; - case 25: if ((inst >> 25) & 1) op = rv_op_vmand_mm; break; - case 26: if ((inst >> 25) & 1) op = rv_op_vmor_mm; break; - case 27: if ((inst >> 25) & 1) op = rv_op_vmxor_mm; break; - case 28: if ((inst >> 25) & 1) op = rv_op_vmorn_mm; break; - case 29: if ((inst >> 25) & 1) op = rv_op_vmnand_mm; break; - case 30: if ((inst >> 25) & 1) op = rv_op_vmnor_mm; break; - case 31: if ((inst >> 25) & 1) op = rv_op_vmxnor_mm; break; - case 32: op = rv_op_vdivu_vv; break; - case 33: op = rv_op_vdiv_vv; break; - case 34: op = rv_op_vremu_vv; break; - case 35: op = rv_op_vrem_vv; break; - case 36: op = rv_op_vmulhu_vv; break; - case 37: op = rv_op_vmul_vv; break; - case 38: op = rv_op_vmulhsu_vv; break; - case 39: op = rv_op_vmulh_vv; break; - case 41: op = rv_op_vmadd_vv; break; - case 43: op = rv_op_vnmsub_vv; break; - case 45: op = rv_op_vmacc_vv; break; - case 47: op = rv_op_vnmsac_vv; break; - case 48: op = rv_op_vwaddu_vv; break; - case 49: op = rv_op_vwadd_vv; break; - case 50: op = rv_op_vwsubu_vv; break; - case 51: op = rv_op_vwsub_vv; break; - case 52: op = rv_op_vwaddu_wv; break; - case 53: op = rv_op_vwadd_wv; break; - case 54: op = rv_op_vwsubu_wv; break; - case 55: op = rv_op_vwsub_wv; break; - case 56: op = rv_op_vwmulu_vv; break; - case 58: op = rv_op_vwmulsu_vv; break; - case 59: op = rv_op_vwmul_vv; break; - case 60: op = rv_op_vwmaccu_vv; break; - case 61: op = rv_op_vwmacc_vv; break; - case 63: op = rv_op_vwmaccsu_vv; break; + case 23: + if ((inst >> 25) & 1) { + return &op_vcompress_vm; + } + break; + case 24: + if ((inst >> 25) & 1) { + return &op_vmandn_mm; + } + break; + case 25: + if ((inst >> 25) & 1) { + return &op_vmand_mm; + } + break; + case 26: + if ((inst >> 25) & 1) { + return &op_vmor_mm; + } + break; + case 27: + if ((inst >> 25) & 1) { + return &op_vmxor_mm; + } + break; + case 28: + if ((inst >> 25) & 1) { + return &op_vmorn_mm; + } + break; + case 29: + if ((inst >> 25) & 1) { + return &op_vmnand_mm; + } + break; + case 30: + if ((inst >> 25) & 1) { + return &op_vmnor_mm; + } + break; + case 31: + if ((inst >> 25) & 1) { + return &op_vmxnor_mm; + } + break; + case 32: return &op_vdivu_vv; + case 33: return &op_vdiv_vv; + case 34: return &op_vremu_vv; + case 35: return &op_vrem_vv; + case 36: return &op_vmulhu_vv; + case 37: return &op_vmul_vv; + case 38: return &op_vmulhsu_vv; + case 39: return &op_vmulh_vv; + case 41: return &op_vmadd_vv; + case 43: return &op_vnmsub_vv; + case 45: return &op_vmacc_vv; + case 47: return &op_vnmsac_vv; + case 48: return &op_vwaddu_vv; + case 49: return &op_vwadd_vv; + case 50: return &op_vwsubu_vv; + case 51: return &op_vwsub_vv; + case 52: return &op_vwaddu_wv; + case 53: return &op_vwadd_wv; + case 54: return &op_vwsubu_wv; + case 55: return &op_vwsub_wv; + case 56: return &op_vwmulu_vv; + case 58: return &op_vwmulsu_vv; + case 59: return &op_vwmul_vv; + case 60: return &op_vwmaccu_vv; + case 61: return &op_vwmacc_vv; + case 63: return &op_vwmaccsu_vv; } break; case 3: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vadd_vi; break; - case 3: op = rv_op_vrsub_vi; break; - case 9: op = rv_op_vand_vi; break; - case 10: op = rv_op_vor_vi; break; - case 11: op = rv_op_vxor_vi; break; - case 12: op = rv_op_vrgather_vi; break; - case 14: op = rv_op_vslideup_vi; break; - case 15: op = rv_op_vslidedown_vi; break; + case 0: return &op_vadd_vi; + case 3: return &op_vrsub_vi; + case 9: return &op_vand_vi; + case 10: return &op_vor_vi; + case 11: return &op_vxor_vi; + case 12: return &op_vrgather_vi; + case 14: return &op_vslideup_vi; + case 15: return &op_vslidedown_vi; case 16: if (((inst >> 25) & 1) == 0) { - op = rv_op_vadc_vim; + return &op_vadc_vim; } break; - case 17: op = rv_op_vmadc_vim; break; - case 20: case 21: op = rv_op_vror_vi; break; + case 17: return &op_vmadc_vim; + case 20: case 21: return &op_vror_vi; case 23: - if (((inst >> 20) & 0b111111) == 32) - op = rv_op_vmv_v_i; - else if (((inst >> 25) & 1) == 0) - op = rv_op_vmerge_vim; + if (((inst >> 20) & 0b111111) == 32) { + return &op_vmv_v_i; + } else if (((inst >> 25) & 1) == 0) { + return &op_vmerge_vim; + } break; - case 24: op = rv_op_vmseq_vi; break; - case 25: op = rv_op_vmsne_vi; break; - case 28: op = rv_op_vmsleu_vi; break; - case 29: op = rv_op_vmsle_vi; break; - case 30: op = rv_op_vmsgtu_vi; break; - case 31: op = rv_op_vmsgt_vi; break; - case 32: op = rv_op_vsaddu_vi; break; - case 33: op = rv_op_vsadd_vi; break; - case 37: op = rv_op_vsll_vi; break; + case 24: return &op_vmseq_vi; + case 25: return &op_vmsne_vi; + case 28: return &op_vmsleu_vi; + case 29: return &op_vmsle_vi; + case 30: return &op_vmsgtu_vi; + case 31: return &op_vmsgt_vi; + case 32: return &op_vsaddu_vi; + case 33: return &op_vsadd_vi; + case 37: return &op_vsll_vi; case 39: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_vmv1r_v; break; - case 1: op = rv_op_vmv2r_v; break; - case 3: op = rv_op_vmv4r_v; break; - case 7: op = rv_op_vmv8r_v; break; + case 0: return &op_vmv1r_v; + case 1: return &op_vmv2r_v; + case 3: return &op_vmv4r_v; + case 7: return &op_vmv8r_v; } break; - case 40: op = rv_op_vsrl_vi; break; - case 41: op = rv_op_vsra_vi; break; - case 42: op = rv_op_vssrl_vi; break; - case 43: op = rv_op_vssra_vi; break; - case 44: op = rv_op_vnsrl_wi; break; - case 45: op = rv_op_vnsra_wi; break; - case 46: op = rv_op_vnclipu_wi; break; - case 47: op = rv_op_vnclip_wi; break; - case 53: op = rv_op_vwsll_vi; break; + case 40: return &op_vsrl_vi; + case 41: return &op_vsra_vi; + case 42: return &op_vssrl_vi; + case 43: return &op_vssra_vi; + case 44: return &op_vnsrl_wi; + case 45: return &op_vnsra_wi; + case 46: return &op_vnclipu_wi; + case 47: return &op_vnclip_wi; + case 53: return &op_vwsll_vi; } break; case 4: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vadd_vx; break; - case 1: op = rv_op_vandn_vx; break; - case 2: op = rv_op_vsub_vx; break; - case 3: op = rv_op_vrsub_vx; break; - case 4: op = rv_op_vminu_vx; break; - case 5: op = rv_op_vmin_vx; break; - case 6: op = rv_op_vmaxu_vx; break; - case 7: op = rv_op_vmax_vx; break; - case 9: op = rv_op_vand_vx; break; - case 10: op = rv_op_vor_vx; break; - case 11: op = rv_op_vxor_vx; break; - case 12: op = rv_op_vrgather_vx; break; - case 14: op = rv_op_vslideup_vx; break; - case 15: op = rv_op_vslidedown_vx; break; + case 0: return &op_vadd_vx; + case 1: return &op_vandn_vx; + case 2: return &op_vsub_vx; + case 3: return &op_vrsub_vx; + case 4: return &op_vminu_vx; + case 5: return &op_vmin_vx; + case 6: return &op_vmaxu_vx; + case 7: return &op_vmax_vx; + case 9: return &op_vand_vx; + case 10: return &op_vor_vx; + case 11: return &op_vxor_vx; + case 12: return &op_vrgather_vx; + case 14: return &op_vslideup_vx; + case 15: return &op_vslidedown_vx; case 16: if (((inst >> 25) & 1) == 0) { - op = rv_op_vadc_vxm; + return &op_vadc_vxm; } break; - case 17: op = rv_op_vmadc_vxm; break; + case 17: return &op_vmadc_vxm; case 18: if (((inst >> 25) & 1) == 0) { - op = rv_op_vsbc_vxm; + return &op_vsbc_vxm; } break; - case 19: op = rv_op_vmsbc_vxm; break; - case 20: op = rv_op_vror_vx; break; - case 21: op = rv_op_vrol_vx; break; + case 19: return &op_vmsbc_vxm; + case 20: return &op_vror_vx; + case 21: return &op_vrol_vx; case 23: - if (((inst >> 20) & 0b111111) == 32) - op = rv_op_vmv_v_x; - else if (((inst >> 25) & 1) == 0) - op = rv_op_vmerge_vxm; + if (((inst >> 20) & 0b111111) == 32) { + return &op_vmv_v_x; + } else if (((inst >> 25) & 1) == 0) { + return &op_vmerge_vxm; + } break; - case 24: op = rv_op_vmseq_vx; break; - case 25: op = rv_op_vmsne_vx; break; - case 26: op = rv_op_vmsltu_vx; break; - case 27: op = rv_op_vmslt_vx; break; - case 28: op = rv_op_vmsleu_vx; break; - case 29: op = rv_op_vmsle_vx; break; - case 30: op = rv_op_vmsgtu_vx; break; - case 31: op = rv_op_vmsgt_vx; break; - case 32: op = rv_op_vsaddu_vx; break; - case 33: op = rv_op_vsadd_vx; break; - case 34: op = rv_op_vssubu_vx; break; - case 35: op = rv_op_vssub_vx; break; - case 37: op = rv_op_vsll_vx; break; - case 39: op = rv_op_vsmul_vx; break; - case 40: op = rv_op_vsrl_vx; break; - case 41: op = rv_op_vsra_vx; break; - case 42: op = rv_op_vssrl_vx; break; - case 43: op = rv_op_vssra_vx; break; - case 44: op = rv_op_vnsrl_wx; break; - case 45: op = rv_op_vnsra_wx; break; - case 46: op = rv_op_vnclipu_wx; break; - case 47: op = rv_op_vnclip_wx; break; - case 53: op = rv_op_vwsll_vx; break; + case 24: return &op_vmseq_vx; + case 25: return &op_vmsne_vx; + case 26: return &op_vmsltu_vx; + case 27: return &op_vmslt_vx; + case 28: return &op_vmsleu_vx; + case 29: return &op_vmsle_vx; + case 30: return &op_vmsgtu_vx; + case 31: return &op_vmsgt_vx; + case 32: return &op_vsaddu_vx; + case 33: return &op_vsadd_vx; + case 34: return &op_vssubu_vx; + case 35: return &op_vssub_vx; + case 37: return &op_vsll_vx; + case 39: return &op_vsmul_vx; + case 40: return &op_vsrl_vx; + case 41: return &op_vsra_vx; + case 42: return &op_vssrl_vx; + case 43: return &op_vssra_vx; + case 44: return &op_vnsrl_wx; + case 45: return &op_vnsra_wx; + case 46: return &op_vnclipu_wx; + case 47: return &op_vnclip_wx; + case 53: return &op_vwsll_vx; } break; case 5: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_vfadd_vf; break; - case 2: op = rv_op_vfsub_vf; break; - case 4: op = rv_op_vfmin_vf; break; - case 6: op = rv_op_vfmax_vf; break; - case 8: op = rv_op_vfsgnj_vf; break; - case 9: op = rv_op_vfsgnjn_vf; break; - case 10: op = rv_op_vfsgnjx_vf; break; - case 14: op = rv_op_vfslide1up_vf; break; - case 15: op = rv_op_vfslide1down_vf; break; + case 0: return &op_vfadd_vf; + case 2: return &op_vfsub_vf; + case 4: return &op_vfmin_vf; + case 6: return &op_vfmax_vf; + case 8: return &op_vfsgnj_vf; + case 9: return &op_vfsgnjn_vf; + case 10: return &op_vfsgnjx_vf; + case 14: return &op_vfslide1up_vf; + case 15: return &op_vfslide1down_vf; case 16: switch ((inst >> 20) & 0b11111) { - case 0: if ((inst >> 25) & 1) op = rv_op_vfmv_s_f; break; + case 0: + if ((inst >> 25) & 1) { + return &op_vfmv_s_f; + } } break; case 23: - if (((inst >> 25) & 1) == 0) - op = rv_op_vfmerge_vfm; - else if (((inst >> 20) & 0b111111) == 32) - op = rv_op_vfmv_v_f; + if (((inst >> 25) & 1) == 0) { + return &op_vfmerge_vfm; + } else if (((inst >> 20) & 0b111111) == 32) { + return &op_vfmv_v_f; + } break; - case 24: op = rv_op_vmfeq_vf; break; - case 25: op = rv_op_vmfle_vf; break; - case 27: op = rv_op_vmflt_vf; break; - case 28: op = rv_op_vmfne_vf; break; - case 29: op = rv_op_vmfgt_vf; break; - case 31: op = rv_op_vmfge_vf; break; - case 32: op = rv_op_vfdiv_vf; break; - case 33: op = rv_op_vfrdiv_vf; break; - case 36: op = rv_op_vfmul_vf; break; - case 39: op = rv_op_vfrsub_vf; break; - case 40: op = rv_op_vfmadd_vf; break; - case 41: op = rv_op_vfnmadd_vf; break; - case 42: op = rv_op_vfmsub_vf; break; - case 43: op = rv_op_vfnmsub_vf; break; - case 44: op = rv_op_vfmacc_vf; break; - case 45: op = rv_op_vfnmacc_vf; break; - case 46: op = rv_op_vfmsac_vf; break; - case 47: op = rv_op_vfnmsac_vf; break; - case 48: op = rv_op_vfwadd_vf; break; - case 50: op = rv_op_vfwsub_vf; break; - case 52: op = rv_op_vfwadd_wf; break; - case 54: op = rv_op_vfwsub_wf; break; - case 56: op = rv_op_vfwmul_vf; break; - case 59: op = rv_op_vfwmaccbf16_vf; break; - case 60: op = rv_op_vfwmacc_vf; break; - case 61: op = rv_op_vfwnmacc_vf; break; - case 62: op = rv_op_vfwmsac_vf; break; - case 63: op = rv_op_vfwnmsac_vf; break; + case 24: return &op_vmfeq_vf; + case 25: return &op_vmfle_vf; + case 27: return &op_vmflt_vf; + case 28: return &op_vmfne_vf; + case 29: return &op_vmfgt_vf; + case 31: return &op_vmfge_vf; + case 32: return &op_vfdiv_vf; + case 33: return &op_vfrdiv_vf; + case 36: return &op_vfmul_vf; + case 39: return &op_vfrsub_vf; + case 40: return &op_vfmadd_vf; + case 41: return &op_vfnmadd_vf; + case 42: return &op_vfmsub_vf; + case 43: return &op_vfnmsub_vf; + case 44: return &op_vfmacc_vf; + case 45: return &op_vfnmacc_vf; + case 46: return &op_vfmsac_vf; + case 47: return &op_vfnmsac_vf; + case 48: return &op_vfwadd_vf; + case 50: return &op_vfwsub_vf; + case 52: return &op_vfwadd_wf; + case 54: return &op_vfwsub_wf; + case 56: return &op_vfwmul_vf; + case 59: return &op_vfwmaccbf16_vf; + case 60: return &op_vfwmacc_vf; + case 61: return &op_vfwnmacc_vf; + case 62: return &op_vfwmsac_vf; + case 63: return &op_vfwnmsac_vf; } break; case 6: switch ((inst >> 26) & 0b111111) { - case 8: op = rv_op_vaaddu_vx; break; - case 9: op = rv_op_vaadd_vx; break; - case 10: op = rv_op_vasubu_vx; break; - case 11: op = rv_op_vasub_vx; break; - case 12: op = rv_op_vclmul_vx; break; - case 13: op = rv_op_vclmulh_vx; break; - case 14: op = rv_op_vslide1up_vx; break; - case 15: op = rv_op_vslide1down_vx; break; + case 8: return &op_vaaddu_vx; + case 9: return &op_vaadd_vx; + case 10: return &op_vasubu_vx; + case 11: return &op_vasub_vx; + case 12: return &op_vclmul_vx; + case 13: return &op_vclmulh_vx; + case 14: return &op_vslide1up_vx; + case 15: return &op_vslide1down_vx; case 16: switch ((inst >> 20) & 0b11111) { - case 0: if ((inst >> 25) & 1) op = rv_op_vmv_s_x; break; + case 0: + if ((inst >> 25) & 1) { + return &op_vmv_s_x; + } } break; - case 32: op = rv_op_vdivu_vx; break; - case 33: op = rv_op_vdiv_vx; break; - case 34: op = rv_op_vremu_vx; break; - case 35: op = rv_op_vrem_vx; break; - case 36: op = rv_op_vmulhu_vx; break; - case 37: op = rv_op_vmul_vx; break; - case 38: op = rv_op_vmulhsu_vx; break; - case 39: op = rv_op_vmulh_vx; break; - case 41: op = rv_op_vmadd_vx; break; - case 43: op = rv_op_vnmsub_vx; break; - case 45: op = rv_op_vmacc_vx; break; - case 47: op = rv_op_vnmsac_vx; break; - case 48: op = rv_op_vwaddu_vx; break; - case 49: op = rv_op_vwadd_vx; break; - case 50: op = rv_op_vwsubu_vx; break; - case 51: op = rv_op_vwsub_vx; break; - case 52: op = rv_op_vwaddu_wx; break; - case 53: op = rv_op_vwadd_wx; break; - case 54: op = rv_op_vwsubu_wx; break; - case 55: op = rv_op_vwsub_wx; break; - case 56: op = rv_op_vwmulu_vx; break; - case 58: op = rv_op_vwmulsu_vx; break; - case 59: op = rv_op_vwmul_vx; break; - case 60: op = rv_op_vwmaccu_vx; break; - case 61: op = rv_op_vwmacc_vx; break; - case 62: op = rv_op_vwmaccus_vx; break; - case 63: op = rv_op_vwmaccsu_vx; break; + case 32: return &op_vdivu_vx; + case 33: return &op_vdiv_vx; + case 34: return &op_vremu_vx; + case 35: return &op_vrem_vx; + case 36: return &op_vmulhu_vx; + case 37: return &op_vmul_vx; + case 38: return &op_vmulhsu_vx; + case 39: return &op_vmulh_vx; + case 41: return &op_vmadd_vx; + case 43: return &op_vnmsub_vx; + case 45: return &op_vmacc_vx; + case 47: return &op_vnmsac_vx; + case 48: return &op_vwaddu_vx; + case 49: return &op_vwadd_vx; + case 50: return &op_vwsubu_vx; + case 51: return &op_vwsub_vx; + case 52: return &op_vwaddu_wx; + case 53: return &op_vwadd_wx; + case 54: return &op_vwsubu_wx; + case 55: return &op_vwsub_wx; + case 56: return &op_vwmulu_vx; + case 58: return &op_vwmulsu_vx; + case 59: return &op_vwmul_vx; + case 60: return &op_vwmaccu_vx; + case 61: return &op_vwmacc_vx; + case 62: return &op_vwmaccus_vx; + case 63: return &op_vwmaccsu_vx; } break; case 7: if (((inst >> 31) & 1) == 0) { - op = rv_op_vsetvli; + return &op_vsetvli; } else if ((inst >> 30) & 1) { - op = rv_op_vsetivli; + return &op_vsetivli; } else if (((inst >> 25) & 0b11111) == 0) { - op = rv_op_vsetvl; + return &op_vsetvl; } break; } break; case 22: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_addid; break; + case 0: return &op_addid; case 1: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_sllid; break; + case 0: return &op_sllid; } break; case 5: switch ((inst >> 26) & 0b111111) { - case 0: op = rv_op_srlid; break; - case 16: op = rv_op_sraid; break; + case 0: return &op_srlid; + case 16: return &op_sraid; } break; } break; case 24: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_beq; break; - case 1: op = rv_op_bne; break; - case 4: op = rv_op_blt; break; - case 5: op = rv_op_bge; break; - case 6: op = rv_op_bltu; break; - case 7: op = rv_op_bgeu; break; + case 0: return &op_beq; + case 1: return &op_bne; + case 4: return &op_blt; + case 5: return &op_bge; + case 6: return &op_bltu; + case 7: return &op_bgeu; } break; case 25: switch ((inst >> 12) & 0b111) { - case 0: op = rv_op_jalr; break; + case 0: return &op_jalr; } break; - case 27: op = rv_op_jal; break; + case 27: return &op_jal; case 28: switch ((inst >> 12) & 0b111) { case 0: @@ -2483,76 +2504,76 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) ((inst >> 7) & 0b000000011111)) { case 0: switch ((inst >> 15) & 0b1111111111) { - case 0: op = rv_op_ecall; break; - case 32: op = rv_op_ebreak; break; - case 64: op = rv_op_uret; break; - case 416: op = rv_op_wrs_nto; break; - case 928: op = rv_op_wrs_sto; break; + case 0: return &op_ecall; + case 32: return &op_ebreak; + case 64: return &op_uret; + case 416: return &op_wrs_nto; + case 928: return &op_wrs_sto; } break; case 256: switch ((inst >> 20) & 0b11111) { case 2: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_sret; break; + case 0: return &op_sret; } break; - case 4: op = rv_op_sfence_vm; break; + case 4: return &op_sfence_vm; case 5: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_wfi; break; + case 0: return &op_wfi; } break; } break; - case 288: op = rv_op_sfence_vma; break; + case 288: return &op_sfence_vma; case 512: switch ((inst >> 15) & 0b1111111111) { - case 64: op = rv_op_hret; break; + case 64: return &op_hret; } break; case 768: switch ((inst >> 15) & 0b1111111111) { - case 64: op = rv_op_mret; break; + case 64: return &op_mret; } break; case 1792: switch ((inst >> 15) & 0b1111111111) { - case 64: op = rv_op_mnret; break; + case 64: return &op_mnret; } break; case 1952: switch ((inst >> 15) & 0b1111111111) { - case 576: op = rv_op_dret; break; + case 576: return &op_dret; } break; } break; case 1: switch (operand_csr12(inst)) { - case 1: op = rv_op_fsflags; break; - case 2: op = rv_op_fsrm; break; - case 3: op = rv_op_fscsr; break; - default: op = rv_op_csrrw; break; + case 1: return &op_fsflags; + case 2: return &op_fsrm; + case 3: return &op_fscsr; + default: return &op_csrrw; } break; case 2: - op = rv_op_csrrs; + return &op_csrrs; if (operand_rs1(inst) == 0) { switch (operand_csr12(inst)) { - case 0x001: op = rv_op_frflags; break; - case 0x002: op = rv_op_frrm; break; - case 0x003: op = rv_op_frcsr; break; - case 0xc00: op = rv_op_rdcycle; break; - case 0xc01: op = rv_op_rdtime; break; - case 0xc02: op = rv_op_rdinstret; break; - case 0xc80: op = rv_op_rdcycleh; break; - case 0xc81: op = rv_op_rdtimeh; break; - case 0xc82: op = rv_op_rdinstreth; break; + case 0x001: return &op_frflags; + case 0x002: return &op_frrm; + case 0x003: return &op_frcsr; + case 0xc00: return &op_rdcycle; + case 0xc01: return &op_rdtime; + case 0xc02: return &op_rdinstret; + case 0xc80: return &op_rdcycleh; + case 0xc81: return &op_rdtimeh; + case 0xc82: return &op_rdinstreth; } } break; - case 3: op = rv_op_csrrc; break; + case 3: return &op_csrrc; case 4: if (dec->cfg && dec->cfg->ext_zimop) { if (((inst >> 22) & 0b1011001111) == 0b1000000111) { @@ -2560,15 +2581,15 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) && operand_mop_r_imm(inst) == 28) { switch (operand_rs1(inst)) { case 0: - return &rvi_opcode_data[rv_op_ssrdp]; + return &op_ssrdp; case 1: case 5: if (operand_rd(inst) == 0) { - return &rvi_opcode_data[rv_op_sspopchk]; + return &op_sspopchk; } } } - return &rvi_opcode_data[rv_op_mop_r]; + return &op_mop_r; } if (((inst >> 25) & 0b1011001) == 0b1000001) { if (dec->cfg->ext_zicfiss @@ -2578,79 +2599,79 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) switch (operand_rs2(inst)) { case 1: case 5: - return &rvi_opcode_data[rv_op_sspush]; + return &op_sspush; } } - return &rvi_opcode_data[rv_op_mop_rr]; + return &op_mop_rr; } } break; case 5: switch (operand_csr12(inst)) { - case 1: op = rv_op_fsflagsi; break; - case 2: op = rv_op_fsrmi; break; - default: op = rv_op_csrrwi; break; + case 1: return &op_fsflagsi; + case 2: return &op_fsrmi; + default: return &op_csrrwi; } break; - case 6: op = rv_op_csrrsi; break; - case 7: op = rv_op_csrrci; break; + case 6: return &op_csrrsi; + case 7: return &op_csrrci; } break; case 29: if (((inst >> 25) & 1) == 1 && ((inst >> 12) & 0b111) == 2) { switch ((inst >> 26) & 0b111111) { - case 32: op = rv_op_vsm3me_vv; break; - case 33: op = rv_op_vsm4k_vi; break; - case 34: op = rv_op_vaeskf1_vi; break; + case 32: return &op_vsm3me_vv; + case 33: return &op_vsm4k_vi; + case 34: return &op_vaeskf1_vi; case 40: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_vaesdm_vv; break; - case 1: op = rv_op_vaesdf_vv; break; - case 2: op = rv_op_vaesem_vv; break; - case 3: op = rv_op_vaesef_vv; break; - case 16: op = rv_op_vsm4r_vv; break; - case 17: op = rv_op_vgmul_vv; break; + case 0: return &op_vaesdm_vv; + case 1: return &op_vaesdf_vv; + case 2: return &op_vaesem_vv; + case 3: return &op_vaesef_vv; + case 16: return &op_vsm4r_vv; + case 17: return &op_vgmul_vv; } break; case 41: switch ((inst >> 15) & 0b11111) { - case 0: op = rv_op_vaesdm_vs; break; - case 1: op = rv_op_vaesdf_vs; break; - case 2: op = rv_op_vaesem_vs; break; - case 3: op = rv_op_vaesef_vs; break; - case 7: op = rv_op_vaesz_vs; break; - case 16: op = rv_op_vsm4r_vs; break; + case 0: return &op_vaesdm_vs; + case 1: return &op_vaesdf_vs; + case 2: return &op_vaesem_vs; + case 3: return &op_vaesef_vs; + case 7: return &op_vaesz_vs; + case 16: return &op_vsm4r_vs; } break; - case 42: op = rv_op_vaeskf2_vi; break; - case 43: op = rv_op_vsm3c_vi; break; - case 44: op = rv_op_vghsh_vv; break; - case 45: op = rv_op_vsha2ms_vv; break; - case 46: op = rv_op_vsha2ch_vv; break; - case 47: op = rv_op_vsha2cl_vv; break; + case 42: return &op_vaeskf2_vi; + case 43: return &op_vsm3c_vi; + case 44: return &op_vghsh_vv; + case 45: return &op_vsha2ms_vv; + case 46: return &op_vsha2ch_vv; + case 47: return &op_vsha2cl_vv; } } break; case 30: switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) { - case 0: op = rv_op_addd; break; - case 1: op = rv_op_slld; break; - case 5: op = rv_op_srld; break; - case 8: op = rv_op_muld; break; - case 12: op = rv_op_divd; break; - case 13: op = rv_op_divud; break; - case 14: op = rv_op_remd; break; - case 15: op = rv_op_remud; break; - case 256: op = rv_op_subd; break; - case 261: op = rv_op_srad; break; + case 0: return &op_addd; + case 1: return &op_slld; + case 5: return &op_srld; + case 8: return &op_muld; + case 12: return &op_divd; + case 13: return &op_divud; + case 14: return &op_remd; + case 15: return &op_remud; + case 256: return &op_subd; + case 261: return &op_srad; } break; } break; } - return op == rv_op_illegal ? NULL : &rvi_opcode_data[op]; + return NULL; } /* decode operands */ @@ -3450,7 +3471,7 @@ static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, decode_inst_operands(&dec, isa, op); op = decode_inst_lift_pseudo(&dec, op); } else { - op = &rvi_opcode_data[rv_op_illegal]; + op = &op_illegal; } return format_inst(24, &dec, op); From 7fe2a88a4049f678b626474933b516eee19bb643 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Aug 2026 15:31:42 -0700 Subject: [PATCH 567/627] disas/riscv: Sort riscv-op.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To date, opcodes had to be added to the end of the list, resulting in quite the disorder. Sort via 'LANG=C sort'. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20260812223142.349142-53-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- disas/riscv-op.c.inc | 1704 +++++++++++++++++++++--------------------- 1 file changed, 852 insertions(+), 852 deletions(-) diff --git a/disas/riscv-op.c.inc b/disas/riscv-op.c.inc index cc939f557f..1d334e4857 100644 --- a/disas/riscv-op.c.inc +++ b/disas/riscv-op.c.inc @@ -1,913 +1,913 @@ -OP(illegal, "illegal", rv_codec_none, rv_fmt_none) -OP(lui, "lui", rv_codec_u, rv_fmt_rd_uimm) -OP(auipc, "auipc", rv_codec_u, rv_fmt_rd_uoffset) -OP(jal, "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal) -OP(jalr, "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr) -OP(beq, "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq) -OP(bne, "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne) -OP(blt, "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt) -OP(bge, "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge) -OP(bltu, "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset) -OP(bgeu, "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset) -OP(lb, "lb", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(lh, "lh", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(lw, "lw", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(lbu, "lbu", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(lhu, "lhu", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(sb, "sb", rv_codec_s, rv_fmt_rs2_offset_rs1) -OP(sh, "sh", rv_codec_s, rv_fmt_rs2_offset_rs1) -OP(sw, "sw", rv_codec_s, rv_fmt_rs2_offset_rs1) -OP(addi, "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi) -OP(slti, "slti", rv_codec_i, rv_fmt_rd_rs1_imm) -OP(sltiu, "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu) -OP(xori, "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori) -OP(ori, "ori", rv_codec_i, rv_fmt_rd_rs1_imm) -OP(andi, "andi", rv_codec_i, rv_fmt_rd_rs1_imm) -OP(slli, "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(srli, "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(srai, "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) OP(add, "add", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sub, "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub) -OP(sll, "sll", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(slt, "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt) -OP(sltu, "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu) -OP(xor, "xor", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(srl, "srl", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sra, "sra", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(or, "or", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(add_uw, "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(addd, "addd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(addi, "addi", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addi) +OP(addid, "addid", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(addiw, "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw) +OP(addw, "addw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes32dsi, "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32dsmi, "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32esi, "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes32esmi, "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) +OP(aes64ds, "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64dsm, "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64es, "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64esm, "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(aes64im, "aes64im", rv_codec_r, rv_fmt_rd_rs1) +OP(aes64ks1i, "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum) +OP(aes64ks2, "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(amoadd_b, "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_d, "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_h, "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_q, "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoadd_w, "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_b, "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_d, "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_h, "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_q, "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoand_w, "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_b, "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_h, "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amocas_w, "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_b, "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_d, "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_h, "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_q, "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomax_w, "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_b, "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_d, "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_h, "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_q, "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomaxu_w, "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_b, "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_d, "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_h, "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_q, "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amomin_w, "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_b, "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_d, "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_h, "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_q, "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amominu_w, "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_b, "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_d, "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_h, "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_q, "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoor_w, "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_b, "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_d, "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_h, "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_q, "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoswap_w, "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_b, "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_d, "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_h, "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_q, "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(amoxor_w, "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) OP(and, "and", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(andi, "andi", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(andn, "andn", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(auipc, "auipc", rv_codec_u, rv_fmt_rd_uoffset) +OP(bclr, "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(bclri, "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(beq, "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq) +OP(beqz, "beqz", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bext, "bext", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(bexti, "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(bge, "bge", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bge) +OP(bgeu, "bgeu", rv_codec_sb, rv_fmt_rs1_rs2_offset) +OP(bgez, "bgez", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bgtz, "bgtz", rv_codec_illegal, rv_fmt_rs2_offset) +OP(binv, "binv", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(binvi, "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(blez, "blez", rv_codec_illegal, rv_fmt_rs2_offset) +OP(blt, "blt", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_blt) +OP(bltu, "bltu", rv_codec_sb, rv_fmt_rs1_rs2_offset) +OP(bltz, "bltz", rv_codec_illegal, rv_fmt_rs1_offset) +OP(bne, "bne", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_bne) +OP(bnez, "bnez", rv_codec_illegal, rv_fmt_rs1_offset) +OP(brev8, "brev8", rv_codec_r, rv_fmt_rd_rs1) +OP(bset, "bset", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(bseti, "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(c_add, "c.add", rv_codec_cr, NULL, DECOMP(op_add)) +OP(c_addi, "c.addi", rv_codec_ci, NULL, DECOMP(op_addi)) +OP(c_addi16sp, "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(op_addi)) +OP(c_addi4spn, "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(op_addi)) +OP(c_addiw, "c.addiw", rv_codec_ci, NULL, DECOMP(op_addiw)) +OP(c_addw, "c.addw", rv_codec_cs, NULL, DECOMP(op_addw)) +OP(c_and, "c.and", rv_codec_cs, NULL, DECOMP(op_and)) +OP(c_andi, "c.andi", rv_codec_cb_imm, NULL, DECOMP(op_andi)) +OP(c_beqz, "c.beqz", rv_codec_cb, NULL, DECOMP(op_beqz)) +OP(c_bnez, "c.bnez", rv_codec_cb, NULL, DECOMP(op_bnez)) +OP(c_ebreak, "c.ebreak", rv_codec_ci_none, NULL, DECOMP(op_ebreak)) +OP(c_fld, "c.fld", rv_codec_cl_ld, NULL, DECOMP(op_fld)) +OP(c_fldsp, "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_fld)) +OP(c_flw, "c.flw", rv_codec_cl_lw, NULL, DECOMP(op_flw)) +OP(c_flwsp, "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_flw)) +OP(c_fsd, "c.fsd", rv_codec_cs_sd, NULL, DECOMP(op_fsd)) +OP(c_fsdsp, "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(op_fsd)) +OP(c_fsw, "c.fsw", rv_codec_cs_sw, NULL, DECOMP(op_fsw)) +OP(c_fswsp, "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(op_fsw)) +OP(c_j, "c.j", rv_codec_cj, NULL, DECOMP(op_j)) +OP(c_jal, "c.jal", rv_codec_cj_jal, NULL, DECOMP(op_jal)) +OP(c_jalr, "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(op_jalr)) +OP(c_jr, "c.jr", rv_codec_cr_jr, NULL, DECOMP(op_jr)) +OP(c_lbu, "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) +OP(c_ld, "c.ld", rv_codec_cl_ld, NULL, DECOMP(op_ld)) +OP(c_ldsp, "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_ld)) +OP(c_lh, "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(c_lhu, "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(c_li, "c.li", rv_codec_ci_li, NULL, DECOMP(op_addi)) +OP(c_lq, "c.lq", rv_codec_cl_lq, NULL, DECOMP(op_lq)) +OP(c_lqsp, "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(op_lq)) +OP(c_lui, "c.lui", rv_codec_ci_lui, NULL, DECOMP(op_lui)) +OP(c_lw, "c.lw", rv_codec_cl_lw, NULL, DECOMP(op_lw)) +OP(c_lwsp, "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_lw)) +OP(c_mop, "c.mop", rv_codec_cmop, rv_fmt_cmop) +OP(c_mul, "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2) +OP(c_mv, "c.mv", rv_codec_cr_mv, NULL, DECOMP(op_mv)) +OP(c_not, "c.not", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_or, "c.or", rv_codec_cs, NULL, DECOMP(op_or)) +OP(c_sb, "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) +OP(c_sd, "c.sd", rv_codec_cs_sd, NULL, DECOMP(op_sd)) +OP(c_sdsp, "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(op_sd)) +OP(c_sext_b, "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_sext_h, "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_sh, "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) +OP(c_slli, "c.slli", rv_codec_ci_sh6, NULL, DECOMP(op_slli)) +OP(c_sq, "c.sq", rv_codec_cs_sq, NULL, DECOMP(op_sq)) +OP(c_sqsp, "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(op_sq)) +OP(c_srai, "c.srai", rv_codec_cb_sh6, NULL, DECOMP(op_srai)) +OP(c_srli, "c.srli", rv_codec_cb_sh6, NULL, DECOMP(op_srli)) +OP(c_sspopchk, "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(op_sspopchk)) +OP(c_sspush, "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(op_sspush)) +OP(c_sub, "c.sub", rv_codec_cs, NULL, DECOMP(op_sub)) +OP(c_subw, "c.subw", rv_codec_cs, NULL, DECOMP(op_subw)) +OP(c_sw, "c.sw", rv_codec_cs_sw, NULL, DECOMP(op_sw)) +OP(c_swsp, "c.swsp", rv_codec_css_swsp, NULL, DECOMP(op_sw)) +OP(c_xor, "c.xor", rv_codec_cs, NULL, DECOMP(op_xor)) +OP(c_zext_b, "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_zext_h, "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd) +OP(c_zext_w, "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd) +OP(cbo_clean, "cbo.clean", rv_codec_r, rv_fmt_rs1) +OP(cbo_flush, "cbo.flush", rv_codec_r, rv_fmt_rs1) +OP(cbo_inval, "cbo.inval", rv_codec_r, rv_fmt_rs1) +OP(cbo_zero, "cbo.zero", rv_codec_r, rv_fmt_rs1) +OP(clmul, "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clmulh, "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clmulr, "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(clz, "clz", rv_codec_r, rv_fmt_rd_rs1) +OP(clzw, "clzw", rv_codec_r, rv_fmt_rd_rs1) +OP(cm_jalt, "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) +OP(cm_jt, "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) +OP(cm_mva01s, "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) +OP(cm_mvsa01, "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) +OP(cm_pop, "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_popret, "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_popretz, "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) +OP(cm_push, "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist) +OP(cpop, "cpop", rv_codec_r, rv_fmt_rd_rs1) +OP(cpopw, "cpopw", rv_codec_r, rv_fmt_rd_rs1) +OP(csrrc, "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrci, "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(csrrs, "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrsi, "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(csrrw, "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1) +OP(csrrwi, "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) +OP(ctz, "ctz", rv_codec_r, rv_fmt_rd_rs1) +OP(ctzw, "ctzw", rv_codec_r, rv_fmt_rd_rs1) +OP(czero_eqz, "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(czero_nez, "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(div, "div", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divd, "divd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divu, "divu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divud, "divud", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divuw, "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(divw, "divw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(dret, "dret", rv_codec_none, rv_fmt_none) +OP(ebreak, "ebreak", rv_codec_none, rv_fmt_none) +OP(ecall, "ecall", rv_codec_none, rv_fmt_none) +OP(fabs_d, "fabs.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fabs_q, "fabs.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fabs_s, "fabs.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fadd_d, "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fadd_q, "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fadd_s, "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fclass_d, "fclass.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fclass_q, "fclass.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fclass_s, "fclass.s", rv_codec_r, rv_fmt_rd_frs1) +OP(fcvt_bf16_s, "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_d_l, "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_d_lu, "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_d_q, "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_d_s, "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_d_w, "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_d_wu, "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_l_d, "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_l_q, "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_l_s, "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_d, "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_q, "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_lu_s, "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_q_d, "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_q_l, "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_q_lu, "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_q_s, "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_q_w, "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_q_wu, "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_bf16, "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_s_d, "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_s_l, "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_lu, "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_q, "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fcvt_s_w, "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_s_wu, "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) +OP(fcvt_w_d, "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_w_q, "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_w_s, "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_d, "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_q, "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvt_wu_s, "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fcvtmod_w_d, "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) +OP(fdiv_d, "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fdiv_q, "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fdiv_s, "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) OP(fence, "fence", rv_codec_r_f, rv_fmt_pred_succ) OP(fence_i, "fence.i", rv_codec_none, rv_fmt_none) -OP(lwu, "lwu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(feq_d, "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(feq_q, "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(feq_s, "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fld, "fld", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fle_d, "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fle_q, "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fle_s, "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_d, "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_h, "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_q, "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fleq_s, "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flh, "flh", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fli_d, "fli.d", rv_codec_fli, rv_fmt_fli) +OP(fli_h, "fli.h", rv_codec_fli, rv_fmt_fli) +OP(fli_q, "fli.q", rv_codec_fli, rv_fmt_fli) +OP(fli_s, "fli.s", rv_codec_fli, rv_fmt_fli) +OP(flq, "flq", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(flt_d, "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flt_q, "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flt_s, "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_d, "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_h, "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_q, "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(fltq_s, "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) +OP(flw, "flw", rv_codec_i, rv_fmt_frd_offset_rs1) +OP(fmadd_d, "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmadd_q, "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmadd_s, "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmax_d, "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmax_q, "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmax_s, "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_d, "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_h, "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_q, "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmaxm_s, "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmin_d, "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmin_q, "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmin_s, "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_d, "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_h, "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_q, "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fminm_s, "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) +OP(fmsub_d, "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmsub_q, "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmsub_s, "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fmul_d, "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmul_q, "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmul_s, "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fmv_d, "fmv.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fmv_d_x, "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fmv_h_x, "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fmv_q, "fmv.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fmv_q_x, "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fmv_s, "fmv.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fmv_s_x, "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1) +OP(fmv_x_d, "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fmv_x_h, "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1) +OP(fmv_x_q, "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fmv_x_s, "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1) +OP(fmvh_x_d, "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1) +OP(fmvh_x_q, "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1) +OP(fmvp_d_x, "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2) +OP(fmvp_q_x, "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2) +OP(fneg_d, "fneg.d", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fneg_q, "fneg.q", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fneg_s, "fneg.s", rv_codec_illegal, rv_fmt_frd_frs1) +OP(fnmadd_d, "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmadd_q, "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmadd_s, "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_d, "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_q, "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(fnmsub_s, "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) +OP(frcsr, "frcsr", rv_codec_i_csr, rv_fmt_rd) +OP(frflags, "frflags", rv_codec_i_csr, rv_fmt_rd) +OP(fround_d, "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_h, "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_q, "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fround_s, "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_d, "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_h, "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_q, "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(froundnx_s, "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(frrm, "frrm", rv_codec_i_csr, rv_fmt_rd) +OP(fscsr, "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsd, "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fsflags, "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsflagsi, "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm) +OP(fsgnj_d, "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d) +OP(fsgnj_q, "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q) +OP(fsgnj_s, "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s) +OP(fsgnjn_d, "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d) +OP(fsgnjn_q, "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q) +OP(fsgnjn_s, "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s) +OP(fsgnjx_d, "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d) +OP(fsgnjx_q, "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q) +OP(fsgnjx_s, "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s) +OP(fsh, "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fsq, "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(fsqrt_d, "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fsqrt_q, "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fsqrt_s, "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) +OP(fsrm, "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1) +OP(fsrmi, "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm) +OP(fsub_d, "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsub_q, "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsub_s, "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) +OP(fsw, "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1) +OP(hret, "hret", rv_codec_none, rv_fmt_none) +OP(illegal, "illegal", rv_codec_none, rv_fmt_none) +OP(j, "j", rv_codec_illegal, rv_fmt_offset) +OP(jal, "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal) +OP(jal_ra, "jal", rv_codec_illegal, rv_fmt_offset) +OP(jalr, "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr) +OP(jalr_ra, "jalr", rv_codec_illegal, rv_fmt_rs1) +OP(jr, "jr", rv_codec_illegal, rv_fmt_rs1, rvcp_jr) +OP(lb, "lb", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lbu, "lbu", rv_codec_i, rv_fmt_rd_offset_rs1) OP(ld, "ld", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(sd, "sd", rv_codec_s, rv_fmt_rs2_offset_rs1) -OP(addiw, "addiw", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_addiw) -OP(slliw, "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) -OP(srliw, "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) -OP(sraiw, "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) -OP(addw, "addw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(subw, "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw) -OP(sllw, "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(srlw, "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sraw, "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(ldu, "ldu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lh, "lh", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lhu, "lhu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lpad, "lpad", rv_codec_lp, rv_fmt_imm) OP(lq, "lq", rv_codec_i, rv_fmt_rd_offset_rs1) -OP(sq, "sq", rv_codec_s, rv_fmt_rs2_offset_rs1) -OP(addid, "addid", rv_codec_i, rv_fmt_rd_rs1_imm) -OP(sllid, "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) -OP(srlid, "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) -OP(sraid, "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) -OP(addd, "addd", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(subd, "subd", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(slld, "slld", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(srld, "srld", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(srad, "srad", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(lr_d, "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(lr_q, "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(lr_w, "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) +OP(lui, "lui", rv_codec_u, rv_fmt_rd_uimm) +OP(lw, "lw", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(lwu, "lwu", rv_codec_i, rv_fmt_rd_offset_rs1) +OP(max, "max", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(maxu, "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(min, "min", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(minu, "minu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(mnret, "mnret", rv_codec_none, rv_fmt_none) +OP(mop_r, "mop.r", rv_codec_mop_r, rv_fmt_mop_r) +OP(mop_rr, "mop.rr", rv_codec_mop_rr, rv_fmt_mop_rr) +OP(mret, "mret", rv_codec_none, rv_fmt_none) OP(mul, "mul", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(muld, "muld", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mulh, "mulh", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mulhsu, "mulhsu", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mulhu, "mulhu", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(div, "div", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(divu, "divu", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(rem, "rem", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(remu, "remu", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(mulw, "mulw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(divw, "divw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(divuw, "divuw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(remw, "remw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(remuw, "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(muld, "muld", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(divd, "divd", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(divud, "divud", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(remd, "remd", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(remud, "remud", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(lr_w, "lr.w", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) -OP(sc_w, "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoswap_w, "amoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoadd_w, "amoadd.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoxor_w, "amoxor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoor_w, "amoor.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoand_w, "amoand.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomin_w, "amomin.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomax_w, "amomax.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amominu_w, "amominu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomaxu_w, "amomaxu.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(lr_d, "lr.d", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) -OP(sc_d, "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoswap_d, "amoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoadd_d, "amoadd.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoxor_d, "amoxor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoor_d, "amoor.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoand_d, "amoand.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomin_d, "amomin.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomax_d, "amomax.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amominu_d, "amominu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomaxu_d, "amomaxu.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(lr_q, "lr.q", rv_codec_r_l, rv_fmt_aqrl_rd_rs1) -OP(sc_q, "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoswap_q, "amoswap.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoadd_q, "amoadd.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoxor_q, "amoxor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoor_q, "amoor.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoand_q, "amoand.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomin_q, "amomin.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomax_q, "amomax.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amominu_q, "amominu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomaxu_q, "amomaxu.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(ecall, "ecall", rv_codec_none, rv_fmt_none) -OP(ebreak, "ebreak", rv_codec_none, rv_fmt_none) -OP(uret, "uret", rv_codec_none, rv_fmt_none) -OP(sret, "sret", rv_codec_none, rv_fmt_none) -OP(hret, "hret", rv_codec_none, rv_fmt_none) -OP(mret, "mret", rv_codec_none, rv_fmt_none) -OP(dret, "dret", rv_codec_none, rv_fmt_none) -OP(sfence_vm, "sfence.vm", rv_codec_r, rv_fmt_rs1) -OP(sfence_vma, "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2) -OP(wfi, "wfi", rv_codec_none, rv_fmt_none) -OP(csrrw, "csrrw", rv_codec_i_csr, rv_fmt_rd_csr_rs1) -OP(csrrs, "csrrs", rv_codec_i_csr, rv_fmt_rd_csr_rs1) -OP(csrrc, "csrrc", rv_codec_i_csr, rv_fmt_rd_csr_rs1) -OP(csrrwi, "csrrwi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) -OP(csrrsi, "csrrsi", rv_codec_i_csr, rv_fmt_rd_csr_zimm) -OP(csrrci, "csrrci", rv_codec_i_csr, rv_fmt_rd_csr_zimm) -OP(flw, "flw", rv_codec_i, rv_fmt_frd_offset_rs1) -OP(fsw, "fsw", rv_codec_s, rv_fmt_frs2_offset_rs1) -OP(fmadd_s, "fmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fmsub_s, "fmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmsub_s, "fnmsub.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmadd_s, "fnmadd.s", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fadd_s, "fadd.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsub_s, "fsub.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fmul_s, "fmul.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fdiv_s, "fdiv.s", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsgnj_s, "fsgnj.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_s) -OP(fsgnjn_s, "fsgnjn.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_s) -OP(fsgnjx_s, "fsgnjx.s", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_s) -OP(fmin_s, "fmin.s", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmax_s, "fmax.s", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fsqrt_s, "fsqrt.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fle_s, "fle.s", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(flt_s, "flt.s", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(feq_s, "feq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fcvt_w_s, "fcvt.w.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_wu_s, "fcvt.wu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_s_w, "fcvt.s.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_s_wu, "fcvt.s.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fmv_x_s, "fmv.x.s", rv_codec_r, rv_fmt_rd_frs1) -OP(fclass_s, "fclass.s", rv_codec_r, rv_fmt_rd_frs1) -OP(fmv_s_x, "fmv.s.x", rv_codec_r, rv_fmt_frd_rs1) -OP(fcvt_l_s, "fcvt.l.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_lu_s, "fcvt.lu.s", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_s_l, "fcvt.s.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_s_lu, "fcvt.s.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fld, "fld", rv_codec_i, rv_fmt_frd_offset_rs1) -OP(fsd, "fsd", rv_codec_s, rv_fmt_frs2_offset_rs1) -OP(fmadd_d, "fmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fmsub_d, "fmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmsub_d, "fnmsub.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmadd_d, "fnmadd.d", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fadd_d, "fadd.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsub_d, "fsub.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fmul_d, "fmul.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fdiv_d, "fdiv.d", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsgnj_d, "fsgnj.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_d) -OP(fsgnjn_d, "fsgnjn.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_d) -OP(fsgnjx_d, "fsgnjx.d", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_d) -OP(fmin_d, "fmin.d", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmax_d, "fmax.d", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fcvt_s_d, "fcvt.s.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvt_d_s, "fcvt.d.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fsqrt_d, "fsqrt.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fle_d, "fle.d", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(flt_d, "flt.d", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(feq_d, "feq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fcvt_w_d, "fcvt.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_wu_d, "fcvt.wu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_d_w, "fcvt.d.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_d_wu, "fcvt.d.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fclass_d, "fclass.d", rv_codec_r, rv_fmt_rd_frs1) -OP(fcvt_l_d, "fcvt.l.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_lu_d, "fcvt.lu.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fmv_x_d, "fmv.x.d", rv_codec_r, rv_fmt_rd_frs1) -OP(fcvt_d_l, "fcvt.d.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_d_lu, "fcvt.d.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fmv_d_x, "fmv.d.x", rv_codec_r, rv_fmt_frd_rs1) -OP(flq, "flq", rv_codec_i, rv_fmt_frd_offset_rs1) -OP(fsq, "fsq", rv_codec_s, rv_fmt_frs2_offset_rs1) -OP(fmadd_q, "fmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fmsub_q, "fmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmsub_q, "fnmsub.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fnmadd_q, "fnmadd.q", rv_codec_r4_m, rv_fmt_rm_frd_frs1_frs2_frs3) -OP(fadd_q, "fadd.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsub_q, "fsub.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fmul_q, "fmul.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fdiv_q, "fdiv.q", rv_codec_r_m, rv_fmt_rm_frd_frs1_frs2) -OP(fsgnj_q, "fsgnj.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnj_q) -OP(fsgnjn_q, "fsgnjn.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjn_q) -OP(fsgnjx_q, "fsgnjx.q", rv_codec_r, rv_fmt_frd_frs1_frs2, rvcp_fsgnjx_q) -OP(fmin_q, "fmin.q", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmax_q, "fmax.q", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fcvt_s_q, "fcvt.s.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvt_q_s, "fcvt.q.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvt_d_q, "fcvt.d.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvt_q_d, "fcvt.q.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fsqrt_q, "fsqrt.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fle_q, "fle.q", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(flt_q, "flt.q", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(feq_q, "feq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fcvt_w_q, "fcvt.w.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_wu_q, "fcvt.wu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_q_w, "fcvt.q.w", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_q_wu, "fcvt.q.wu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fclass_q, "fclass.q", rv_codec_r, rv_fmt_rd_frs1) -OP(fcvt_l_q, "fcvt.l.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_lu_q, "fcvt.lu.q", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fcvt_q_l, "fcvt.q.l", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fcvt_q_lu, "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1) -OP(fmv_x_q, "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1) -OP(fmv_q_x, "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1) -OP(c_addi4spn, "c.addi4spn", rv_codec_ciw_4spn, NULL, DECOMP(op_addi)) -OP(c_fld, "c.fld", rv_codec_cl_ld, NULL, DECOMP(op_fld)) -OP(c_lw, "c.lw", rv_codec_cl_lw, NULL, DECOMP(op_lw)) -OP(c_flw, "c.flw", rv_codec_cl_lw, NULL, DECOMP(op_flw)) -OP(c_fsd, "c.fsd", rv_codec_cs_sd, NULL, DECOMP(op_fsd)) -OP(c_sw, "c.sw", rv_codec_cs_sw, NULL, DECOMP(op_sw)) -OP(c_fsw, "c.fsw", rv_codec_cs_sw, NULL, DECOMP(op_fsw)) -OP(c_addi, "c.addi", rv_codec_ci, NULL, DECOMP(op_addi)) -OP(c_jal, "c.jal", rv_codec_cj_jal, NULL, DECOMP(op_jal)) -OP(c_li, "c.li", rv_codec_ci_li, NULL, DECOMP(op_addi)) -OP(c_addi16sp, "c.addi16sp", rv_codec_ci_16sp, NULL, DECOMP(op_addi)) -OP(c_lui, "c.lui", rv_codec_ci_lui, NULL, DECOMP(op_lui)) -OP(c_srli, "c.srli", rv_codec_cb_sh6, NULL, DECOMP(op_srli)) -OP(c_srai, "c.srai", rv_codec_cb_sh6, NULL, DECOMP(op_srai)) -OP(c_andi, "c.andi", rv_codec_cb_imm, NULL, DECOMP(op_andi)) -OP(c_sub, "c.sub", rv_codec_cs, NULL, DECOMP(op_sub)) -OP(c_xor, "c.xor", rv_codec_cs, NULL, DECOMP(op_xor)) -OP(c_or, "c.or", rv_codec_cs, NULL, DECOMP(op_or)) -OP(c_and, "c.and", rv_codec_cs, NULL, DECOMP(op_and)) -OP(c_subw, "c.subw", rv_codec_cs, NULL, DECOMP(op_subw)) -OP(c_addw, "c.addw", rv_codec_cs, NULL, DECOMP(op_addw)) -OP(c_j, "c.j", rv_codec_cj, NULL, DECOMP(op_j)) -OP(c_beqz, "c.beqz", rv_codec_cb, NULL, DECOMP(op_beqz)) -OP(c_bnez, "c.bnez", rv_codec_cb, NULL, DECOMP(op_bnez)) -OP(c_slli, "c.slli", rv_codec_ci_sh6, NULL, DECOMP(op_slli)) -OP(c_fldsp, "c.fldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_fld)) -OP(c_lwsp, "c.lwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_lw)) -OP(c_flwsp, "c.flwsp", rv_codec_ci_lwsp, NULL, DECOMP(op_flw)) -OP(c_jr, "c.jr", rv_codec_cr_jr, NULL, DECOMP(op_jr)) -OP(c_mv, "c.mv", rv_codec_cr_mv, NULL, DECOMP(op_mv)) -OP(c_ebreak, "c.ebreak", rv_codec_ci_none, NULL, DECOMP(op_ebreak)) -OP(c_jalr, "c.jalr", rv_codec_cr_jalr, NULL, DECOMP(op_jalr)) -OP(c_add, "c.add", rv_codec_cr, NULL, DECOMP(op_add)) -OP(c_fsdsp, "c.fsdsp", rv_codec_css_sdsp, NULL, DECOMP(op_fsd)) -OP(c_swsp, "c.swsp", rv_codec_css_swsp, NULL, DECOMP(op_sw)) -OP(c_fswsp, "c.fswsp", rv_codec_css_swsp, NULL, DECOMP(op_fsw)) -OP(c_ld, "c.ld", rv_codec_cl_ld, NULL, DECOMP(op_ld)) -OP(c_sd, "c.sd", rv_codec_cs_sd, NULL, DECOMP(op_sd)) -OP(c_addiw, "c.addiw", rv_codec_ci, NULL, DECOMP(op_addiw)) -OP(c_ldsp, "c.ldsp", rv_codec_ci_ldsp, NULL, DECOMP(op_ld)) -OP(c_sdsp, "c.sdsp", rv_codec_css_sdsp, NULL, DECOMP(op_sd)) -OP(c_lq, "c.lq", rv_codec_cl_lq, NULL, DECOMP(op_lq)) -OP(c_sq, "c.sq", rv_codec_cs_sq, NULL, DECOMP(op_sq)) -OP(c_lqsp, "c.lqsp", rv_codec_ci_lqsp, NULL, DECOMP(op_lq)) -OP(c_sqsp, "c.sqsp", rv_codec_css_sqsp, NULL, DECOMP(op_sq)) -OP(nop, "nop", rv_codec_illegal, rv_fmt_none) OP(mv, "mv", rv_codec_illegal, rv_fmt_rd_rs1, rvcp_mv) -OP(not, "not", rv_codec_illegal, rv_fmt_rd_rs1) OP(neg, "neg", rv_codec_illegal, rv_fmt_rd_rs2) OP(negw, "negw", rv_codec_illegal, rv_fmt_rd_rs2) -OP(sext_w, "sext.w", rv_codec_illegal, rv_fmt_rd_rs1) -OP(seqz, "seqz", rv_codec_illegal, rv_fmt_rd_rs1) -OP(snez, "snez", rv_codec_illegal, rv_fmt_rd_rs2) -OP(sltz, "sltz", rv_codec_illegal, rv_fmt_rd_rs1) -OP(sgtz, "sgtz", rv_codec_illegal, rv_fmt_rd_rs2) -OP(fmv_s, "fmv.s", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fabs_s, "fabs.s", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fneg_s, "fneg.s", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fmv_d, "fmv.d", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fabs_d, "fabs.d", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fneg_d, "fneg.d", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fmv_q, "fmv.q", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fabs_q, "fabs.q", rv_codec_illegal, rv_fmt_frd_frs1) -OP(fneg_q, "fneg.q", rv_codec_illegal, rv_fmt_frd_frs1) -OP(beqz, "beqz", rv_codec_illegal, rv_fmt_rs1_offset) -OP(bnez, "bnez", rv_codec_illegal, rv_fmt_rs1_offset) -OP(blez, "blez", rv_codec_illegal, rv_fmt_rs2_offset) -OP(bgez, "bgez", rv_codec_illegal, rv_fmt_rs1_offset) -OP(bltz, "bltz", rv_codec_illegal, rv_fmt_rs1_offset) -OP(bgtz, "bgtz", rv_codec_illegal, rv_fmt_rs2_offset) -OP(jal_ra, "jal", rv_codec_illegal, rv_fmt_offset) -OP(jalr_ra, "jalr", rv_codec_illegal, rv_fmt_rs1) -OP(j, "j", rv_codec_illegal, rv_fmt_offset) -OP(ret, "ret", rv_codec_illegal, rv_fmt_none) -OP(jr, "jr", rv_codec_illegal, rv_fmt_rs1, rvcp_jr) -OP(rdcycle, "rdcycle", rv_codec_i_csr, rv_fmt_rd) -OP(rdtime, "rdtime", rv_codec_i_csr, rv_fmt_rd) -OP(rdinstret, "rdinstret", rv_codec_i_csr, rv_fmt_rd) -OP(rdcycleh, "rdcycleh", rv_codec_i_csr, rv_fmt_rd) -OP(rdtimeh, "rdtimeh", rv_codec_i_csr, rv_fmt_rd) -OP(rdinstreth, "rdinstreth", rv_codec_i_csr, rv_fmt_rd) -OP(frcsr, "frcsr", rv_codec_i_csr, rv_fmt_rd) -OP(frrm, "frrm", rv_codec_i_csr, rv_fmt_rd) -OP(frflags, "frflags", rv_codec_i_csr, rv_fmt_rd) -OP(fscsr, "fscsr", rv_codec_i_csr, rv_fmt_rd_rs1) -OP(fsrm, "fsrm", rv_codec_i_csr, rv_fmt_rd_rs1) -OP(fsflags, "fsflags", rv_codec_i_csr, rv_fmt_rd_rs1) -OP(fsrmi, "fsrmi", rv_codec_i_csr, rv_fmt_rd_zimm) -OP(fsflagsi, "fsflagsi", rv_codec_i_csr, rv_fmt_rd_zimm) -OP(bseti, "bseti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(bclri, "bclri", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(binvi, "binvi", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(bexti, "bexti", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(rori, "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) -OP(clz, "clz", rv_codec_r, rv_fmt_rd_rs1) -OP(ctz, "ctz", rv_codec_r, rv_fmt_rd_rs1) -OP(cpop, "cpop", rv_codec_r, rv_fmt_rd_rs1) -OP(sext_h, "sext.h", rv_codec_r, rv_fmt_rd_rs1) -OP(sext_b, "sext.b", rv_codec_r, rv_fmt_rd_rs1) -OP(xnor, "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(orn, "orn", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(andn, "andn", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(rol, "rol", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(ror, "ror", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh1add, "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh2add, "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh3add, "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh1add_uw, "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh2add_uw, "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sh3add_uw, "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(clmul, "clmul", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(clmulr, "clmulr", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(clmulh, "clmulh", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(min, "min", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(minu, "minu", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(max, "max", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(maxu, "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(clzw, "clzw", rv_codec_r, rv_fmt_rd_rs1) -OP(ctzw, "ctzw", rv_codec_r, rv_fmt_rd_rs1) -OP(cpopw, "cpopw", rv_codec_r, rv_fmt_rd_rs1) -OP(slli_uw, "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) -OP(add_uw, "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(rolw, "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(rorw, "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(rev8, "rev8", rv_codec_r, rv_fmt_rd_rs1) -OP(zext_h, "zext.h", rv_codec_r, rv_fmt_rd_rs1) -OP(roriw, "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(nop, "nop", rv_codec_illegal, rv_fmt_none) +OP(not, "not", rv_codec_illegal, rv_fmt_rd_rs1) +OP(or, "or", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(orc_b, "orc.b", rv_codec_r, rv_fmt_rd_rs1) -OP(bset, "bset", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(bclr, "bclr", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(binv, "binv", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(bext, "bext", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(aes32esmi, "aes32esmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) -OP(aes32esi, "aes32esi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) -OP(aes32dsmi, "aes32dsmi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) -OP(aes32dsi, "aes32dsi", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) -OP(aes64ks1i, "aes64ks1i", rv_codec_k_rnum, rv_fmt_rd_rs1_rnum) -OP(aes64ks2, "aes64ks2", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(aes64im, "aes64im", rv_codec_r, rv_fmt_rd_rs1) -OP(aes64esm, "aes64esm", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(aes64es, "aes64es", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(aes64dsm, "aes64dsm", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(aes64ds, "aes64ds", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ori, "ori", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(orn, "orn", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(pack, "pack", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(packh, "packh", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(packw, "packw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rdcycle, "rdcycle", rv_codec_i_csr, rv_fmt_rd) +OP(rdcycleh, "rdcycleh", rv_codec_i_csr, rv_fmt_rd) +OP(rdinstret, "rdinstret", rv_codec_i_csr, rv_fmt_rd) +OP(rdinstreth, "rdinstreth", rv_codec_i_csr, rv_fmt_rd) +OP(rdtime, "rdtime", rv_codec_i_csr, rv_fmt_rd) +OP(rdtimeh, "rdtimeh", rv_codec_i_csr, rv_fmt_rd) +OP(rem, "rem", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remd, "remd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remu, "remu", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remud, "remud", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remuw, "remuw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(remw, "remw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ret, "ret", rv_codec_illegal, rv_fmt_none) +OP(rev8, "rev8", rv_codec_r, rv_fmt_rd_rs1) +OP(rol, "rol", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rolw, "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ror, "ror", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(rori, "rori", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(roriw, "roriw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(rorw, "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sb, "sb", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(sc_d, "sc.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(sc_q, "sc.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(sc_w, "sc.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(sd, "sd", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(seqz, "seqz", rv_codec_illegal, rv_fmt_rd_rs1) +OP(sext_b, "sext.b", rv_codec_r, rv_fmt_rd_rs1) +OP(sext_h, "sext.h", rv_codec_r, rv_fmt_rd_rs1) +OP(sext_w, "sext.w", rv_codec_illegal, rv_fmt_rd_rs1) +OP(sfence_vm, "sfence.vm", rv_codec_r, rv_fmt_rs1) +OP(sfence_vma, "sfence.vma", rv_codec_r, rv_fmt_rs1_rs2) +OP(sgtz, "sgtz", rv_codec_illegal, rv_fmt_rd_rs2) +OP(sh, "sh", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(sh1add, "sh1add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh1add_uw, "sh1add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh2add, "sh2add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh2add_uw, "sh2add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh3add, "sh3add", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sh3add_uw, "sh3add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(sha256sig0, "sha256sig0", rv_codec_r, rv_fmt_rd_rs1) OP(sha256sig1, "sha256sig1", rv_codec_r, rv_fmt_rd_rs1) OP(sha256sum0, "sha256sum0", rv_codec_r, rv_fmt_rd_rs1) OP(sha256sum1, "sha256sum1", rv_codec_r, rv_fmt_rd_rs1) OP(sha512sig0, "sha512sig0", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sig1, "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sum0, "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sum1, "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sum0r, "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sum1r, "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sig0l, "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(sha512sig0h, "sha512sig0h", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(sha512sig1l, "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig0l, "sha512sig0l", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig1, "sha512sig1", rv_codec_r, rv_fmt_rd_rs1_rs2) OP(sha512sig1h, "sha512sig1h", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sig1l, "sha512sig1l", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum0, "sha512sum0", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum0r, "sha512sum0r", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum1, "sha512sum1", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sha512sum1r, "sha512sum1r", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sll, "sll", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(slld, "slld", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(slli, "slli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(slli_uw, "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(sllid, "sllid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(slliw, "slliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(sllw, "sllw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(slt, "slt", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_slt) +OP(slti, "slti", rv_codec_i, rv_fmt_rd_rs1_imm) +OP(sltiu, "sltiu", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_sltiu) +OP(sltu, "sltu", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sltu) +OP(sltz, "sltz", rv_codec_illegal, rv_fmt_rd_rs1) OP(sm3p0, "sm3p0", rv_codec_r, rv_fmt_rd_rs1) OP(sm3p1, "sm3p1", rv_codec_r, rv_fmt_rd_rs1) OP(sm4ed, "sm4ed", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) OP(sm4ks, "sm4ks", rv_codec_k_bs, rv_fmt_rs1_rs2_bs) -OP(brev8, "brev8", rv_codec_r, rv_fmt_rd_rs1) -OP(pack, "pack", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(packh, "packh", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(packw, "packw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(snez, "snez", rv_codec_illegal, rv_fmt_rd_rs2) +OP(sq, "sq", rv_codec_s, rv_fmt_rs2_offset_rs1) +OP(sra, "sra", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srad, "srad", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srai, "srai", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(sraid, "sraid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(sraiw, "sraiw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(sraw, "sraw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(sret, "sret", rv_codec_none, rv_fmt_none) +OP(srl, "srl", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srld, "srld", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(srli, "srli", rv_codec_i_sh7, rv_fmt_rd_rs1_imm) +OP(srlid, "srlid", rv_codec_i_sh6, rv_fmt_rd_rs1_imm) +OP(srliw, "srliw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm) +OP(srlw, "srlw", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(ssamoswap_d, "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(ssamoswap_w, "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) +OP(sspopchk, "sspopchk", rv_codec_r, rv_fmt_rs1) +OP(sspush, "sspush", rv_codec_r, rv_fmt_rs2) +OP(ssrdp, "ssrdp", rv_codec_r, rv_fmt_rd) +OP(sub, "sub", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_sub) +OP(subd, "subd", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(subw, "subw", rv_codec_r, rv_fmt_rd_rs1_rs2, rvcp_subw) +OP(sw, "sw", rv_codec_s, rv_fmt_rs2_offset_rs1) OP(unzip, "unzip", rv_codec_r, rv_fmt_rd_rs1) -OP(zip, "zip", rv_codec_r, rv_fmt_rd_rs1) -OP(xperm4, "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(xperm8, "xperm8", rv_codec_r, rv_fmt_rd_rs1) -OP(vle8_v, "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle16_v, "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle32_v, "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle64_v, "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vse8_v, "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vse16_v, "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vse32_v, "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vse64_v, "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vlm_v, "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vsm_v, "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vlse8_v, "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vlse16_v, "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vlse32_v, "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vlse64_v, "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vsse8_v, "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vsse16_v, "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vsse32_v, "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vsse64_v, "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) -OP(vluxei8_v, "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vluxei16_v, "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vluxei32_v, "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vluxei64_v, "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vloxei8_v, "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vloxei16_v, "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vloxei32_v, "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vloxei64_v, "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsuxei16_v, "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsoxei8_v, "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsoxei16_v, "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsoxei32_v, "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vsoxei64_v, "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) -OP(vle8ff_v, "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle16ff_v, "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle32ff_v, "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vle64ff_v, "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl1re8_v, "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl1re16_v, "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl1re32_v, "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl1re64_v, "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl2re8_v, "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl2re16_v, "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl2re32_v, "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl2re64_v, "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl4re8_v, "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl4re16_v, "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl4re32_v, "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl4re64_v, "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl8re8_v, "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl8re16_v, "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl8re32_v, "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vl8re64_v, "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vs1r_v, "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vs2r_v, "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vs4r_v, "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vs8r_v, "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) -OP(vadd_vv, "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vadd_vx, "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vadd_vi, "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vsub_vv, "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsub_vx, "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vrsub_vx, "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vrsub_vi, "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vwaddu_vv, "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwaddu_vx, "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwsubu_vv, "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwsubu_vx, "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwsub_vv, "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwsub_vx, "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwaddu_wv, "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwaddu_wx, "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwadd_wx, "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwsubu_wv, "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwsubu_wx, "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwsub_wv, "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwsub_wx, "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) -OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) -OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) -OP(vmadc_vvm, "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) -OP(vmadc_vxm, "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) -OP(vmadc_vim, "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) -OP(vsbc_vvm, "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) -OP(vsbc_vxm, "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) -OP(vmsbc_vvm, "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) -OP(vmsbc_vxm, "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) -OP(vand_vv, "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vand_vx, "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vand_vi, "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vor_vv, "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vor_vx, "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vor_vi, "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vxor_vv, "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vxor_vx, "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vxor_vi, "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vsll_vv, "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsll_vx, "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsll_vi, "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vsrl_vv, "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsrl_vx, "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsrl_vi, "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vsra_vv, "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsra_vx, "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsra_vi, "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vnsrl_wv, "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vnsrl_wx, "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vnsrl_wi, "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vnsra_wv, "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vnsra_wx, "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vnsra_wi, "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vmseq_vv, "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmseq_vx, "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmseq_vi, "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vmsne_vv, "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmsne_vx, "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsne_vi, "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vmsltu_vv, "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmsltu_vx, "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmslt_vv, "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmslt_vx, "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsleu_vv, "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmsleu_vx, "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsleu_vi, "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vmsle_vv, "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmsle_vx, "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsle_vi, "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vmsgtu_vx, "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsgtu_vi, "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vmsgt_vx, "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmsgt_vi, "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vminu_vv, "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vminu_vx, "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmin_vv, "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmin_vx, "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmaxu_vv, "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmaxu_vx, "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmax_vv, "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmax_vx, "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmul_vv, "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmul_vx, "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmulh_vv, "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmulh_vx, "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmulhu_vv, "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmulhu_vx, "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmulhsu_vv, "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmulhsu_vx, "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vdivu_vv, "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vdivu_vx, "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vdiv_vv, "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vdiv_vx, "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vremu_vv, "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vremu_vx, "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vrem_vv, "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vrem_vx, "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwmulu_vv, "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwmulu_vx, "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwmulsu_vv, "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwmulsu_vx, "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwmul_vv, "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwmul_vx, "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vmacc_vv, "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vmacc_vx, "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vnmsac_vv, "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vnmsac_vx, "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vmadd_vv, "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vmadd_vx, "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vnmsub_vv, "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vnmsub_vx, "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vwmaccu_vv, "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vwmaccu_vx, "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vwmacc_vv, "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vwmacc_vx, "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vwmaccsu_vv, "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vwmaccsu_vx, "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vwmaccus_vx, "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) -OP(vmv_v_v, "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1) -OP(vmv_v_x, "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1) -OP(vmv_v_i, "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm) -OP(vmerge_vvm, "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) -OP(vmerge_vxm, "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) -OP(vmerge_vim, "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) -OP(vsaddu_vv, "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsaddu_vx, "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsaddu_vi, "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vsadd_vv, "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsadd_vx, "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsadd_vi, "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) -OP(vssubu_vv, "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vssubu_vx, "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vssub_vv, "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vssub_vx, "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(uret, "uret", rv_codec_none, rv_fmt_none) OP(vaadd_vv, "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vaadd_vx, "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vaaddu_vv, "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vaaddu_vx, "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vadd_vi, "vadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vadd_vv, "vadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vadd_vx, "vadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vaesdf_vs, "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdf_vv, "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdm_vs, "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesdm_vv, "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesef_vs, "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesef_vv, "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesem_vs, "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaesem_vv, "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vaeskf1_vi, "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vaeskf2_vi, "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) +OP(vaesz_vs, "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vand_vi, "vand.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vand_vv, "vand.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vand_vx, "vand.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vandn_vv, "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vandn_vx, "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vasub_vv, "vasub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vasub_vx, "vasub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vasubu_vv, "vasubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vasubu_vx, "vasubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vsmul_vv, "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vsmul_vx, "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vssrl_vv, "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vssrl_vx, "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vssrl_vi, "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vssra_vv, "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vssra_vx, "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vssra_vi, "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vnclipu_wv, "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vnclipu_wx, "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vnclipu_wi, "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vnclip_wv, "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vnclip_wx, "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vnclip_wi, "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vfadd_vv, "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfadd_vf, "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfsub_vv, "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfsub_vf, "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfrsub_vf, "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfwadd_vv, "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwadd_vf, "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfwadd_wv, "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwadd_wf, "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfwsub_vv, "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwsub_vf, "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfwsub_wv, "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwsub_wf, "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfmul_vv, "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfmul_vf, "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfdiv_vv, "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfdiv_vf, "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfrdiv_vf, "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfwmul_vv, "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwmul_vf, "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfmacc_vv, "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfmacc_vf, "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfnmacc_vv, "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfnmacc_vf, "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfmsac_vv, "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfmsac_vf, "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfnmsac_vv, "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfnmsac_vf, "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfmadd_vv, "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfmadd_vf, "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfnmadd_vv, "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfnmadd_vf, "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfmsub_vv, "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfmsub_vf, "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfnmsub_vv, "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfnmsub_vf, "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfwmacc_vv, "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfwmacc_vf, "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfwnmacc_vv, "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfwnmacc_vf, "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfwmsac_vv, "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfwmsac_vf, "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfwnmsac_vv, "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfwnmsac_vf, "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(vfsqrt_v, "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vfrsqrt7_v, "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vfrec7_v, "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vfmin_vv, "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfmin_vf, "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfmax_vv, "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfmax_vf, "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfsgnj_vv, "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfsgnj_vf, "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfsgnjn_vv, "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfsgnjn_vf, "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfsgnjx_vv, "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfsgnjx_vf, "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfslide1up_vf, "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfslide1down_vf, "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmfeq_vv, "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmfeq_vf, "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmfne_vv, "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmfne_vf, "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmflt_vv, "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmflt_vf, "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmfle_vv, "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmfle_vf, "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmfgt_vf, "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vmfge_vf, "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) -OP(vfclass_v, "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfmerge_vfm, "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl) -OP(vfmv_v_f, "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1) -OP(vfcvt_xu_f_v, "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfcvt_x_f_v, "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfcvt_f_xu_v, "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfcvt_f_x_v, "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfcvt_rtz_xu_f_v, "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfcvt_rtz_x_f_v, "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_xu_f_v, "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_x_f_v, "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_f_xu_v, "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_f_x_v, "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_f_f_v, "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_rtz_xu_f_v, "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvt_rtz_x_f_v, "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_xu_f_w, "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_x_f_w, "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_f_xu_w, "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_f_x_w, "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_f_f_w, "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_rod_f_f_w, "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_rtz_xu_f_w, "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfncvt_rtz_x_f_w, "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vredsum_vs, "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredand_vs, "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredor_vs, "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredxor_vs, "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredminu_vs, "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredmin_vs, "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredmaxu_vs, "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vredmax_vs, "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwredsumu_vs, "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vwredsum_vs, "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfredusum_vs, "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfredosum_vs, "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfredmin_vs, "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfredmax_vs, "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwredusum_vs, "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vfwredosum_vs, "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmand_mm, "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmnand_mm, "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmandn_mm, "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmxor_mm, "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmor_mm, "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmnor_mm, "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmorn_mm, "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vmxnor_mm, "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vcpop_m, "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) -OP(vfirst_m, "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) -OP(vmsbf_m, "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vmsif_m, "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vmsof_m, "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(viota_m, "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vid_v, "vid.v", rv_codec_v_r, rv_fmt_vd_vm) -OP(vmv_x_s, "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2) -OP(vmv_s_x, "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1) -OP(vfmv_f_s, "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2) -OP(vfmv_s_f, "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1) -OP(vslideup_vx, "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vslideup_vi, "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vslide1up_vx, "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vslidedown_vx, "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vslidedown_vi, "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vslide1down_vx, "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vrgather_vv, "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vrgatherei16_vv, "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vrgather_vx, "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vrgather_vi, "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(vcompress_vm, "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1) -OP(vmv1r_v, "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vmv2r_v, "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vmv4r_v, "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vmv8r_v, "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vzext_vf2, "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vzext_vf4, "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vzext_vf8, "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vsext_vf2, "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vsext_vf4, "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vsext_vf8, "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vsetvli, "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli) -OP(vsetivli, "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli) -OP(vsetvl, "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(c_zext_b, "c.zext.b", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_sext_b, "c.sext.b", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_zext_h, "c.zext.h", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_sext_h, "c.sext.h", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_zext_w, "c.zext.w", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_not, "c.not", rv_codec_zcb_ext, rv_fmt_rd) -OP(c_mul, "c.mul", rv_codec_zcb_mul, rv_fmt_rd_rs2) -OP(c_lbu, "c.lbu", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) -OP(c_lhu, "c.lhu", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) -OP(c_lh, "c.lh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) -OP(c_sb, "c.sb", rv_codec_zcb_lb, rv_fmt_rs1_rs2_zce_ldst) -OP(c_sh, "c.sh", rv_codec_zcb_lh, rv_fmt_rs1_rs2_zce_ldst) -OP(cm_push, "cm.push", rv_codec_zcmp_cm_pushpop, rv_fmt_push_rlist) -OP(cm_pop, "cm.pop", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) -OP(cm_popret, "cm.popret", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) -OP(cm_popretz, "cm.popretz", rv_codec_zcmp_cm_pushpop, rv_fmt_pop_rlist) -OP(cm_mva01s, "cm.mva01s", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) -OP(cm_mvsa01, "cm.mvsa01", rv_codec_zcmp_cm_mv, rv_fmt_rd_rs2) -OP(cm_jt, "cm.jt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) -OP(cm_jalt, "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index) -OP(czero_eqz, "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(czero_nez, "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2) -OP(fcvt_bf16_s, "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvt_s_bf16, "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(vfncvtbf16_f_f_w, "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwcvtbf16_f_f_v, "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) -OP(vfwmaccbf16_vv, "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) -OP(vfwmaccbf16_vf, "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) -OP(flh, "flh", rv_codec_i, rv_fmt_frd_offset_rs1) -OP(fsh, "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1) -OP(fmv_h_x, "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1) -OP(fmv_x_h, "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1) -OP(fli_s, "fli.s", rv_codec_fli, rv_fmt_fli) -OP(fli_d, "fli.d", rv_codec_fli, rv_fmt_fli) -OP(fli_q, "fli.q", rv_codec_fli, rv_fmt_fli) -OP(fli_h, "fli.h", rv_codec_fli, rv_fmt_fli) -OP(fminm_s, "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmaxm_s, "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fminm_d, "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmaxm_d, "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fminm_q, "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmaxm_q, "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fminm_h, "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fmaxm_h, "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2) -OP(fround_s, "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(froundnx_s, "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fround_d, "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(froundnx_d, "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fround_q, "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(froundnx_q, "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fround_h, "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(froundnx_h, "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1) -OP(fcvtmod_w_d, "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1) -OP(fmvh_x_d, "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1) -OP(fmvp_d_x, "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2) -OP(fmvh_x_q, "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1) -OP(fmvp_q_x, "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2) -OP(fleq_s, "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fltq_s, "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fleq_d, "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fltq_d, "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fleq_q, "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fltq_q, "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fleq_h, "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(fltq_h, "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2) -OP(vaesdf_vv, "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesdf_vs, "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesdm_vv, "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesdm_vs, "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesef_vv, "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesef_vs, "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesem_vv, "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaesem_vs, "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vaeskf1_vi, "vaeskf1.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) -OP(vaeskf2_vi, "vaeskf2.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) -OP(vaesz_vs, "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2) -OP(vandn_vv, "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) -OP(vandn_vx, "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vbrev_v, "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) OP(vbrev8_v, "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vbrev_v, "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) OP(vclmul_vv, "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vclmul_vx, "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vclmulh_vv, "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vclmulh_vx, "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vclz_v, "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vcompress_vm, "vcompress.vm", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vcpop_m, "vcpop.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) OP(vcpop_v, "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) OP(vctz_v, "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vdiv_vv, "vdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vdiv_vx, "vdiv.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vdivu_vv, "vdivu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vdivu_vx, "vdivu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vfadd_vf, "vfadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfadd_vv, "vfadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfclass_v, "vfclass.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_f_x_v, "vfcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_f_xu_v, "vfcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_rtz_x_f_v, "vfcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_rtz_xu_f_v, "vfcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_x_f_v, "vfcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfcvt_xu_f_v, "vfcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfdiv_vf, "vfdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfdiv_vv, "vfdiv.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfirst_m, "vfirst.m", rv_codec_v_r, rv_fmt_rd_vs2_vm) +OP(vfmacc_vf, "vfmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmacc_vv, "vfmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmadd_vf, "vfmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmadd_vv, "vfmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmax_vf, "vfmax.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmax_vv, "vfmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmerge_vfm, "vfmerge.vfm", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vl) +OP(vfmin_vf, "vfmin.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmin_vv, "vfmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmsac_vf, "vfmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmsac_vv, "vfmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmsub_vf, "vfmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfmsub_vv, "vfmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfmul_vf, "vfmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfmul_vv, "vfmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfmv_f_s, "vfmv.f.s", rv_codec_v_r, rv_fmt_fd_vs2) +OP(vfmv_s_f, "vfmv.s.f", rv_codec_v_r, rv_fmt_vd_fs1) +OP(vfmv_v_f, "vfmv.v.f", rv_codec_v_r, rv_fmt_vd_fs1) +OP(vfncvt_f_f_w, "vfncvt.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_f_x_w, "vfncvt.f.x.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_f_xu_w, "vfncvt.f.xu.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rod_f_f_w, "vfncvt.rod.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rtz_x_f_w, "vfncvt.rtz.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_rtz_xu_f_w, "vfncvt.rtz.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_x_f_w, "vfncvt.x.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvt_xu_f_w, "vfncvt.xu.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfncvtbf16_f_f_w, "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfnmacc_vf, "vfnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmacc_vv, "vfnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmadd_vf, "vfnmadd.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmadd_vv, "vfnmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmsac_vf, "vfnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmsac_vv, "vfnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfnmsub_vf, "vfnmsub.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfnmsub_vv, "vfnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfrdiv_vf, "vfrdiv.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfrec7_v, "vfrec7.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfredmax_vs, "vfredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredmin_vs, "vfredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredosum_vs, "vfredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfredusum_vs, "vfredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfrsqrt7_v, "vfrsqrt7.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfrsub_vf, "vfrsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnj_vf, "vfsgnj.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnj_vv, "vfsgnj.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsgnjn_vf, "vfsgnjn.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnjn_vv, "vfsgnjn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfsgnjx_vf, "vfsgnjx.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsgnjx_vv, "vfsgnjx.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfslide1down_vf, "vfslide1down.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfslide1up_vf, "vfslide1up.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsqrt_v, "vfsqrt.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vfsub_vf, "vfsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfsub_vv, "vfsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwadd_vf, "vfwadd.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwadd_vv, "vfwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwadd_wf, "vfwadd.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwadd_wv, "vfwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwcvt_f_f_v, "vfwcvt.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_f_x_v, "vfwcvt.f.x.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_f_xu_v, "vfwcvt.f.xu.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_rtz_x_f_v, "vfwcvt.rtz.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_rtz_xu_f_v, "vfwcvt.rtz.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_x_f_v, "vfwcvt.x.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvt_xu_f_v, "vfwcvt.xu.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwcvtbf16_f_f_v, "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vfwmacc_vf, "vfwmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwmacc_vv, "vfwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmaccbf16_vf, "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwmaccbf16_vv, "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmsac_vf, "vfwmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwmsac_vv, "vfwmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwmul_vf, "vfwmul.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwmul_vv, "vfwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwnmacc_vf, "vfwnmacc.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwnmacc_vv, "vfwnmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwnmsac_vf, "vfwnmsac.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm) +OP(vfwnmsac_vv, "vfwnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vfwredosum_vs, "vfwredosum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwredusum_vs, "vfwredusum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwsub_vf, "vfwsub.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwsub_vv, "vfwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vfwsub_wf, "vfwsub.wf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vfwsub_wv, "vfwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vghsh_vv, "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) OP(vgmul_vv, "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vid_v, "vid.v", rv_codec_v_r, rv_fmt_vd_vm) +OP(viota_m, "viota.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vl1re16_v, "vl1re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re32_v, "vl1re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re64_v, "vl1re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl1re8_v, "vl1re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re16_v, "vl2re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re32_v, "vl2re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re64_v, "vl2re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl2re8_v, "vl2re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re16_v, "vl4re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re32_v, "vl4re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re64_v, "vl4re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl4re8_v, "vl4re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re16_v, "vl8re16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re32_v, "vl8re32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re64_v, "vl8re64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vl8re8_v, "vl8re8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle16_v, "vle16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle16ff_v, "vle16ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle32_v, "vle32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle32ff_v, "vle32ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle64_v, "vle64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle64ff_v, "vle64ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle8_v, "vle8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vle8ff_v, "vle8ff.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vlm_v, "vlm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vloxei16_v, "vloxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei32_v, "vloxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei64_v, "vloxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vloxei8_v, "vloxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vlse16_v, "vlse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse32_v, "vlse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse64_v, "vlse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vlse8_v, "vlse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vluxei16_v, "vluxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei32_v, "vluxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei64_v, "vluxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vluxei8_v, "vluxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vmacc_vv, "vmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vmacc_vx, "vmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vmadc_vim, "vmadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vmadc_vvm, "vmadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmadc_vxm, "vmadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmadd_vv, "vmadd.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vmadd_vx, "vmadd.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vmand_mm, "vmand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmandn_mm, "vmandn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmax_vv, "vmax.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmax_vx, "vmax.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmaxu_vv, "vmaxu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmaxu_vx, "vmaxu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmerge_vim, "vmerge.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) +OP(vmerge_vvm, "vmerge.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmerge_vxm, "vmerge.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmfeq_vf, "vmfeq.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfeq_vv, "vmfeq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmfge_vf, "vmfge.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfgt_vf, "vmfgt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfle_vf, "vmfle.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfle_vv, "vmfle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmflt_vf, "vmflt.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmflt_vv, "vmflt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmfne_vf, "vmfne.vf", rv_codec_v_r, rv_fmt_vd_vs2_fs1_vm) +OP(vmfne_vv, "vmfne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmin_vv, "vmin.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmin_vx, "vmin.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vminu_vv, "vminu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vminu_vx, "vminu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmnand_mm, "vmnand.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmnor_mm, "vmnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmor_mm, "vmor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmorn_mm, "vmorn.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsbc_vvm, "vmsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vmsbc_vxm, "vmsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vmsbf_m, "vmsbf.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vmseq_vi, "vmseq.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmseq_vv, "vmseq.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmseq_vx, "vmseq.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsgt_vi, "vmsgt.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsgt_vx, "vmsgt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsgtu_vi, "vmsgtu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsgtu_vx, "vmsgtu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsif_m, "vmsif.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vmsle_vi, "vmsle.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsle_vv, "vmsle.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsle_vx, "vmsle.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsleu_vi, "vmsleu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsleu_vv, "vmsleu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsleu_vx, "vmsleu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmslt_vv, "vmslt.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmslt_vx, "vmslt.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsltu_vv, "vmsltu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsltu_vx, "vmsltu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsne_vi, "vmsne.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vmsne_vv, "vmsne.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmsne_vx, "vmsne.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmsof_m, "vmsof.m", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vmul_vv, "vmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmul_vx, "vmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulh_vv, "vmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulh_vx, "vmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulhsu_vv, "vmulhsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulhsu_vx, "vmulhsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmulhu_vv, "vmulhu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmulhu_vx, "vmulhu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vmv1r_v, "vmv1r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv2r_v, "vmv2r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv4r_v, "vmv4r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv8r_v, "vmv8r.v", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vmv_s_x, "vmv.s.x", rv_codec_v_r, rv_fmt_vd_rs1) +OP(vmv_v_i, "vmv.v.i", rv_codec_v_i, rv_fmt_vd_imm) +OP(vmv_v_v, "vmv.v.v", rv_codec_v_r, rv_fmt_vd_vs1) +OP(vmv_v_x, "vmv.v.x", rv_codec_v_r, rv_fmt_vd_rs1) +OP(vmv_x_s, "vmv.x.s", rv_codec_v_r, rv_fmt_rd_vs2) +OP(vmxnor_mm, "vmxnor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vmxor_mm, "vmxor.mm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnclip_wi, "vnclip.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnclip_wv, "vnclip.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnclip_wx, "vnclip.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnclipu_wi, "vnclipu.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnclipu_wv, "vnclipu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnclipu_wx, "vnclipu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnmsac_vv, "vnmsac.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vnmsac_vx, "vnmsac.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vnmsub_vv, "vnmsub.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vnmsub_vx, "vnmsub.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vnsra_wi, "vnsra.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnsra_wv, "vnsra.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnsra_wx, "vnsra.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vnsrl_wi, "vnsrl.wi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vnsrl_wv, "vnsrl.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vnsrl_wx, "vnsrl.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vor_vi, "vor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vor_vv, "vor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vor_vx, "vor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vredand_vs, "vredand.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmax_vs, "vredmax.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmaxu_vs, "vredmaxu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredmin_vs, "vredmin.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredminu_vs, "vredminu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredor_vs, "vredor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredsum_vs, "vredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vredxor_vs, "vredxor.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrem_vv, "vrem.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrem_vx, "vrem.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vremu_vv, "vremu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vremu_vx, "vremu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vrev8_v, "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vrgather_vi, "vrgather.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vrgather_vv, "vrgather.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vrgather_vx, "vrgather.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vrgatherei16_vv, "vrgatherei16.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vrol_vv, "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vrol_vx, "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vror_vi, "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm) OP(vror_vv, "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vror_vx, "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vror_vi, "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm) +OP(vrsub_vi, "vrsub.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vrsub_vx, "vrsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vs1r_v, "vs1r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs2r_v, "vs2r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs4r_v, "vs4r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vs8r_v, "vs8r.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vsadd_vi, "vsadd.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vsadd_vv, "vsadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsadd_vx, "vsadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsaddu_vi, "vsaddu.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vsaddu_vv, "vsaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsaddu_vx, "vsaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsbc_vvm, "vsbc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) +OP(vsbc_vxm, "vsbc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) +OP(vse16_v, "vse16.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse32_v, "vse32.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse64_v, "vse64.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vse8_v, "vse8.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vsetivli, "vsetivli", rv_codec_vsetivli, rv_fmt_vsetivli) +OP(vsetvl, "vsetvl", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(vsetvli, "vsetvli", rv_codec_vsetvli, rv_fmt_vsetvli) +OP(vsext_vf2, "vsext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsext_vf4, "vsext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vsext_vf8, "vsext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) OP(vsha2ch_vv, "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) OP(vsha2cl_vv, "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) OP(vsha2ms_vv, "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) +OP(vslide1down_vx, "vslide1down.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslide1up_vx, "vslide1up.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslidedown_vi, "vslidedown.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vslidedown_vx, "vslidedown.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vslideup_vi, "vslideup.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vslideup_vx, "vslideup.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsll_vi, "vsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vsll_vv, "vsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsll_vx, "vsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vsm3c_vi, "vsm3c.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) OP(vsm3me_vv, "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1) OP(vsm4k_vi, "vsm4k.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm) -OP(vsm4r_vv, "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2) OP(vsm4r_vs, "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vsm4r_vv, "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2) +OP(vsm_v, "vsm.v", rv_codec_v_ldst, rv_fmt_ldst_vd_rs1_vm) +OP(vsmul_vv, "vsmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsmul_vx, "vsmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsoxei16_v, "vsoxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei32_v, "vsoxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei64_v, "vsoxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsoxei8_v, "vsoxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsra_vi, "vsra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vsra_vv, "vsra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsra_vx, "vsra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsrl_vi, "vsrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vsrl_vv, "vsrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsrl_vx, "vsrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsse16_v, "vsse16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse32_v, "vsse32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse64_v, "vsse64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vsse8_v, "vsse8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_rs2_vm) +OP(vssra_vi, "vssra.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vssra_vv, "vssra.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssra_vx, "vssra.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssrl_vi, "vssrl.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) +OP(vssrl_vv, "vssrl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssrl_vx, "vssrl.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssub_vv, "vssub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssub_vx, "vssub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vssubu_vv, "vssubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vssubu_vx, "vssubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsub_vv, "vsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vsub_vx, "vsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vsuxei16_v, "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) +OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwadd_wx, "vwadd.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwaddu_vv, "vwaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwaddu_vx, "vwaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwaddu_wv, "vwaddu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwaddu_wx, "vwaddu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmacc_vv, "vwmacc.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmacc_vx, "vwmacc.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccsu_vv, "vwmaccsu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmaccsu_vx, "vwmaccsu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccu_vv, "vwmaccu.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm) +OP(vwmaccu_vx, "vwmaccu.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmaccus_vx, "vwmaccus.vx", rv_codec_v_r, rv_fmt_vd_rs1_vs2_vm) +OP(vwmul_vv, "vwmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmul_vx, "vwmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmulsu_vv, "vwmulsu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmulsu_vx, "vwmulsu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwmulu_vv, "vwmulu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwmulu_vx, "vwmulu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwredsum_vs, "vwredsum.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwredsumu_vs, "vwredsumu.vs", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsll_vi, "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) OP(vwsll_vv, "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vwsll_vx, "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) -OP(vwsll_vi, "vwsll.vi", rv_codec_v_i_u, rv_fmt_vd_vs2_uimm_vm) -OP(amocas_w, "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amocas_d, "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amocas_q, "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(mop_r, "mop.r", rv_codec_mop_r, rv_fmt_mop_r) -OP(mop_rr, "mop.rr", rv_codec_mop_rr, rv_fmt_mop_rr) -OP(c_mop, "c.mop", rv_codec_cmop, rv_fmt_cmop) -OP(amoswap_b, "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoadd_b, "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoxor_b, "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoor_b, "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoand_b, "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomin_b, "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomax_b, "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amominu_b, "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomaxu_b, "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoswap_h, "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoadd_h, "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoxor_h, "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoor_h, "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amoand_h, "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomin_h, "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomax_h, "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amominu_h, "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amomaxu_h, "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amocas_b, "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(amocas_h, "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(wrs_sto, "wrs.sto", rv_codec_none, rv_fmt_none) +OP(vwsub_vv, "vwsub.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsub_vx, "vwsub.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsub_wv, "vwsub.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsub_wx, "vwsub.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsubu_vv, "vwsubu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsubu_vx, "vwsubu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vwsubu_wv, "vwsubu.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vwsubu_wx, "vwsubu.wx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vxor_vi, "vxor.vi", rv_codec_v_i, rv_fmt_vd_vs2_imm_vm) +OP(vxor_vv, "vxor.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) +OP(vxor_vx, "vxor.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) +OP(vzext_vf2, "vzext.vf2", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vzext_vf4, "vzext.vf4", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(vzext_vf8, "vzext.vf8", rv_codec_v_r, rv_fmt_vd_vs2_vm) +OP(wfi, "wfi", rv_codec_none, rv_fmt_none) OP(wrs_nto, "wrs.nto", rv_codec_none, rv_fmt_none) -OP(lpad, "lpad", rv_codec_lp, rv_fmt_imm) -OP(sspush, "sspush", rv_codec_r, rv_fmt_rs2) -OP(sspopchk, "sspopchk", rv_codec_r, rv_fmt_rs1) -OP(ssrdp, "ssrdp", rv_codec_r, rv_fmt_rd) -OP(ssamoswap_w, "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(ssamoswap_d, "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1) -OP(c_sspush, "c.sspush", rv_codec_cmop_ss, NULL, DECOMP(op_sspush)) -OP(c_sspopchk, "c.sspopchk", rv_codec_cmop_ss, NULL, DECOMP(op_sspopchk)) -OP(cbo_inval, "cbo.inval", rv_codec_r, rv_fmt_rs1) -OP(cbo_clean, "cbo.clean", rv_codec_r, rv_fmt_rs1) -OP(cbo_flush, "cbo.flush", rv_codec_r, rv_fmt_rs1) -OP(cbo_zero, "cbo.zero", rv_codec_r, rv_fmt_rs1) -OP(mnret, "mnret", rv_codec_none, rv_fmt_none) +OP(wrs_sto, "wrs.sto", rv_codec_none, rv_fmt_none) +OP(xnor, "xnor", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(xor, "xor", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(xori, "xori", rv_codec_i, rv_fmt_rd_rs1_imm, rvcp_xori) +OP(xperm4, "xperm4", rv_codec_r, rv_fmt_rd_rs1_rs2) +OP(xperm8, "xperm8", rv_codec_r, rv_fmt_rd_rs1) +OP(zext_h, "zext.h", rv_codec_r, rv_fmt_rd_rs1) +OP(zip, "zip", rv_codec_r, rv_fmt_rd_rs1) From 12289f2f9a0f1ffa6a75c2b189a0273dc455dfb0 Mon Sep 17 00:00:00 2001 From: wangyang Date: Thu, 13 Aug 2026 18:39:06 +0800 Subject: [PATCH 568/627] target/riscv: honor zicbo* envcfg gating in linux-user mode In user-only builds check_zicbo_envcfg() skipped the envcfg check entirely (#if !defined(CONFIG_USER_ONLY)), so cbo.inval/cbo.flush/ cbo.zero retired unconditionally in linux-user even though the machine-level envcfg fields are never initialized. Give the user-mode build a senvcfg-based gate, and initialize SENVCFG_CBZE at reset when ext_zicboz is enabled so cbo.zero stays usable while cbo.inval/cbo.flush remain illegal, matching the user-mode view of a typical firmware/kernel setup. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4107 Reviewed-by: Alistair Francis Signed-off-by: wangyang Message-ID: <9b2f22fc402b48b8ba81f72be8ed04bc@wangyang25.otcaix.iscas.ac.cn> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 8 ++++++++ target/riscv/tcg/op_helper.c | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d8f239e41d..79ddde419a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1062,6 +1062,14 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) #else env->priv = PRV_U; env->senvcfg = 0; + /* + * Match the user-mode view of a typical firmware/kernel setup where + * cbo.zero is enabled for user mode; the CBCFE/CBIE bits stay zero, + * so the cache-management operations remain illegal in user mode. + */ + if (riscv_cpu_cfg(env)->ext_zicboz) { + env->senvcfg |= SENVCFG_CBZE; + } env->menvcfg = 0; #endif /* !CONFIG_USER_ONLY */ diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c index acdccd1a97..a7bd42d2c6 100644 --- a/target/riscv/tcg/op_helper.c +++ b/target/riscv/tcg/op_helper.c @@ -152,7 +152,16 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr, static void check_zicbo_envcfg(CPURISCVState *env, target_ulong envbits, uintptr_t ra) { -#ifndef CONFIG_USER_ONLY +#if defined(CONFIG_USER_ONLY) + /* + * linux-user: the machine-level envcfg fields are not part of the + * user-mode environment; only the user-mode view of the enabling + * bits (senvcfg, as initialized for the guest) applies. + */ + if (!get_field(env->senvcfg, envbits)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra); + } +#else if ((env->priv < PRV_M) && !get_field(env->menvcfg, envbits)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra); } From af1e669cef162e8d9b5f2f176e8b909d61c4b530 Mon Sep 17 00:00:00 2001 From: wangyang Date: Thu, 13 Aug 2026 18:39:06 +0800 Subject: [PATCH 569/627] target/riscv: reject FMV.X.W/FMV.W.X under Zfinx Zfinx explicitly excludes the FMV transfer instructions, but trans_fmv_x_w/trans_fmv_w_x used REQUIRE_ZFINX_OR_F so a Zfinx-only CPU accepted them. Require RVF instead so the transfers trap with an illegal instruction when only Zfinx is present. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4108 Reviewed-by: Alistair Francis Signed-off-by: wangyang Message-ID: <36c7cfebd27b4b6e8bcdd00e09e9dda0@wangyang25.otcaix.iscas.ac.cn> Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvf.c.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/tcg/insn_trans/trans_rvf.c.inc b/target/riscv/tcg/insn_trans/trans_rvf.c.inc index 481f7282da..636dec1664 100644 --- a/target/riscv/tcg/insn_trans/trans_rvf.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvf.c.inc @@ -434,7 +434,8 @@ static bool trans_fmv_x_w(DisasContext *ctx, arg_fmv_x_w *a) { /* NOTE: This was FMV.X.S in an earlier version of the ISA spec! */ REQUIRE_FPU; - REQUIRE_ZFINX_OR_F(ctx); + /* Zfinx explicitly excludes the FMV transfer instructions. */ + REQUIRE_EXT(ctx, RVF); TCGv dest = dest_gpr(ctx, a->rd); TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); @@ -537,7 +538,8 @@ static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) { /* NOTE: This was FMV.S.X in an earlier version of the ISA spec! */ REQUIRE_FPU; - REQUIRE_ZFINX_OR_F(ctx); + /* Zfinx explicitly excludes the FMV transfer instructions. */ + REQUIRE_EXT(ctx, RVF); TCGv_i64 dest = dest_fpr(ctx, a->rd); TCGv src = get_gpr(ctx, a->rs1, EXT_ZERO); From e68cc2e5cd28333ac76d757ed2db7d2f7635d09a Mon Sep 17 00:00:00 2001 From: wangyang Date: Thu, 13 Aug 2026 18:39:06 +0800 Subject: [PATCH 570/627] target/riscv: enforce even register constraints for Zdinx fcvt pairs fcvt.d.h and fcvt.h.d access a 64-bit double held in a register pair, so under Zdinx/Zhinxmin the odd-rd (fcvt.d.h) and odd-rs1 (fcvt.h.d) encodings are reserved. Add the missing REQUIRE_EVEN checks so those encodings raise an illegal-instruction exception instead of retiring. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4109 Reviewed-by: Alistair Francis Signed-off-by: wangyang Message-ID: Signed-off-by: Alistair Francis --- target/riscv/tcg/insn_trans/trans_rvzfh.c.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc b/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc index 88711fb076..b17ef9541c 100644 --- a/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc +++ b/target/riscv/tcg/insn_trans/trans_rvzfh.c.inc @@ -419,6 +419,7 @@ static bool trans_fcvt_d_h(DisasContext *ctx, arg_fcvt_d_h *a) REQUIRE_FPU; REQUIRE_ZFHMIN_OR_ZHINXMIN(ctx); REQUIRE_ZDINX_OR_D(ctx); + REQUIRE_EVEN(ctx, a->rd); TCGv_i64 dest = dest_fpr(ctx, a->rd); TCGv_i64 src1 = get_fpr_hs(ctx, a->rs1); @@ -453,6 +454,7 @@ static bool trans_fcvt_h_d(DisasContext *ctx, arg_fcvt_h_d *a) REQUIRE_FPU; REQUIRE_ZFHMIN_OR_ZHINXMIN(ctx); REQUIRE_ZDINX_OR_D(ctx); + REQUIRE_EVEN(ctx, a->rs1); TCGv_i64 dest = dest_fpr(ctx, a->rd); TCGv_i64 src1 = get_fpr_d(ctx, a->rs1); From e4ae434836a98039ed0511dea506992b55e55865 Mon Sep 17 00:00:00 2001 From: Chao Liu Date: Thu, 13 Aug 2026 13:43:29 +0800 Subject: [PATCH 571/627] tests/qtest: remove trace output from k230 watchdog test The interrupt mode test does not depend on trace output, but passes a trace file to QEMU. This makes startup fail when QEMU is built without the log or simple trace backend, so qtest cannot connect. Drop the unnecessary trace option. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4126 Signed-off-by: Chao Liu Reviewed-by: Bin Meng Message-ID: <20260813054329.35425-1-chao.liu@processmission.com> Signed-off-by: Alistair Francis --- tests/qtest/k230-wdt-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/k230-wdt-test.c b/tests/qtest/k230-wdt-test.c index c8eaeaf1ae..b1131f42e3 100644 --- a/tests/qtest/k230-wdt-test.c +++ b/tests/qtest/k230-wdt-test.c @@ -76,7 +76,7 @@ static void test_counter_restart(void) static void test_interrupt_mode(void) { - QTestState *qts = qtest_init("-machine k230 --trace k230_*,file=k230.log"); + QTestState *qts = qtest_init("-machine k230"); /* Set interrupt mode and enable watchdog */ qtest_writel(qts, WDT_BASE + K230_WDT_CR, From 409c7d8682ae91c5e275d744d55a2ac19789534a Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Thu, 13 Aug 2026 12:54:14 +0930 Subject: [PATCH 572/627] target/riscv: Restore register dump zero padding The register values lost their leading zeroes when the underlying type was changed, resulting in mismatched padding and harder to read output. Print with a runtime field width based on MXL, so values are 16 hex digits on rv64 and 8 on rv32, matching the csr and fp dump. This avoids adding target_ulong back into the dump. Fixes: c4e6bc63853c ("target/riscv: Fix size of gpr and gprh") Signed-off-by: Joel Stanley Reviewed-by: Anton Johansson Reviewed-by: Max Chou Message-ID: <20260813032421.54438-1-joel@jms.id.au> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 79ddde419a..a13177b7b7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -651,6 +651,9 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + bool rv32 = riscv_cpu_is_32bit(cpu); + int width = rv32 ? 8 : 16; + uint64_t mask = rv32 ? UINT32_MAX : UINT64_MAX; int i, j; uint8_t *p; @@ -665,7 +668,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " %-13s %d\n", "elp", env->elp); } #endif - qemu_fprintf(f, " %-13s %" PRIx64 "\n", "pc", env->pc); + qemu_fprintf(f, " %-13s %0*" PRIx64 "\n", "pc", width, env->pc & mask); #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) for (i = 0; i < ARRAY_SIZE(csr_ops); i++) { int csrno = i; @@ -692,8 +695,8 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) #endif for (i = 0; i < 32; i++) { - qemu_fprintf(f, " %-8s %" PRIx64, - riscv_int_regnames[i], env->gpr[i]); + qemu_fprintf(f, " %-8s %0*" PRIx64, + riscv_int_regnames[i], width, env->gpr[i] & mask); if ((i & 3) == 3) { qemu_fprintf(f, "\n"); } From ea8e5d3c504d38a6eb82a338dc48b9ba7b072153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9trot?= Date: Wed, 19 Aug 2026 12:56:54 +0200 Subject: [PATCH 573/627] target/riscv: Fix sstatus update in rv128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sstatus register assignment was performed before the write mask was fully constructed, leading to an incomplete update of sstatus fields on the experimental rv128 target. Move the sstatus write after the mask completion so the full write mask is applied correctly. Signed-off-by: Frédéric Pétrot Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Chao Liu Message-ID: <20260819105655.33391-2-frederic.petrot@univ-grenoble-alpes.fr> Signed-off-by: Alistair Francis --- target/riscv/tcg/csr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index ffd751caa5..9cc6297328 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -3998,7 +3998,7 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno, Int128 *val) { uint64_t mask = sstatus_v1_10_mask; - uint64_t sstatus = env->mstatus & mask; + uint64_t sstatus; if (env->xl != MXL_RV32 || env->debugger) { mask |= SSTATUS64_UXL; } @@ -4009,7 +4009,7 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno, if (env_archcpu(env)->cfg.ext_zicfilp) { mask |= SSTATUS_SPELP; } - + sstatus = env->mstatus & mask; *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus)); return RISCV_EXCP_NONE; } From a9779d24be31338d90aa19a560e69cc4c9660627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9trot?= Date: Wed, 19 Aug 2026 12:56:55 +0200 Subject: [PATCH 574/627] target/riscv: Allow UXL to be 3 in mstatus on rv128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Valid UXL field values for mstatus were restricted to fix a reported issue, but this inadvertently broke the experimental rv128 support where a value of 3 validly represents 128-bit execution. Update the mstatus write logic to permit UXL=3 when running on an rv128 CPU. Fixes: dcd028517749 ("target/riscv: Apply UXL WARL handling to vsstatus") Signed-off-by: Frédéric Pétrot Reviewed-by: Daniel Henrique Barboza Reviewed-by: Chao Liu Message-ID: <20260819105655.33391-3-frederic.petrot@univ-grenoble-alpes.fr> Signed-off-by: Alistair Francis --- target/riscv/tcg/csr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 9cc6297328..4c8959a33d 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -2014,8 +2014,8 @@ static uint64_t riscv_write_uxl(CPURISCVState *env, uint64_t val, RISCVMXL xl = riscv_cpu_mxl(env); uint64_t uxl = get_field(val, field); - if (uxl == MXL_RV128) { - uxl = xl == MXL_RV128 ? MXL_RV64 : xl; + if (xl != MXL_RV128 && uxl == MXL_RV128) { + uxl = xl; val = set_field(val, field, uxl); } From af37cd2821f970a1a9d2d34fa0d319f80d2ab84d Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Mon, 17 Aug 2026 18:06:37 +0300 Subject: [PATCH 575/627] riscv: csr: do not drop C bit on misa write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to spec: > Writing misa may increase IALIGN, e.g., by disabling the "C" extension. > If an instruction that would write misa increases IALIGN, and the > subsequent instruction’s address is not IALIGN-bit aligned, the > write to misa is suppressed, leaving misa unchanged. So attempt to disable C extension if next instruction is not aligned should not change the misa. Reviewed-by: Alistair Francis Signed-off-by: Vladimir Isaev Reviewed-by: Chao Liu Message-ID: <20260817150653.40357-2-vvisaev@gmail.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/csr.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index 4c8959a33d..002f7e69c1 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -2187,9 +2187,13 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, /* Mask extensions that are not supported by this hart */ val &= env->misa_ext_mask; - /* Suppress 'C' if next instruction is not aligned. */ - if ((val & RVC) && (get_next_pc(env, ra) & 3) != 0) { - val &= ~RVC; + /* drop write if RVC is cleared and next instruction is not aligned */ + if ((env->misa_ext & RVC) && !(val & RVC) && + (get_next_pc(env, ra) & 3) != 0) { + qemu_log_mask(LOG_GUEST_ERROR, "Unable to write MISA ext value " + "0x%x, MISA.C disable failed\n", env->misa_ext); + + return RISCV_EXCP_NONE; } /* Disable RVG if any of its dependencies are disabled */ From ce781055ff61308df9c4f9546c72e09b6908fe06 Mon Sep 17 00:00:00 2001 From: Vladimir Isaev Date: Mon, 17 Aug 2026 18:06:38 +0300 Subject: [PATCH 576/627] tests/tcg/riscv64: add misa write test Link: https://lore.kernel.org/r/20260321144554.606417-2-npiggin@gmail.com Suggested-by: Nicholas Piggin Signed-off-by: Vladimir Isaev Message-ID: <20260817150653.40357-3-vvisaev@gmail.com> Signed-off-by: Alistair Francis --- tests/tcg/riscv64/Makefile.softmmu-target | 4 ++ tests/tcg/riscv64/test-misa-w.S | 88 +++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 tests/tcg/riscv64/test-misa-w.S diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target index fac0474746..6a219c306c 100644 --- a/tests/tcg/riscv64/Makefile.softmmu-target +++ b/tests/tcg/riscv64/Makefile.softmmu-target @@ -67,5 +67,9 @@ EXTRA_RUNS += run-test-zicclsm-off run-test-zicclsm-off: test-zicclsm-off $(call run-test, $<, $(QEMU) -cpu rv64$(comma)v=true$(comma)zfh=true$(comma)zicclsm=false $(QEMU_OPTS)$<) +EXTRA_RUNS += run-test-misa-w +run-test-misa-w: test-misa-w + $(call run-test, $<, $(QEMU) -cpu rv64$(comma)x-misa-w=true$(comma)c=true$(comma)v=true $(QEMU_OPTS)$<) + # We don't currently support the multiarch system tests undefine MULTIARCH_TESTS diff --git a/tests/tcg/riscv64/test-misa-w.S b/tests/tcg/riscv64/test-misa-w.S new file mode 100644 index 0000000000..7f1eb30023 --- /dev/null +++ b/tests/tcg/riscv64/test-misa-w.S @@ -0,0 +1,88 @@ +/* + * Test for MISA changing C and related IALIGN alignment cases + * + * This test verifies that the "C" extension can be cleared and set in MISA, + * that a branch to 2-byte aligned instructions can be executed when "C" is + * enabled, and that a write to MISA which would increase IALIGN and cause + * the next instruction to be unaligned is ignored. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#define RVC (1 << ('C'-'A')) +#define RVV (1 << ('V'-'A')) + +.option norvc + .text + .global _start +_start: + lla t0, trap + csrw mtvec, t0 + + csrr t0, misa + li t1, RVC + not t1, t1 + and t0, t0, t1 + csrw misa, t0 + csrr t1, misa + li a0, 2 # fail code + bne t0, t1, _exit # Could not clear RVC in MISA + + li t1, RVC + or t0, t0, t1 + csrw misa, t0 + csrr t1, misa + li a0, 3 # fail code + bne t0, t1, _exit # Could not set RVC in MISA + + j unalign +. = . + 2 +unalign: + + li t1, RVC + not t1, t1 + and t0, t0, t1 + csrw misa, t0 + csrr t1, misa + li a0, 4 # fail code + beq t0, t1, _exit # Was able to clear RVC in MISA + + li t0, (RVC|RVV) + not t0, t0 + and t0, t0, t1 + csrw misa, t0 + csrr t0, misa + li a0, 5 # fail code + bne t0, t1, _exit # MISA write was not ignored (RVV was cleared) + + j realign +. = . + 2 +realign: + + # Success! + li a0, 0 + j _exit + +trap: + # Any trap is a fail code 1 + li a0, 1 + +# Exit code in a0 +_exit: + lla a1, semiargs + li t0, 0x20026 # ADP_Stopped_ApplicationExit + sd t0, 0(a1) + sd a0, 8(a1) + li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED + + # Semihosting call sequence + .balign 16 + slli zero, zero, 0x1f + ebreak + srai zero, zero, 0x7 + j . + + .data + .balign 16 +semiargs: + .space 16 From 598ef9c81a7f3a9edefdb71e87ca51fb9a4b28bd Mon Sep 17 00:00:00 2001 From: Xu Liu Date: Mon, 17 Aug 2026 16:30:05 +0800 Subject: [PATCH 577/627] target/riscv: Make Zcmt JVT loads endian-aware The Zcmt specification says JVT table entries follow the current data endianness. Support that behavior as described by the specification so big-endian guests can use JVT tables stored in big-endian form. Signed-off-by: Xu Liu Reviewed-by: Alistair Francis Message-ID: <02050B1BBB8815BE+20260817083005.2392-1-liuxu@nucleisys.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/zce_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/tcg/zce_helper.c b/target/riscv/tcg/zce_helper.c index 15bf0a99c8..c6ba4c1a47 100644 --- a/target/riscv/tcg/zce_helper.c +++ b/target/riscv/tcg/zce_helper.c @@ -18,12 +18,14 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internals.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" target_ulong HELPER(cm_jalt)(CPURISCVState *env, uint32_t index) { unsigned mmu_index = cpu_mmu_index(env_cpu(env), true); + MemOp endian = mo_endian_env(env); MemOpIdx oi; #if !defined(CONFIG_USER_ONLY) @@ -45,11 +47,11 @@ target_ulong HELPER(cm_jalt)(CPURISCVState *env, uint32_t index) } if (xlen == 32) { - oi = make_memop_idx(MO_LEUL, mmu_index); + oi = make_memop_idx(MO_UL | endian, mmu_index); t0 = base + (index << 2); target = cpu_ldl_code_mmu(env, t0, oi, 0); } else { - oi = make_memop_idx(MO_LEUQ, mmu_index); + oi = make_memop_idx(MO_UQ | endian, mmu_index); t0 = base + (index << 3); target = cpu_ldq_code_mmu(env, t0, oi, 0); } From 85d38315fd19cda7fcfec5350f27cdfa15742600 Mon Sep 17 00:00:00 2001 From: "Christian S. Lima" Date: Sat, 8 Aug 2026 03:18:54 +0000 Subject: [PATCH 578/627] target/riscv/tcg: sret in virtual user mode raises virtual instruction exception Currently, when a `sret` is executed in virtual user mode, qemu raise an `illegal instruction exception`, but in this case the correct behavior is to raise a `virtual instruction exception` and the code already contains a check to it, but it's not enough to catch. This patch is useful to improve the correctness of the virtualization of the risc v architecture. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3622 Signed-off-by: Christian S. Lima Reviewed-by: Alistair Francis Message-ID: <20260808031849.59726-1-christianslima@proton.me> Signed-off-by: Alistair Francis --- target/riscv/tcg/op_helper.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c index a7bd42d2c6..3e94005d2b 100644 --- a/target/riscv/tcg/op_helper.c +++ b/target/riscv/tcg/op_helper.c @@ -308,6 +308,11 @@ target_ulong helper_sret(CPURISCVState *env) const privilege_mode_t src_priv = env->priv; const bool src_virt = env->virt_enabled; + if ((env->virt_enabled && env->priv < PRV_S) || + (env->virt_enabled && get_field(env->hstatus, HSTATUS_VTSR))) { + riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); + } + if (!(env->priv >= PRV_S)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } @@ -323,10 +328,6 @@ target_ulong helper_sret(CPURISCVState *env) riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } - if (env->virt_enabled && get_field(env->hstatus, HSTATUS_VTSR)) { - riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); - } - mstatus = env->mstatus; prev_priv = get_field(mstatus, MSTATUS_SPP); mstatus = set_field(mstatus, MSTATUS_SIE, From 42feb94b790523f83c1d39141c59face0e327211 Mon Sep 17 00:00:00 2001 From: Jeuk Kim Date: Fri, 7 Aug 2026 19:36:16 +0900 Subject: [PATCH 579/627] hw/ufs: Separate the controller core from the PCI frontend UfsHc is currently also the PCI device instance, tying common code to PCI-specific DMA and IRQ interfaces and preventing reuse by non-PCI frontends. Make UfsHc transport-independent and embed it in UfsPciState. Move the PCI-specific handling to ufs-pci.c, pass the owning DeviceState and DMA AddressSpace to the core, and record the core explicitly in UfsBus. Split the common implementation into CONFIG_UFS, selected by CONFIG_UFS_PCI. The user-visible "ufs" device and its properties remain unchanged. No functional change is intended. Signed-off-by: Jeuk Kim --- hw/ufs/Kconfig | 5 ++ hw/ufs/lu.c | 2 +- hw/ufs/meson.build | 3 +- hw/ufs/trace-events | 4 +- hw/ufs/ufs-pci.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ hw/ufs/ufs.c | 109 +++++++++--------------------------------- hw/ufs/ufs.h | 14 ++++-- 7 files changed, 153 insertions(+), 96 deletions(-) create mode 100644 hw/ufs/ufs-pci.c diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig index b7b3392e85..47e28a30ea 100644 --- a/hw/ufs/Kconfig +++ b/hw/ufs/Kconfig @@ -1,4 +1,9 @@ +config UFS + bool + select SCSI + config UFS_PCI bool default y if PCI_DEVICES depends on PCI + select UFS diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 13f4a90145..eeca865eb5 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -497,7 +497,7 @@ static void ufs_lu_realize(DeviceState *dev, Error **errp) { UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev); BusState *s = qdev_get_parent_bus(dev); - UfsHc *u = UFS(s->parent); + UfsHc *u = UFS_BUS(s)->hc; BlockBackend *blk = lu->conf.blk; if (!ufs_lu_check_constraints(lu, errp)) { diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build index 6e68328b93..880fc52c05 100644 --- a/hw/ufs/meson.build +++ b/hw/ufs/meson.build @@ -1 +1,2 @@ -system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c', 'lu.c')) +system_ss.add(when: 'CONFIG_UFS', if_true: files('ufs.c', 'lu.c')) +system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs-pci.c')) diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events index 662d9afee3..0cd3ba9b02 100644 --- a/hw/ufs/trace-events +++ b/hw/ufs/trace-events @@ -1,6 +1,6 @@ # ufs.c -ufs_irq_raise(void) "INTx" -ufs_irq_lower(void) "INTx" +ufs_irq_raise(void) "IRQ" +ufs_irq_lower(void) "IRQ" ufs_mmio_read(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" ufs_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" ufs_process_db(uint32_t slot) "UTRLDBR slot %"PRIu32"" diff --git a/hw/ufs/ufs-pci.c b/hw/ufs/ufs-pci.c new file mode 100644 index 0000000000..8abd7d98e3 --- /dev/null +++ b/hw/ufs/ufs-pci.c @@ -0,0 +1,112 @@ +/* + * QEMU Universal Flash Storage (UFS) PCI Controller + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. + * + * Written by Jeuk Kim + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/** + * Usage + * ----- + * + * Add options: + * -drive file=,if=none,id= + * -device ufs,serial=,id=, \ + * nutrs=,nutmrs= + * -device ufs-lu,drive=,bus= + */ + +#include "qemu/osdep.h" +#include "hw/core/irq.h" +#include "hw/core/qdev-properties.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_device.h" +#include "migration/vmstate.h" +#include "ufs.h" + +#define TYPE_UFS_PCI "ufs" +OBJECT_DECLARE_SIMPLE_TYPE(UfsPciState, UFS_PCI) + +struct UfsPciState { + PCIDevice parent_obj; + UfsHc ufs; +}; + +static void ufs_pci_realize(PCIDevice *pci_dev, Error **errp) +{ + UfsPciState *s = UFS_PCI(pci_dev); + UfsHc *u = &s->ufs; + uint8_t *pci_conf = pci_dev->config; + + pci_conf[PCI_INTERRUPT_PIN] = 1; + pci_config_set_prog_interface(pci_conf, 0x1); + u->irq = pci_allocate_irq(pci_dev); + if (!ufs_realize(u, DEVICE(pci_dev), pci_get_address_space(pci_dev), + errp)) { + qemu_free_irq(u->irq); + u->irq = NULL; + return; + } + + pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem); +} + +static void ufs_pci_exit(PCIDevice *pci_dev) +{ + UfsPciState *s = UFS_PCI(pci_dev); + + ufs_unrealize(&s->ufs); + qemu_free_irq(s->ufs.irq); +} + +static const Property ufs_pci_props[] = { + DEFINE_PROP_STRING("serial", UfsPciState, ufs.params.serial), + DEFINE_PROP_UINT8("nutrs", UfsPciState, ufs.params.nutrs, 32), + DEFINE_PROP_UINT8("nutmrs", UfsPciState, ufs.params.nutmrs, 8), + DEFINE_PROP_BOOL("mcq", UfsPciState, ufs.params.mcq, false), + DEFINE_PROP_UINT8("mcq-maxq", UfsPciState, ufs.params.mcq_maxq, 2), + DEFINE_PROP_UINT32("wb-max-size", UfsPciState, ufs.params.wb_max_size, + 0x400), + DEFINE_PROP_UINT32("wb-min-size", UfsPciState, ufs.params.wb_min_size, + 0x100), +}; + +static const VMStateDescription ufs_pci_vmstate = { + .name = "ufs", + .unmigratable = 1, +}; + +static void ufs_pci_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); + + pc->realize = ufs_pci_realize; + pc->exit = ufs_pci_exit; + pc->vendor_id = PCI_VENDOR_ID_REDHAT; + pc->device_id = PCI_DEVICE_ID_REDHAT_UFS; + pc->class_id = PCI_CLASS_STORAGE_UFS; + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->desc = "Universal Flash Storage"; + device_class_set_props(dc, ufs_pci_props); + dc->vmsd = &ufs_pci_vmstate; +} + +static const TypeInfo ufs_pci_info = { + .name = TYPE_UFS_PCI, + .parent = TYPE_PCI_DEVICE, + .class_init = ufs_pci_class_init, + .instance_size = sizeof(UfsPciState), + .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} }, +}; + +static void ufs_pci_register_types(void) +{ + type_register_static(&ufs_pci_info); +} + +type_init(ufs_pci_register_types) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 464fd465b3..160a4ac4f3 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -11,19 +11,10 @@ /** * Reference Specs: https://www.jedec.org/, 4.1 * - * Usage - * ----- - * - * Add options: - * -drive file=,if=none,id= - * -device ufs,serial=,id=, \ - * nutrs=,nutmrs= - * -device ufs-lu,drive=,bus= */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "migration/vmstate.h" #include "scsi/constants.h" #include "hw/core/irq.h" #include "trace.h" @@ -102,7 +93,7 @@ static MemTxResult ufs_addr_read(UfsHc *u, hwaddr addr, void *buf, int size) return MEMTX_DECODE_ERROR; } - return pci_dma_read(PCI_DEVICE(u), addr, buf, size); + return dma_memory_read(u->dma_as, addr, buf, size, MEMTXATTRS_UNSPECIFIED); } static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf, @@ -117,7 +108,7 @@ static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf, return MEMTX_DECODE_ERROR; } - return pci_dma_write(PCI_DEVICE(u), addr, buf, size); + return dma_memory_write(u->dma_as, addr, buf, size, MEMTXATTRS_UNSPECIFIED); } static inline hwaddr ufs_get_utrd_addr(UfsHc *u, uint32_t slot) @@ -222,7 +213,7 @@ static MemTxResult ufs_dma_read_prdt(UfsRequest *req) } req->sg = g_malloc0(sizeof(QEMUSGList)); - pci_dma_sglist_init(req->sg, PCI_DEVICE(u), prdt_len); + qemu_sglist_init(req->sg, u->dev, prdt_len, u->dma_as); req->data_len = 0; for (uint16_t i = 0; i < prdt_len; ++i) { @@ -317,14 +308,12 @@ static MemTxResult ufs_dma_write_upiu(UfsRequest *req) static void ufs_irq_check(UfsHc *u) { - PCIDevice *pci = PCI_DEVICE(u); - if ((u->reg.is & UFS_INTR_MASK) & u->reg.ie) { trace_ufs_irq_raise(); - pci_irq_assert(pci); + qemu_irq_raise(u->irq); } else { trace_ufs_irq_lower(); - pci_irq_deassert(pci); + qemu_irq_lower(u->irq); } } @@ -596,7 +585,7 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr) sq->size = qsize; sq->bh = qemu_bh_new_guarded(ufs_mcq_process_sq, sq, - &DEVICE(u)->mem_reentrancy_guard); + &u->dev->mem_reentrancy_guard); sq->req = g_new0(UfsRequest, sq->size); QTAILQ_INIT(&sq->req_list); for (int i = 0; i < sq->size; i++) { @@ -690,7 +679,7 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr) cq->size = qsize; cq->bh = qemu_bh_new_guarded(ufs_mcq_process_cq, cq, - &DEVICE(u)->mem_reentrancy_guard); + &u->dev->mem_reentrancy_guard); QTAILQ_INIT(&cq->req_list); u->cq[qid] = cq; @@ -2488,19 +2477,6 @@ static bool ufs_check_constraints(UfsHc *u, Error **errp) return true; } -static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev) -{ - uint8_t *pci_conf = pci_dev->config; - - pci_conf[PCI_INTERRUPT_PIN] = 1; - pci_config_set_prog_interface(pci_conf, 0x1); - - memory_region_init_io(&u->iomem, OBJECT(u), &ufs_mmio_ops, u, "ufs", - u->reg_size); - pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem); - u->irq = pci_allocate_irq(pci_dev); -} - static void ufs_init_state(UfsHc *u) { u->req_list = g_new0(UfsRequest, u->params.nutrs); @@ -2512,10 +2488,10 @@ static void ufs_init_state(UfsHc *u) u->req_list[i].state = UFS_REQUEST_IDLE; } - u->doorbell_bh = qemu_bh_new_guarded(ufs_process_req, u, - &DEVICE(u)->mem_reentrancy_guard); - u->complete_bh = qemu_bh_new_guarded(ufs_sendback_req, u, - &DEVICE(u)->mem_reentrancy_guard); + u->doorbell_bh = + qemu_bh_new_guarded(ufs_process_req, u, &u->dev->mem_reentrancy_guard); + u->complete_bh = + qemu_bh_new_guarded(ufs_sendback_req, u, &u->dev->mem_reentrancy_guard); if (u->params.mcq) { memset(u->sq, 0, sizeof(u->sq)); @@ -2689,35 +2665,35 @@ static void ufs_init_hc(UfsHc *u) timer_mod(&u->idle_timer, now + UFS_IDLE_TIMER_TICK); } -static void ufs_realize(PCIDevice *pci_dev, Error **errp) +bool ufs_realize(UfsHc *u, DeviceState *dev, AddressSpace *dma_as, Error **errp) { - UfsHc *u = UFS(pci_dev); + u->dev = dev; + u->dma_as = dma_as; if (!ufs_check_constraints(u, errp)) { - return; + return false; } - qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, &pci_dev->qdev, - u->parent_obj.qdev.id); + qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, dev, dev->id); + u->bus.hc = u; ufs_init_state(u); ufs_init_hc(u); - ufs_init_pci(u, pci_dev); + memory_region_init_io(&u->iomem, OBJECT(dev), &ufs_mmio_ops, u, "ufs", + u->reg_size); ufs_init_wlu(&u->report_wlu, UFS_UPIU_REPORT_LUNS_WLUN); ufs_init_wlu(&u->dev_wlu, UFS_UPIU_UFS_DEVICE_WLUN); ufs_init_wlu(&u->boot_wlu, UFS_UPIU_BOOT_WLUN); ufs_init_wlu(&u->rpmb_wlu, UFS_UPIU_RPMB_WLUN); + + return true; } -static void ufs_exit(PCIDevice *pci_dev) +void ufs_unrealize(UfsHc *u) { - UfsHc *u = UFS(pci_dev); - timer_del(&u->idle_timer); - qemu_free_irq(u->irq); - qemu_bh_delete(u->doorbell_bh); qemu_bh_delete(u->complete_bh); @@ -2740,38 +2716,6 @@ static void ufs_exit(PCIDevice *pci_dev) } } -static const Property ufs_props[] = { - DEFINE_PROP_STRING("serial", UfsHc, params.serial), - DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32), - DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8), - DEFINE_PROP_BOOL("mcq", UfsHc, params.mcq, false), - DEFINE_PROP_UINT8("mcq-maxq", UfsHc, params.mcq_maxq, 2), - DEFINE_PROP_UINT32("wb-max-size", UfsHc, params.wb_max_size, 0x400), - DEFINE_PROP_UINT32("wb-min-size", UfsHc, params.wb_min_size, 0x100), -}; - -static const VMStateDescription ufs_vmstate = { - .name = "ufs", - .unmigratable = 1, -}; - -static void ufs_class_init(ObjectClass *oc, const void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); - - pc->realize = ufs_realize; - pc->exit = ufs_exit; - pc->vendor_id = PCI_VENDOR_ID_REDHAT; - pc->device_id = PCI_DEVICE_ID_REDHAT_UFS; - pc->class_id = PCI_CLASS_STORAGE_UFS; - - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->desc = "Universal Flash Storage"; - device_class_set_props(dc, ufs_props); - dc->vmsd = &ufs_vmstate; -} - static bool ufs_bus_check_address(BusState *qbus, DeviceState *qdev, Error **errp) { @@ -2798,14 +2742,6 @@ static void ufs_bus_class_init(ObjectClass *class, const void *data) bc->check_address = ufs_bus_check_address; } -static const TypeInfo ufs_info = { - .name = TYPE_UFS, - .parent = TYPE_PCI_DEVICE, - .class_init = ufs_class_init, - .instance_size = sizeof(UfsHc), - .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} }, -}; - static const TypeInfo ufs_bus_info = { .name = TYPE_UFS_BUS, .parent = TYPE_BUS, @@ -2816,7 +2752,6 @@ static const TypeInfo ufs_bus_info = { static void ufs_register_types(void) { - type_register_static(&ufs_info); type_register_static(&ufs_bus_info); } diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h index feb47f460d..aa8361d93d 100644 --- a/hw/ufs/ufs.h +++ b/hw/ufs/ufs.h @@ -11,9 +11,11 @@ #ifndef HW_UFS_UFS_H #define HW_UFS_UFS_H -#include "hw/pci/pci_device.h" +#include "hw/core/qdev.h" #include "hw/scsi/scsi.h" #include "block/ufs.h" +#include "scsi/constants.h" +#include "system/dma.h" #define UFS_MAX_LUS 32 #define UFS_MAX_MCQ_QNUM 32 @@ -27,6 +29,7 @@ typedef struct UfsBusClass { typedef struct UfsBus { BusState parent_bus; + struct UfsHc *hc; } UfsBus; #define TYPE_UFS_BUS "ufs-bus" @@ -141,7 +144,8 @@ typedef struct UfsWb { } UfsWb; typedef struct UfsHc { - PCIDevice parent_obj; + DeviceState *dev; + AddressSpace *dma_as; UfsBus bus; MemoryRegion iomem; UfsReg reg; @@ -268,9 +272,6 @@ static inline bool ufs_is_write_req(UfsRequest *req) return (cmd == WRITE_6) || (cmd == WRITE_10) || (cmd == WRITE_16); } -#define TYPE_UFS "ufs" -#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS) - #define TYPE_UFS_LU "ufs-lu" #define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU) @@ -302,4 +303,7 @@ void ufs_build_query_response(UfsRequest *req); void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); void ufs_wb_update_avail_buffer(UfsHc *u); void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); +bool ufs_realize(UfsHc *u, DeviceState *dev, AddressSpace *dma_as, + Error **errp); +void ufs_unrealize(UfsHc *u); #endif /* HW_UFS_UFS_H */ From 6ed05d5e65208a5ee23a02667d5df0dc6491c156 Mon Sep 17 00:00:00 2001 From: Jeuk Kim Date: Fri, 7 Aug 2026 19:36:17 +0900 Subject: [PATCH 580/627] hw/ufs: Add a generic SysBus frontend Add TYPE_SYSBUS_UFS as a reusable frontend for the transport-independent UFS controller core. Use the system memory address space for DMA, expose the controller MMIO region and IRQ through SysBus, and provide the same properties and migration policy as the PCI frontend. Platform-specific controllers can derive from this type and keep only their hardware-specific behavior. Signed-off-by: Jeuk Kim --- hw/ufs/Kconfig | 4 +++ hw/ufs/meson.build | 1 + hw/ufs/ufs-sysbus.c | 80 +++++++++++++++++++++++++++++++++++++++++++++ hw/ufs/ufs-sysbus.h | 22 +++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 hw/ufs/ufs-sysbus.c create mode 100644 hw/ufs/ufs-sysbus.h diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig index 47e28a30ea..0e40f08a41 100644 --- a/hw/ufs/Kconfig +++ b/hw/ufs/Kconfig @@ -7,3 +7,7 @@ config UFS_PCI default y if PCI_DEVICES depends on PCI select UFS + +config UFS_SYSBUS + bool + select UFS diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build index 880fc52c05..a84627b96a 100644 --- a/hw/ufs/meson.build +++ b/hw/ufs/meson.build @@ -1,2 +1,3 @@ system_ss.add(when: 'CONFIG_UFS', if_true: files('ufs.c', 'lu.c')) system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs-pci.c')) +system_ss.add(when: 'CONFIG_UFS_SYSBUS', if_true: files('ufs-sysbus.c')) diff --git a/hw/ufs/ufs-sysbus.c b/hw/ufs/ufs-sysbus.c new file mode 100644 index 0000000000..84de2e95ac --- /dev/null +++ b/hw/ufs/ufs-sysbus.c @@ -0,0 +1,80 @@ +/* + * QEMU Universal Flash Storage (UFS) sysbus controller + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/qdev-properties.h" +#include "ufs-sysbus.h" +#include "migration/vmstate.h" +#include "system/address-spaces.h" + +static void ufs_sysbus_realize(DeviceState *dev, Error **errp) +{ + SysbusUfsState *s = SYSBUS_UFS(dev); + + if (!ufs_realize(&s->ufs, dev, &address_space_memory, errp)) { + return; + } + + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->ufs.iomem); +} + +static void ufs_sysbus_unrealize(DeviceState *dev) +{ + SysbusUfsState *s = SYSBUS_UFS(dev); + + ufs_unrealize(&s->ufs); +} + +static void ufs_sysbus_init(Object *obj) +{ + SysbusUfsState *s = SYSBUS_UFS(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->ufs.irq); +} + +static const Property ufs_sysbus_props[] = { + DEFINE_PROP_STRING("serial", SysbusUfsState, ufs.params.serial), + DEFINE_PROP_UINT8("nutrs", SysbusUfsState, ufs.params.nutrs, 32), + DEFINE_PROP_UINT8("nutmrs", SysbusUfsState, ufs.params.nutmrs, 8), + DEFINE_PROP_BOOL("mcq", SysbusUfsState, ufs.params.mcq, false), + DEFINE_PROP_UINT8("mcq-maxq", SysbusUfsState, ufs.params.mcq_maxq, 2), + DEFINE_PROP_UINT32("wb-max-size", SysbusUfsState, ufs.params.wb_max_size, + 0x400), + DEFINE_PROP_UINT32("wb-min-size", SysbusUfsState, ufs.params.wb_min_size, + 0x100), +}; + +static const VMStateDescription ufs_sysbus_vmstate = { + .name = TYPE_SYSBUS_UFS, + .unmigratable = 1, +}; + +static void ufs_sysbus_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ufs_sysbus_realize; + dc->unrealize = ufs_sysbus_unrealize; + dc->vmsd = &ufs_sysbus_vmstate; + dc->desc = "Universal Flash Storage"; + device_class_set_props(dc, ufs_sysbus_props); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); +} + +static const TypeInfo ufs_sysbus_info = { + .name = TYPE_SYSBUS_UFS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysbusUfsState), + .instance_init = ufs_sysbus_init, + .class_init = ufs_sysbus_class_init, +}; + +static void ufs_sysbus_register_types(void) +{ + type_register_static(&ufs_sysbus_info); +} + +type_init(ufs_sysbus_register_types) diff --git a/hw/ufs/ufs-sysbus.h b/hw/ufs/ufs-sysbus.h new file mode 100644 index 0000000000..71b6787d3a --- /dev/null +++ b/hw/ufs/ufs-sysbus.h @@ -0,0 +1,22 @@ +/* + * QEMU Universal Flash Storage (UFS) sysbus controller + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_UFS_UFS_SYSBUS_H +#define HW_UFS_UFS_SYSBUS_H + +#include "hw/core/sysbus.h" +#include "ufs.h" + +#define TYPE_SYSBUS_UFS "sysbus-ufs" +OBJECT_DECLARE_SIMPLE_TYPE(SysbusUfsState, SYSBUS_UFS) + +struct SysbusUfsState { + SysBusDevice parent_obj; + + UfsHc ufs; +}; + +#endif /* HW_UFS_UFS_SYSBUS_H */ From 8fda982a7c083251635a2ce41dcc068ed0e5c124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 25 Aug 2026 11:41:14 +0400 Subject: [PATCH 581/627] hw/misc: fix trace-events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit 8041d1730871 accidentally removed the vmlaunchupdate.c trace events. Fixes: 8041d1730871 ("tests/qtest: add test for K230 gsdma") Reviewed-by: Daniel P. Berrangé Reviewed-by: Luigi Leonardi Signed-off-by: Marc-André Lureau Message-ID: <20260825074114.853069-1-marcandre.lureau@redhat.com> --- hw/misc/trace-events | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 16db4ba0cc..0b8be3d0f2 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -446,3 +446,9 @@ iommu_testdev_dma_armed(bool armed) "armed=%d" # k230_decomp_gzip.c k230_decomp_gzip_read(uint64_t offset, unsigned int size, uint64_t value) "K230 DECOMP GZIP read: [0x%"PRIx64"] size %u -> 0x%"PRIx64 k230_decomp_gzip_write(uint64_t offset, unsigned int size, uint64_t value) "K230 DECOMP GZIP write: [0x%"PRIx64"] size %u <- 0x%"PRIx64 + +# vmlaunchupdate.c +launch_update_write(void) "" +vmlaunch_reset_enter(void) "" +vm_launchupdate_finalize(void) "" +restore_host_x86_igvm(void) "" From b5102872b8de250c58442b8d83c91566d5cca2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 27 Jul 2026 00:44:10 +0400 Subject: [PATCH 582/627] migration/multifd: fix Error leak in multifd_recv_terminate_threads() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If err != NULL, free it. Fixes: 11dd7be57524 ("migration/multifd: Remove p->quit from recv side") Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu Signed-off-by: Marc-André Lureau Message-ID: <20260727-fix2-v2-11-d0c4831ed7ea@redhat.com> --- migration/multifd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/multifd.c b/migration/multifd.c index dbad525d2a..503014f76b 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1056,6 +1056,7 @@ static void multifd_recv_terminate_threads(Error *err) trace_multifd_recv_terminate_threads(err != NULL); if (qatomic_xchg(&multifd_recv_state->exiting, 1)) { + error_free(err); return; } From df42a1589fad9bd140df4e48aabc32b02bea5b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 9 Jul 2026 15:12:49 +0400 Subject: [PATCH 583/627] hw/core/machine: fix fdt memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineState fdt field is allocated by various machine types via create_device_tree(), load_device_tree(), or similar, but was never freed in machine_finalize(). Add the missing g_free() call. Reviewed-by: Zhao Liu Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Marc-André Lureau Message-ID: <20260709111249.1107640-1-marcandre.lureau@redhat.com> --- hw/core/machine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index e617f7804d..8939ae1666 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1314,6 +1314,7 @@ static void machine_finalize(Object *obj) g_free(ms->nvdimms_state); g_free(ms->numa_state); g_free(ms->audiodev); + g_free(ms->fdt); } bool machine_usb(MachineState *machine) From ab7183ed4eecb4727532e3ffe5953d127e102c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 6 Aug 2026 13:40:27 +0400 Subject: [PATCH 584/627] hw/display/qxl: validate primary surface stride against width The existing validation in qxl_create_guest_primary() checks that abs(stride) * height fits in vgamem_size and that stride is 4-byte aligned, but never checks that abs(stride) is large enough to hold one row of pixels for the declared width and format. A malicious guest can create a primary surface with a stride much smaller than width * bytes_per_pixel (e.g. stride=4 for a 64-wide 32bpp surface). The spice server rejects this via red_validate_surface(), but the return is void and QEMU unconditionally proceeds to set up the local rendering state. On the next display refresh, VNC or SDL reads width * bytes_pp per scanline from a region backed by only stride bytes per row, causing a host-side out-of-bounds read. Add three checks in qxl_create_guest_primary() before creating the surface: - reject unknown surface formats - reject zero width or height - reject surfaces where abs(stride) < width * bytes_per_pixel Also fix three related issues in qxl-render.c: - qxl_blit() used abs_stride to advance the dst pointer into the DisplaySurface, but when stride is negative the DisplaySurface is a packed buffer whose stride may be smaller. Use surface_stride() instead. - qxl_render_update_area_unlocked() uses guest_head0_width (set via QXL_IO_MONITORS_CONFIG_ASYNC) without validating it against abs_stride, bypassing the new validation. Clamp the effective width to abs_stride / bytes_pp to prevent out-of-bounds access while tolerating the normal transient where the monitor config arrives before the primary surface is resized to match. - Similarly, guest_head0_height bypasses qxl_create_guest_primary() validation. Without clamping, abs_stride * height can overrun vgamem_size, and the product can also overflow 32 bits (e.g. abs_stride=16 MiB, height=256 wraps to zero), defeating the qxl_phys2virt() bounds check. Clamp height to vgamem_size / abs_stride to prevent both. While touch it, fix some endianness issues. Fixes: CVE-2026-16271 Fixes: a19cbfb34642 ("spice: add qxl device") Fixes: 979f7ef8966b ("qxl: use guest_monitor_config for local renderer.") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3637 Reported-by: huntr bubble Signed-off-by: Marc-Andre Lureau Reviewed-by: Akihiko Odaki Message-ID: <20260806094028.640676-1-marcandre.lureau@redhat.com> --- hw/display/qxl-render.c | 66 +++++++++++++++++++++++++---------------- hw/display/qxl.c | 59 ++++++++++++++++++++++++++++++++++++ hw/display/qxl.h | 2 ++ 3 files changed, 101 insertions(+), 26 deletions(-) diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index 4799c9e8be..348ddba768 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -27,6 +27,7 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { DisplaySurface *surface = qemu_console_surface(qxl->vga.con); + int dst_stride = surface_stride(surface); uint8_t *dst = surface_data(surface); uint8_t *src; int len, i; @@ -45,14 +46,14 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) } else { src += rect->top * qxl->guest_primary.abs_stride; } - dst += rect->top * qxl->guest_primary.abs_stride; + dst += rect->top * dst_stride; src += rect->left * qxl->guest_primary.bytes_pp; dst += rect->left * qxl->guest_primary.bytes_pp; len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp; for (i = rect->top; i < rect->bottom; i++) { memcpy(dst, src, len); - dst += qxl->guest_primary.abs_stride; + dst += dst_stride; src += qxl->guest_primary.qxl_stride; } } @@ -61,30 +62,13 @@ void qxl_render_resize(PCIQXLDevice *qxl) { QXLSurfaceCreate *sc = &qxl->guest_primary.surface; - qxl->guest_primary.qxl_stride = sc->stride; - qxl->guest_primary.abs_stride = abs(sc->stride); + qxl->guest_primary.qxl_stride = le32_to_cpu(sc->stride); + qxl->guest_primary.abs_stride = abs(qxl->guest_primary.qxl_stride); qxl->guest_primary.resized++; - switch (sc->format) { - case SPICE_SURFACE_FMT_16_555: - qxl->guest_primary.bytes_pp = 2; - qxl->guest_primary.bits_pp = 15; - break; - case SPICE_SURFACE_FMT_16_565: - qxl->guest_primary.bytes_pp = 2; - qxl->guest_primary.bits_pp = 16; - break; - case SPICE_SURFACE_FMT_32_xRGB: - case SPICE_SURFACE_FMT_32_ARGB: - qxl->guest_primary.bytes_pp = 4; - qxl->guest_primary.bits_pp = 32; - break; - default: - fprintf(stderr, "%s: unhandled format: %x\n", __func__, - qxl->guest_primary.surface.format); - qxl->guest_primary.bytes_pp = 4; - qxl->guest_primary.bits_pp = 32; - break; - } + /* fallback to default bpp if format is unknown */ + qxl_format_bpp(qxl, le32_to_cpu(sc->format), + &qxl->guest_primary.bytes_pp, + &qxl->guest_primary.bits_pp); } static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) @@ -101,15 +85,45 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) DisplaySurface *surface; int width = qxl->guest_head0_width ?: qxl->guest_primary.surface.width; int height = qxl->guest_head0_height ?: qxl->guest_primary.surface.height; + uint64_t map_height; int i; + if (width <= 0 || height <= 0) { + goto end; + } + + if (qxl->guest_primary.bytes_pp > 0) { + int max_width = qxl->guest_primary.abs_stride + / qxl->guest_primary.bytes_pp; + width = MIN(width, max_width); + } + + if (qxl->guest_primary.qxl_stride < 0) { + /* qxl_blit() uses the primary height to find the first scanline. */ + height = MIN(height, (int)qxl->guest_primary.surface.height); + } + + if (qxl->guest_primary.abs_stride > 0) { + int max_height = qxl->vgamem_size / qxl->guest_primary.abs_stride; + height = MIN(height, max_height); + } + + /* + * height limits the visible update, while map_height is the guest memory + * span validated by qxl_phys2virt(). With a negative stride qxl_blit() + * addresses scanlines from the declared primary height, so a shorter + * monitor still requires validating the full primary surface. + */ + map_height = qxl->guest_primary.qxl_stride < 0 ? + qxl->guest_primary.surface.height : height; + if (qxl->guest_primary.resized) { qxl->guest_primary.resized = 0; qxl->guest_primary.data = qxl_phys2virt(qxl, qxl->guest_primary.surface.mem, MEMSLOT_GROUP_GUEST, qxl->guest_primary.abs_stride - * height); + * map_height); if (!qxl->guest_primary.data) { goto end; } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index b7d871b9ee..384b8767b8 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1489,6 +1489,47 @@ static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl) qxl_render_resize(qxl); } +/* + * Convert a SpiceSurfaceFormat to bytes per pixel and bits per pixel. + * + * Only valid for surface suitable for rendering. + */ +bool qxl_format_bpp(PCIQXLDevice *qxl, SpiceSurfaceFmt format, + uint32_t *bytes_pp, uint32_t *bits_pp) +{ + uint32_t bypp = 4; + uint32_t bipp = 32; + bool ret = true; + + switch (format) { + case SPICE_SURFACE_FMT_16_555: + bypp = 2; + bipp = 15; + break; + case SPICE_SURFACE_FMT_16_565: + bypp = 2; + bipp = 16; + break; + case SPICE_SURFACE_FMT_32_xRGB: + case SPICE_SURFACE_FMT_32_ARGB: + bypp = 4; + bipp = 32; + break; + default: + ret = false; + qxl_set_guest_bug(qxl, "%s: unhandled format: %x", __func__, format); + } + + if (bytes_pp != NULL) { + *bytes_pp = bypp; + } + if (bits_pp != NULL) { + *bits_pp = bipp; + } + + return ret; +} + static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, qxl_async_io async) { @@ -1496,6 +1537,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, QXLSurfaceCreate *sc = &qxl->guest_primary.surface; uint32_t requested_height = le32_to_cpu(sc->height); int requested_stride = le32_to_cpu(sc->stride); + uint32_t bytes_pp; if (requested_stride == INT32_MIN || abs(requested_stride) * (uint64_t)requested_height @@ -1532,6 +1574,23 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, return; } + if (!qxl_format_bpp(qxl, surface.format, &bytes_pp, NULL)) { + return; + } + + if (surface.width == 0 || surface.height == 0) { + qxl_set_guest_bug(qxl, "%s: zero dimension %ux%u", + __func__, surface.width, surface.height); + return; + } + + if ((uint64_t)surface.width * bytes_pp > abs(surface.stride)) { + qxl_set_guest_bug(qxl, "%s: stride too small for width:" + " stride %d width %u bpp %u", + __func__, surface.stride, surface.width, bytes_pp); + return; + } + surface.mouse_mode = true; surface.group_id = MEMSLOT_GROUP_GUEST; if (loadvm) { diff --git a/hw/display/qxl.h b/hw/display/qxl.h index 48d664f777..6f5b96fe86 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -181,6 +181,8 @@ void qxl_spice_oom(PCIQXLDevice *qxl); void qxl_spice_reset_memslots(PCIQXLDevice *qxl); void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); void qxl_spice_reset_cursor(PCIQXLDevice *qxl); +bool qxl_format_bpp(PCIQXLDevice *qxl, SpiceSurfaceFmt format, + uint32_t *bytes_pp, uint32_t *bits_pp); /* qxl-logger.c */ int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); From eb2b3a1fa807f47515a1d86e434c60c981310bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 5 Aug 2026 17:01:41 +0400 Subject: [PATCH 585/627] virtio-gpu: use g_try_malloc to avoid guest-triggered abort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use g_try_malloc/g_try_new0 for guest-controlled allocation, so failure returns an error to the guest rather than crashing the host (glib behaviour). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3898 Reviewed-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Message-ID: <20260805130141.211398-1-marcandre.lureau@redhat.com> --- contrib/vhost-user-gpu/vhost-user-gpu.c | 25 ++++++++++----- contrib/vhost-user-gpu/virgl.c | 6 +++- contrib/vhost-user-gpu/vugbm.c | 5 ++- hw/display/virtio-gpu-rutabaga.c | 14 +++++++-- hw/display/virtio-gpu-udmabuf.c | 7 +++-- hw/display/virtio-gpu-virgl.c | 6 +++- hw/display/virtio-gpu.c | 42 ++++++++++++++++++------- 7 files changed, 79 insertions(+), 26 deletions(-) diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c index 7864881509..933bdbb671 100644 --- a/contrib/vhost-user-gpu/vhost-user-gpu.c +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c @@ -487,7 +487,7 @@ vg_create_mapping_iov(VuGpu *g, struct virtio_gpu_ctrl_command *cmd, struct iovec **iov) { - struct virtio_gpu_mem_entry *ents; + g_autofree struct virtio_gpu_mem_entry *ents = NULL; size_t esize, s; int i; @@ -498,17 +498,22 @@ vg_create_mapping_iov(VuGpu *g, } esize = sizeof(*ents) * ab->nr_entries; - ents = g_malloc(esize); + ents = g_try_malloc(esize); + if (!ents && esize) { + return -1; + } s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, sizeof(*ab), ents, esize); if (s != esize) { g_critical("%s: command data size incorrect %zu vs %zu", __func__, s, esize); - g_free(ents); return -1; } - *iov = g_new0(struct iovec, ab->nr_entries); + *iov = g_try_new0(struct iovec, ab->nr_entries); + if (!*iov && ab->nr_entries) { + return -1; + } for (i = 0; i < ab->nr_entries; i++) { uint64_t len = ents[i].length; (*iov)[i].iov_len = ents[i].length; @@ -517,12 +522,10 @@ vg_create_mapping_iov(VuGpu *g, g_critical("%s: resource %d element %d", __func__, ab->resource_id, i); g_free(*iov); - g_free(ents); *iov = NULL; return -1; } } - g_free(ents); return 0; } @@ -828,8 +831,14 @@ vg_resource_flush(VuGpu *g, PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) / 8; size_t size = width * height * bpp; - void *p = g_malloc(VHOST_USER_GPU_HDR_SIZE + - sizeof(VhostUserGpuUpdate) + size); + void *p = g_try_malloc(VHOST_USER_GPU_HDR_SIZE + + sizeof(VhostUserGpuUpdate) + size); + if (!p) { + pixman_region_fini(®ion); + pixman_region_fini(&finalregion); + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + break; + } VhostUserGpuMsg *msg = p; msg->request = VHOST_USER_GPU_UPDATE; msg->size = sizeof(VhostUserGpuUpdate) + size; diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c index 550fd03bf5..20bae57d0f 100644 --- a/contrib/vhost-user-gpu/virgl.c +++ b/contrib/vhost-user-gpu/virgl.c @@ -209,7 +209,11 @@ virgl_cmd_submit_3d(VuGpu *g, return; } - buf = g_malloc(cs.size); + buf = g_try_malloc(cs.size); + if (!buf && cs.size) { + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, sizeof(cs), buf, cs.size); if (s != cs.size) { diff --git a/contrib/vhost-user-gpu/vugbm.c b/contrib/vhost-user-gpu/vugbm.c index 710d545297..e2d8385fd8 100644 --- a/contrib/vhost-user-gpu/vugbm.c +++ b/contrib/vhost-user-gpu/vugbm.c @@ -13,7 +13,10 @@ static bool mem_alloc_bo(struct vugbm_buffer *buf) { - buf->mmap = g_malloc((uint64_t)buf->width * buf->height * 4); + buf->mmap = g_try_malloc((uint64_t)buf->width * buf->height * 4); + if (!buf->mmap && buf->width && buf->height) { + return false; + } buf->stride = buf->width * 4; return true; } diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c index a054f8117f..041216a10d 100644 --- a/hw/display/virtio-gpu-rutabaga.c +++ b/hw/display/virtio-gpu-rutabaga.c @@ -366,10 +366,20 @@ rutabaga_cmd_submit_3d(VirtIOGPU *g, return; } - buf = g_new0(uint8_t, cs.size); + buf = g_try_new0(uint8_t, cs.size); + if (!buf && cs.size) { + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, sizeof(cs), buf, cs.size); - CHECK(s == cs.size, cmd); + if (s != cs.size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: size mismatch (%zu/%u)\n", + __func__, s, cs.size); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } rutabaga_cmd.ctx_id = cs.hdr.ctx_id; rutabaga_cmd.cmd = buf; diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 5f08c855dd..816f52a514 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -39,8 +39,11 @@ static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res) return; } - list = g_malloc0(sizeof(struct udmabuf_create_list) + - sizeof(struct udmabuf_create_item) * res->iov_cnt); + list = g_try_malloc0(sizeof(struct udmabuf_create_list) + + sizeof(struct udmabuf_create_item) * res->iov_cnt); + if (!list) { + return; + } for (i = 0; i < res->iov_cnt; i++) { rcu_read_lock(); diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c index 6e298f997d..9bda572426 100644 --- a/hw/display/virtio-gpu-virgl.c +++ b/hw/display/virtio-gpu-virgl.c @@ -620,7 +620,11 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g, return; } - buf = g_malloc(cs.size); + buf = g_try_malloc(cs.size); + if (!buf && cs.size) { + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, sizeof(cs), buf, cs.size); if (s != cs.size) { diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index fbb6fec7a0..9eb010082d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -892,7 +892,10 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, } esize = sizeof(*ents) * nr_entries; - ents = g_malloc(esize); + ents = g_try_malloc(esize); + if (!ents && esize) { + return -1; + } s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, offset, ents, esize); if (s != esize) { @@ -913,6 +916,7 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, hwaddr len; void *map; + /* TODO: a common DMA map SG helper */ do { len = l; map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, a, &len, @@ -921,20 +925,27 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, if (!map) { qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" " element %d\n", __func__, e); - virtio_gpu_cleanup_mapping_iov(g, *iov, v); - g_free(ents); - *iov = NULL; - if (addr) { - g_free(*addr); - *addr = NULL; - } - return -1; + goto err; } if (!(v % 16)) { - *iov = g_renew(struct iovec, *iov, v + 16); + struct iovec *new_iov; + new_iov = g_try_renew(struct iovec, *iov, v + 16); + if (!new_iov) { + dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, map, len, + DMA_DIRECTION_TO_DEVICE, len); + goto err; + } + *iov = new_iov; if (addr) { - *addr = g_renew(uint64_t, *addr, v + 16); + uint64_t *new_addr; + new_addr = g_try_renew(uint64_t, *addr, v + 16); + if (!new_addr) { + dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, map, len, + DMA_DIRECTION_TO_DEVICE, len); + goto err; + } + *addr = new_addr; } } (*iov)[v].iov_base = map; @@ -952,6 +963,15 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, g_free(ents); return 0; + +err: + virtio_gpu_cleanup_mapping_iov(g, *iov, v); + *iov = NULL; + if (addr) { + g_clear_pointer(addr, g_free); + } + g_free(ents); + return -1; } void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, From 0e62034ca10f9d71fba43c8277a6590540217df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 28 Jun 2026 23:50:46 +0400 Subject: [PATCH 586/627] crypto: fix build against nettle >= 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sha.h has been deprecated. It seems we can rely on sha1.h/sha2.h since we depend on >= 3.7.3. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4184 Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Signed-off-by: Marc-André Lureau --- crypto/hash-nettle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c index 53f68301ef..2589bbf4c1 100644 --- a/crypto/hash-nettle.c +++ b/crypto/hash-nettle.c @@ -24,7 +24,8 @@ #include "crypto/hash.h" #include "hashpriv.h" #include -#include +#include +#include #include #ifdef CONFIG_CRYPTO_SM3 #include From f4b26072289084a0b182c1faa28aa338fe861c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 May 2026 10:56:33 +0400 Subject: [PATCH 587/627] tests: tag slow tests with 'slow' suite for easy filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add several RCU and thread-pool unit tests to the slow_tests dict, and tag all slow tests (both qtest and unit) with a 'slow' suite so they can be excluded or selected via meson test --suite/--no-suite. Acked-by: Fabiano Rosas Signed-off-by: Marc-André Lureau Message-ID: <20260512065633.3542562-1-marcandre.lureau@redhat.com> --- tests/qtest/meson.build | 3 ++- tests/unit/meson.build | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 739df71d8d..cbdef5a545 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -510,6 +510,7 @@ foreach dir : target_dirs protocol: 'tap', timeout: slow_qtests.get(test, 60), priority: slow_qtests.get(test, 60), - suite: ['qtest', 'qtest-' + target_base]) + suite: ['qtest', 'qtest-' + target_base] + + (slow_qtests.has_key(test) ? ['slow'] : [])) endforeach endforeach diff --git a/tests/unit/meson.build b/tests/unit/meson.build index dc3fb954c0..3a9866c1f2 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -184,6 +184,12 @@ slow_tests = { 'test-crypto-tlscredsx509': 90, 'test-crypto-tlssession': 90, 'test-replication': 60, + 'rcutorture': 30, + 'test-rcu-list': 30, + 'test-rcu-simpleq': 30, + 'test-rcu-tailq': 30, + 'test-rcu-slist': 30, + 'test-thread-pool': 30, } foreach test_name, extra: tests @@ -205,5 +211,6 @@ foreach test_name, extra: tests protocol: 'tap', timeout: slow_tests.get(test_name, 30), priority: slow_tests.get(test_name, 30), - suite: ['unit']) + suite: ['unit'] + + (slow_tests.has_key(test_name) ? ['slow'] : [])) endforeach From baca25172d8c195b9abbe6f8a3ab5915dba09a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 20 Aug 2026 17:20:14 +0400 Subject: [PATCH 588/627] ui/egl: fix render node cleanup order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASAN detected some memory leaks when terminating. Release thread-bound EGL state first, destroy the context and terminate the display while the GBM device is still alive, then destroy GBM and close the render-node fd. Reviewed-by: Akihiko Odaki Fixes: a3cf9b55bbdc ("ui/egl: implement display and EGL cleanup") Signed-off-by: Marc-André Lureau Message-ID: <20260820132014.2729748-1-marcandre.lureau@redhat.com> --- ui/egl-helpers.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index d689f187c4..e89cc7c49a 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -736,19 +736,22 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp) void egl_cleanup(void) { + if (qemu_egl_display) { + eglReleaseThread(); + } + if (qemu_egl_rn_ctx) { eglDestroyContext(qemu_egl_display, qemu_egl_rn_ctx); qemu_egl_rn_ctx = NULL; } + if (qemu_egl_display) { + eglTerminate(qemu_egl_display); + qemu_egl_display = NULL; + } + #ifdef CONFIG_GBM g_clear_pointer(&qemu_egl_rn_gbm_dev, gbm_device_destroy); g_clear_fd(&qemu_egl_rn_fd, NULL); #endif - - if (qemu_egl_display) { - eglReleaseThread(); - eglTerminate(qemu_egl_display); - qemu_egl_display = NULL; - } } From 86fc385ca082b21683b42c7c7c5cd709ce903130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 20 Aug 2026 17:19:33 +0400 Subject: [PATCH 589/627] ui/egl: fix qemu_egl_display type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EGLDisplay is already a pointer type (void *), so declaring qemu_egl_display as EGLDisplay * makes it void **, which doesn't match any of its usages. Fixes: 7ced9e9f6da2 ("ui: add egl-helpers") Reviewed-by: Akihiko Odaki Signed-off-by: Marc-André Lureau Message-ID: <20260820131933.2729240-1-marcandre.lureau@redhat.com> --- include/ui/egl-helpers.h | 2 +- ui/egl-helpers.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index 405ddd9125..679c79eacd 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -9,7 +9,7 @@ #include "ui/console.h" #include "ui/shader.h" -extern EGLDisplay *qemu_egl_display; +extern EGLDisplay qemu_egl_display; extern EGLConfig qemu_egl_config; extern DisplayGLMode qemu_egl_mode; extern bool qemu_egl_angle_d3d; diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index e89cc7c49a..8e3729a54d 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -25,7 +25,7 @@ #include "trace.h" #include "standard-headers/drm/drm_fourcc.h" -EGLDisplay *qemu_egl_display; +EGLDisplay qemu_egl_display; EGLConfig qemu_egl_config; DisplayGLMode qemu_egl_mode; bool qemu_egl_angle_d3d; From 4fd6561228c37b6a210242157cf6c1e574b364dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 15 Aug 2026 11:24:21 +0400 Subject: [PATCH 590/627] tests/functional: fix pylint false positives for cv2 module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add generated-members=cv2.* to pylintrc so pylint skips member checking on the cv2 C extension module, whose members are not visible to static analysis. Silence: 2026-08-15 10:42:08,710 - INFO: qemu-test.test_pylint Checking files in /home/elmarco/src/qemu.qom-qapi/tests/functional/arm with pylint 2026-08-15 10:42:10,941 - ERROR: qemu-test.test_pylint "/home/elmarco/src/qemu.qom-qapi/tests/functional/arm/test_integratorcp.py:83: E1101: Module 'cv2' has no 'imread' member (no-member)" Note: I also tried with extension-pkg-allow-list, but that didn't work for some reason. Reviewed-by: Thomas Huth Signed-off-by: Marc-André Lureau Message-ID: <20260815072421.4117291-1-marcandre.lureau@redhat.com> --- tests/functional/pylintrc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/functional/pylintrc b/tests/functional/pylintrc index 949bea611f..373aabd6ca 100644 --- a/tests/functional/pylintrc +++ b/tests/functional/pylintrc @@ -79,6 +79,12 @@ disable=bad-inline-option, useless-suppression, +[TYPECHECK] + +# cv2 is a C extension module whose members are not visible to pylint +generated-members=cv2.* + + [SIMILARITIES] # Minimum lines number of a similarity. From ddf5738503e2ba6adb74359abf3b6e7aa81af420 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Wed, 3 Jun 2026 11:11:37 -0300 Subject: [PATCH 591/627] chardev: Don't unregister yank upon async path connection failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 5c102ac9 ("chardev: Consolidate yank registration") has moved yank registration in the tcp_chr_connect_client_async() path to after the connection is successful. If qio_channel_socket_connect_sync() fails early, there will be no yank registered to be unregistered in the error path, leading to assert. Remove the now-extraneous unregister. Cc: qemu-stable@nongnu.org Fixes: 5c102ac9 ("chardev: Consolidate yank registration") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3528 Signed-off-by: Fabiano Rosas Reviewed-by: Marc-André Lureau Message-ID: <20260603141137.1108963-1-farosas@suse.de> --- chardev/char-socket.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index b629575fcf..81bac42a15 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1128,11 +1128,6 @@ static void qemu_chr_socket_connected(QIOTask *task, void *opaque) if (qio_task_propagate_error(task, &err)) { tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); - if (s->registered_yank) { - yank_unregister_function(CHARDEV_YANK_INSTANCE(chr->label), - char_socket_yank_iochannel, - QIO_CHANNEL(sioc)); - } check_report_connect_error(chr, err); goto cleanup; } From 418396be8013386a81f8d8d89ac0effcf03a64b6 Mon Sep 17 00:00:00 2001 From: Warisjeet Singh Date: Mon, 24 Aug 2026 12:47:26 -0400 Subject: [PATCH 592/627] hw/display/vga: fix text-mode OOB write after a graphics surface switch vga_draw_text() decides whether the console surface needs a resize from its geometry cache, but none of the cache terms observe the graphics renderer having replaced the console surface in between: - last_width/last_height are shared with vga_draw_graphic(), which stores them in pixels while the text path stores characters; - last_depth stays 0 for legacy (non-VBE) graphics modes, because vga_get_bpp() only reports a depth when VBE is enabled, so the "s->last_depth" term that normally forces a resize after a graphics frame does not fire. So a graphics frame that shrinks the console surface (e.g. 80x25 pixels) followed by a text frame with matching character geometry (80x25 chars) skips the resize, and the glyph loop then paints width*cw x height*cheight pixels into the smaller surface, out of bounds, with guest-controlled (DAC palette) values, on every display refresh. Separate the geometry cache per renderer: text paths (vga_draw_text, vga_update_text, and the text handling in vga_invalidate_display / vga_common_reset) now only manipulate last_text_{width,height}, in characters; last_{width,height} become graphics-only, in pixels. Additionally, make the text path compare the pixel size it is about to paint against the console surface's actual dimensions. The surface check is the load-bearing term: caches in either unit cannot see the other renderer swapping the surface, the surface can. Fixes: CVE-2026-77913 Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4215 Cc: qemu-stable@nongnu.org Signed-off-by: Warisjeet Singh (sin99xx) Message-ID: --- hw/display/vga.c | 37 ++++++++++++++++++++++--------------- hw/display/vga_int.h | 3 ++- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/hw/display/vga.c b/hw/display/vga.c index da0c331486..cb0e28b79b 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1241,7 +1241,10 @@ static void vga_draw_text(VGACommonState *s, int full_update) return; } - if (width != s->last_width || height != s->last_height || + if (surface == NULL || + surface_width(surface) != width * cw || + surface_height(surface) != height * cheight || + width != s->last_text_width || height != s->last_text_height || cw != s->last_cw || cheight != s->last_ch || s->last_depth) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; @@ -1249,8 +1252,8 @@ static void vga_draw_text(VGACommonState *s, int full_update) surface = qemu_console_surface(s->con); qemu_console_text_resize(s->con, width, height); s->last_depth = 0; - s->last_width = width; - s->last_height = height; + s->last_text_width = width; + s->last_text_height = height; s->last_ch = cheight; s->last_cw = cw; full_update = 1; @@ -1845,6 +1848,8 @@ static void vga_invalidate_display(void *opaque) s->last_width = -1; s->last_height = -1; + s->last_text_width = -1; + s->last_text_height = -1; } void vga_common_reset(VGACommonState *s) @@ -1887,6 +1892,8 @@ void vga_common_reset(VGACommonState *s) s->last_ch = 0; s->last_width = 0; s->last_height = 0; + s->last_text_width = 0; + s->last_text_height = 0; s->last_scr_width = 0; s->last_scr_height = 0; s->cursor_start = 0; @@ -1938,8 +1945,8 @@ static void vga_update_text(void *opaque, uint32_t *chardata) s->graphic_mode = graphic_mode; full_update = 1; } - if (s->last_width == -1) { - s->last_width = 0; + if (s->last_text_width == -1) { + s->last_text_width = 0; full_update = 1; } @@ -1978,15 +1985,15 @@ static void vga_update_text(void *opaque, uint32_t *chardata) break; } - if (width != s->last_width || height != s->last_height || + if (width != s->last_text_width || height != s->last_text_height || cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); qemu_console_text_resize(s->con, width, height); s->last_depth = 0; - s->last_width = width; - s->last_height = height; + s->last_text_width = width; + s->last_text_height = height; s->last_ch = cheight; s->last_cw = cw; full_update = 1; @@ -2071,22 +2078,22 @@ static void vga_update_text(void *opaque, uint32_t *chardata) } /* Display a message */ - s->last_width = 60; - s->last_height = height = 3; + s->last_text_width = 60; + s->last_text_height = height = 3; qemu_console_text_set_cursor(s->con, -1, -1); - qemu_console_text_resize(s->con, s->last_width, height); + qemu_console_text_resize(s->con, s->last_text_width, height); - for (dst = chardata, i = 0; i < s->last_width * height; i ++) + for (dst = chardata, i = 0; i < s->last_text_width * height; i ++) *dst++ = ' '; size = strlen(msg_buffer); - width = (s->last_width - size) / 2; - dst = chardata + s->last_width + width; + width = (s->last_text_width - size) / 2; + dst = chardata + s->last_text_width + width; for (i = 0; i < size; i ++) *dst++ = ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE, QEMU_COLOR_BLACK, 1); - qemu_console_text_update(s->con, 0, 0, s->last_width, height); + qemu_console_text_update(s->con, 0, 0, s->last_text_width, height); } static uint64_t vga_mem_read(void *opaque, hwaddr addr, diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 5664317ecd..ca69ae9815 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -122,7 +122,8 @@ typedef struct VGACommonState { uint32_t plane_updated; uint32_t last_line_offset; uint8_t last_cw, last_ch; - uint32_t last_width, last_height; /* in chars or pixels */ + uint32_t last_width, last_height; /* in pixels (graphics renderer) */ + uint32_t last_text_width, last_text_height; /* in chars (text renderer) */ uint32_t last_scr_width, last_scr_height; /* in pixels */ uint32_t last_depth; /* in bits */ bool last_byteswap; From 14f2511f5952517a7daae6dc5986e8439f2bbb66 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 25 Aug 2026 16:28:47 +0900 Subject: [PATCH 593/627] hw/display/virtio-gpu: Avoid creating empty udmabuf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtio specification allows creating a blob without backing storage attached. However, virtio-gpu attempts to create an empty udmabuf for such a blob. The ioctl fails with EINVAL and emits a spurious warning. Avoid the invalid ioctl. Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob") Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260825-dmabuf-v2-1-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu.c | 102 +++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 9eb010082d..50c4dcd408 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -363,27 +363,29 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, res->resource_id = cblob.resource_id; res->blob_size = cblob.size; - ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob), - cmd, &res->addrs, &res->iov, - &res->iov_cnt); - if (ret < 0) { - cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; - g_free(res); - return; + if (cblob.nr_entries) { + ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob), + cmd, &res->addrs, &res->iov, + &res->iov_cnt); + if (ret < 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + g_free(res); + return; + } + + if (iov_size(res->iov, res->iov_cnt) < res->blob_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: backing storage smaller than blob size\n", + __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + virtio_gpu_cleanup_mapping(g, res); + g_free(res); + return; + } + + virtio_gpu_init_udmabuf(res); } - if (res->iov_cnt > 0 && - iov_size(res->iov, res->iov_cnt) < res->blob_size) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: backing storage smaller than blob size\n", - __func__); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; - virtio_gpu_cleanup_mapping(g, res); - g_free(res); - return; - } - - virtio_gpu_init_udmabuf(res); QTAILQ_INSERT_HEAD(&g->reslist, res, next); } @@ -1389,8 +1391,6 @@ static bool virtio_gpu_load_restore_mapping(VirtIOGPU *g, } } - QTAILQ_INSERT_HEAD(&g->reslist, res, next); - g->hostmem += res->hostmem; return true; } @@ -1469,6 +1469,8 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return -EINVAL; } + QTAILQ_INSERT_HEAD(&g->reslist, res, next); + g->hostmem += hostmem; resource_id = qemu_get_be32(f); } @@ -1528,36 +1530,38 @@ static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size, res->blob_size = qemu_get_be32(f); res->iov_cnt = qemu_get_be32(f); - res->addrs = g_try_new(uint64_t, res->iov_cnt); - res->iov = g_try_new(struct iovec, res->iov_cnt); - if (res->iov_cnt && (!res->addrs || !res->iov)) { - g_free(res->addrs); - g_free(res->iov); - g_free(res); - return -EINVAL; + if (res->iov_cnt) { + res->addrs = g_try_new(uint64_t, res->iov_cnt); + res->iov = g_try_new(struct iovec, res->iov_cnt); + if (!res->addrs || !res->iov) { + g_free(res->addrs); + g_free(res->iov); + g_free(res); + return -EINVAL; + } + + /* read data */ + for (i = 0; i < res->iov_cnt; i++) { + res->addrs[i] = qemu_get_be64(f); + res->iov[i].iov_len = qemu_get_be32(f); + } + + if (iov_size(res->iov, res->iov_cnt) < res->blob_size) { + g_free(res->addrs); + g_free(res->iov); + g_free(res); + return -EINVAL; + } + + if (!virtio_gpu_load_restore_mapping(g, res)) { + g_free(res); + return -EINVAL; + } + + virtio_gpu_init_udmabuf(res); } - /* read data */ - for (i = 0; i < res->iov_cnt; i++) { - res->addrs[i] = qemu_get_be64(f); - res->iov[i].iov_len = qemu_get_be32(f); - } - - if (res->iov_cnt > 0 && - iov_size(res->iov, res->iov_cnt) < res->blob_size) { - g_free(res->addrs); - g_free(res->iov); - g_free(res); - return -EINVAL; - } - - if (!virtio_gpu_load_restore_mapping(g, res)) { - g_free(res); - return -EINVAL; - } - - virtio_gpu_init_udmabuf(res); - + QTAILQ_INSERT_HEAD(&g->reslist, res, next); resource_id = qemu_get_be32(f); } From 3f163489c6efe8fb0de8e18097773f955ebaaa31 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 25 Aug 2026 16:28:48 +0900 Subject: [PATCH 594/627] hw/display/virtio-gpu: Avoid mmap() for empty blob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling mmap() for an empty blob fails with EINVAL, causing QEMU to emit a spurious warning. Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260825-dmabuf-v2-2-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu-udmabuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 816f52a514..ba02ba9e86 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -139,7 +139,7 @@ void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) if (res->iov_cnt == 1 && res->iov[0].iov_len < 4096) { pdata = res->iov[0].iov_base; - } else { + } else if (res->blob_size) { virtio_gpu_create_udmabuf(res); if (res->dmabuf_fd < 0) { return; From cd71534b225c17c75ca745f13084abff12536f8b Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 25 Aug 2026 16:28:49 +0900 Subject: [PATCH 595/627] hw/display/virtio-gpu: Propagate udmabuf errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate udmabuf errors so that the requested operation will be canceled instead of producing an incomplete result and the user can notice the failure. Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob") Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection") Fixes: 4ae1c5c7d6f3 ("hw/display/virtio-gpu: Initialize blob mapping for ATTACH_BACKING") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260825-dmabuf-v2-3-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu-udmabuf-stubs.c | 3 ++- hw/display/virtio-gpu-udmabuf.c | 8 +++++--- hw/display/virtio-gpu.c | 18 ++++++++++++++---- include/hw/virtio/virtio-gpu.h | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/hw/display/virtio-gpu-udmabuf-stubs.c b/hw/display/virtio-gpu-udmabuf-stubs.c index 85d03935a3..0883bf05fa 100644 --- a/hw/display/virtio-gpu-udmabuf-stubs.c +++ b/hw/display/virtio-gpu-udmabuf-stubs.c @@ -7,9 +7,10 @@ bool virtio_gpu_have_udmabuf(void) return false; } -void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) +bool virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) { /* nothing (stub) */ + return false; } void virtio_gpu_fini_udmabuf(VirtIOGPU *g, struct virtio_gpu_simple_resource *res) diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index ba02ba9e86..c230509852 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -131,7 +131,7 @@ bool virtio_gpu_have_udmabuf(void) return memfd_backend; } -void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) +bool virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) { void *pdata = NULL; @@ -142,17 +142,19 @@ void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res) } else if (res->blob_size) { virtio_gpu_create_udmabuf(res); if (res->dmabuf_fd < 0) { - return; + return false; } virtio_gpu_remap_udmabuf(res); if (!res->remapped) { virtio_gpu_destroy_udmabuf(res); - return; + return false; } pdata = res->remapped; } res->blob = pdata; + + return true; } static void virtio_gpu_free_dmabuf(VirtIOGPU *g, VGPUDMABuf *dmabuf) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 50c4dcd408..7f3301a9ac 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -383,7 +383,12 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g, return; } - virtio_gpu_init_udmabuf(res); + if (!virtio_gpu_init_udmabuf(res)) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + virtio_gpu_cleanup_mapping(g, res); + g_free(res); + return; + } } QTAILQ_INSERT_HEAD(&g->reslist, res, next); @@ -1045,8 +1050,9 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } - if (!res->image) { - virtio_gpu_init_udmabuf(res); + if (!res->image && !virtio_gpu_init_udmabuf(res)) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + virtio_gpu_cleanup_mapping(g, res); } } @@ -1558,7 +1564,11 @@ static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size, return -EINVAL; } - virtio_gpu_init_udmabuf(res); + if (!virtio_gpu_init_udmabuf(res)) { + virtio_gpu_cleanup_mapping(g, res); + g_free(res); + return -EINVAL; + } } QTAILQ_INSERT_HEAD(&g->reslist, res, next); diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 220231ec9d..69b5ee2e38 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -388,7 +388,7 @@ bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb, /* virtio-gpu-udmabuf.c */ bool virtio_gpu_have_udmabuf(void); -void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res); +bool virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res); void virtio_gpu_fini_udmabuf(VirtIOGPU *g, struct virtio_gpu_simple_resource *res); int virtio_gpu_update_dmabuf(VirtIOGPU *g, From d3c2da174ca69161eafeb82d98d0117150017909 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 25 Aug 2026 16:28:50 +0900 Subject: [PATCH 596/627] hw/display/virtio-gpu: Check cursor data presence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject a blob that lacks the backing storage for VIRTIO_GPU_CMD_UPDATE_CURSOR. Fixes: bdd53f739273 ("virtio-gpu: Update cursor data using blob") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260825-dmabuf-v2-4-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7f3301a9ac..01549d29d8 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -63,8 +63,8 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g, } data = pixman_image_get_data(res->image); } else { - if (res->blob_size < (s->current_cursor->width * - s->current_cursor->height * 4)) { + if (!res->iov || res->blob_size < (s->current_cursor->width * + s->current_cursor->height * 4)) { return; } data = res->blob; From 884363589b68049cb344b8f8089464bada32a8e7 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 25 Aug 2026 16:28:51 +0900 Subject: [PATCH 597/627] hw/display/virtio-gpu: Validate resource per command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_gpu_find_check_resource() checks if the resource has backing storage if require_backing is true, but the condition conflates backing storage attachment with host representation; it checks !res->iov || (!res->image && !res->blob), but !res->iov is sufficient. Furthermore, its callers passing true as require_backing have different requirements: - virtio_gpu_transfer_to_host_2d() requires a non-blob with backing storage. - virtio_gpu_set_scanout() requires a non-blob but does not require backing storage. - virtio_gpu_set_scanout_blob() requires a blob with backing storage. - virtio_gpu_resource_detach_backing() accepts any resource. Remove the require_backing parameter and open-code checks appropriate for each function instead. Fixes: 25c001a40346 ("virtio-gpu: Add virtio_gpu_find_check_resource") Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob") Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob") Signed-off-by: Akihiko Odaki Reviewed-by: Marc-André Lureau Message-ID: <20260825-dmabuf-v2-5-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp> --- hw/display/virtio-gpu.c | 66 ++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 01549d29d8..55a1c7f80f 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -37,7 +37,6 @@ static struct virtio_gpu_simple_resource * virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, - bool require_backing, const char *caller, uint32_t *error); static void virtio_gpu_reset_bh(void *opaque); @@ -50,8 +49,7 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g, uint32_t pixels; void *data; - res = virtio_gpu_find_check_resource(g, resource_id, false, - __func__, NULL); + res = virtio_gpu_find_check_resource(g, resource_id, __func__, NULL); if (!res) { return; } @@ -128,7 +126,6 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) static struct virtio_gpu_simple_resource * virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, - bool require_backing, const char *caller, uint32_t *error) { struct virtio_gpu_simple_resource *res; @@ -143,17 +140,6 @@ virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, return NULL; } - if (require_backing) { - if (!res->iov || (!res->image && !res->blob)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: no backing storage %d\n", - caller, resource_id); - if (error) { - *error = VIRTIO_GPU_RESP_ERR_UNSPEC; - } - return NULL; - } - } - return res; } @@ -474,9 +460,24 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, virtio_gpu_t2d_bswap(&t2d); trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); - res = virtio_gpu_find_check_resource(g, t2d.resource_id, true, + res = virtio_gpu_find_check_resource(g, t2d.resource_id, __func__, &cmd->error); - if (!res || res->blob) { + if (!res) { + return; + } + + if (!res->image) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n", + __func__, t2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (!res->iov) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: resource %d has no backing storage\n", + __func__, t2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; return; } @@ -533,7 +534,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, trace_virtio_gpu_cmd_res_flush(rf.resource_id, rf.r.width, rf.r.height, rf.r.x, rf.r.y); - res = virtio_gpu_find_check_resource(g, rf.resource_id, false, + res = virtio_gpu_find_check_resource(g, rf.resource_id, __func__, &cmd->error); if (!res) { return; @@ -771,12 +772,19 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, return; } - res = virtio_gpu_find_check_resource(g, ss.resource_id, true, + res = virtio_gpu_find_check_resource(g, ss.resource_id, __func__, &cmd->error); if (!res) { return; } + if (!res->image) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + fb.format = pixman_image_get_format(res->image); bytes_pp = virtio_gpu_format_bytes_pp(fb.format); fb.width = pixman_image_get_width(res->image); @@ -866,12 +874,28 @@ static void virtio_gpu_set_scanout_blob(VirtIOGPU *g, return; } - res = virtio_gpu_find_check_resource(g, ss.resource_id, true, + res = virtio_gpu_find_check_resource(g, ss.resource_id, __func__, &cmd->error); if (!res) { return; } + if (res->image) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: resource %d is not a blob\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (!res->iov) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: resource %d has no backing storage\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) { cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; return; @@ -1067,7 +1091,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g, virtio_gpu_bswap_32(&detach, sizeof(detach)); trace_virtio_gpu_cmd_res_back_detach(detach.resource_id); - res = virtio_gpu_find_check_resource(g, detach.resource_id, true, + res = virtio_gpu_find_check_resource(g, detach.resource_id, __func__, &cmd->error); if (!res) { return; From 0846740652d1333369265fa075708b5a386c5ff6 Mon Sep 17 00:00:00 2001 From: Christian Quante Date: Tue, 25 Aug 2026 09:51:26 +0200 Subject: [PATCH 598/627] hw/input/ps2: answer unknown mouse commands with a resend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ps2_write_mouse() ends its command switch with a bare "default: break;", so an unknown command draws no reply at all. A real PS/2 device answers every byte it is given -- ACK (0xFA) when it understood one, resend (0xFE) when it did not -- and a guest that gets nothing back is left waiting out its reply timeout. The keyboard path in the same file has answered unknown commands with KBD_REPLY_RESEND since commit 06b3611fc2a3 ("ps2: reject unknown commands, instead of blindly accepting them"). Two guests were measured on this. OS/2 probes the mouse with the vendor command 0xBB, which QEMU does not implement, and then polls the status port until its own timeout runs out. On a Warp 3 guest that wait costs about 25 ms of every boot under TCG, and 2.1 s under KVM, where each of those polls leaves the guest. With this patch the wait ends on the first read: the guest takes the same error path an unexpected reply would, and does not retry. Linux runs into two of them while probing the mouse: the ALPS probe sends 0xEC (reset wrap mode), which ps2_write_mouse() only answers while the mouse is in wrap mode, and the TrackPoint probe sends 0xE1. Each costs libps2 a 200 ms reply timeout. Timing the psmouse detection from a mark written to /dev/kmsg to the kernel's "input:" line, three boots each of a 6.18.35 kernel under TCG: 426.7/428.8/441.6 ms without this patch, 21.4/21.6/21.2 ms with it. The mouse is detected identically either way; only the error the probe ends in changes, from -EIO (nothing came back at all) to -EPROTO (libps2 gives up after its second attempt). The specification's second stage -- 0xFC (Error) when the byte after a rejected one is invalid as well -- is deliberately left out. It would need state that has to survive migration, no guest is known to test for it, and the keyboard path does without it as well. Cc: qemu-stable@nongnu.org Signed-off-by: Christian Quante Reviewed-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20260825075127.34876-2-christian@quante.one> --- hw/input/ps2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 5516eb262d..e8300d2d83 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -73,6 +73,7 @@ #define AUX_SET_DEFAULT 0xF6 #define AUX_RESET 0xFF /* Reset aux device */ #define AUX_ACK 0xFA /* Command byte ACK. */ +#define AUX_RESEND 0xFE /* Command NACK, send the cmd again */ #define MOUSE_STATUS_REMOTE 0x40 #define MOUSE_STATUS_ENABLED 0x20 @@ -955,6 +956,11 @@ void ps2_write_mouse(PS2MouseState *s, int val) s->mouse_type); break; default: + /* + * A PS/2 device answers every command it is given; an unknown + * one draws a resend. + */ + ps2_queue(ps2, AUX_RESEND); break; } break; From a88191a0caecdfba440682e3c120b439681ccaca Mon Sep 17 00:00:00 2001 From: Christian Quante Date: Tue, 25 Aug 2026 09:51:27 +0200 Subject: [PATCH 599/627] hw/input/ps2: say why unknown keyboard commands draw a resend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keyboard path has answered unknown commands with KBD_REPLY_RESEND since commit 06b3611fc2a3 ("ps2: reject unknown commands, instead of blindly accepting them"), but never said why. Give it the comment the mouse path just gained, so the reasoning is written down in both places. Suggested-by: Akihiko Odaki Signed-off-by: Christian Quante Reviewed-by: Marc-André Lureau Reviewed-by: Akihiko Odaki Message-ID: <20260825075127.34876-3-christian@quante.one> --- hw/input/ps2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/input/ps2.c b/hw/input/ps2.c index e8300d2d83..01af4350b3 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -647,6 +647,10 @@ void ps2_write_keyboard(PS2KbdState *s, int val) ps2_cqueue_1(ps2, KBD_REPLY_ACK); break; default: + /* + * A PS/2 device answers every command it is given; an unknown + * one draws a resend. + */ ps2_cqueue_1(ps2, KBD_REPLY_RESEND); break; } From 6c712a86f6c8d8bdd8a3ba6b39cbcd9550668c36 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 15:35:29 +0200 Subject: [PATCH 600/627] hw/ide: reject an unsupported CHS translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ide_set_sector() divides by (s->heads * s->sectors) when the drive is addressed in CHS mode. Both come from the guest via INITIALIZE DEVICE PARAMETERS, and cmd_specify() stored them without any check, so a guest asking for zero sectors per logical track killed QEMU with SIGFPE on the completion of the first CHS read or write. s->heads is safe, as the command passes a heads-1 value. The count has an upper bound as well. The legacy sector count register is eight bits wide, but handle_cmd() takes the count from a 16 bit field of the register FIS, so an AHCI guest can ask for up to 65535 sectors per track, and the CHS branch of ide_get_sector() then overflows the int it multiplies cylinder, heads and sectors in. ATA-5 6.2 numbers CHS sectors from one and ATA-2 D.2.8 limits IDENTIFY DEVICE word 56 to 1 through 255, so neither end is a translation a device may accept. ATA-5 8.16.6 requires an unsupported one to be reported as an aborted command: do that, leave the translation in effect alone, and refuse the value rather than checking it at every use. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Cc: qemu-stable@nongnu.org Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Reported-by: Zheyu Ma Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2399 Signed-off-by: Denis V. Lunev Reviewed-by: Philippe Mathieu-Daudé --- hw/ide/core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index fb9bf11b45..747fa71677 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1655,14 +1655,21 @@ static bool cmd_check_power_mode(IDEState *s, uint8_t cmd) /* INITIALIZE DEVICE PARAMETERS */ static bool cmd_specify(IDEState *s, uint8_t cmd) { - if (s->blk && s->drive_kind != IDE_CD) { - s->heads = (s->select & (ATA_DEV_HS)) + 1; - s->sectors = s->nsector; - ide_bus_set_irq(s->bus); - } else { + if (!s->blk || s->drive_kind == IDE_CD) { ide_abort_command(s); + return true; } + /* ATA-2 D.2.8 limits IDENTIFY DEVICE word 56, and the count, to 1..255 */ + if (s->nsector == 0 || s->nsector > 255) { + ide_abort_command(s); + return true; + } + + s->heads = (s->select & (ATA_DEV_HS)) + 1; + s->sectors = s->nsector; + ide_bus_set_irq(s->bus); + return true; } From 0905ef5b6d483da0e27831152fdde059595244b9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 4 Aug 2026 18:34:44 +0200 Subject: [PATCH 601/627] tests/qtest/ide-test: cover a CHS translation with zero sectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ask for zero sectors per logical track via INITIALIZE DEVICE PARAMETERS and check that the command is aborted, that IDENTIFY DEVICE still reports the translation that was in effect before, and that a CHS read then completes normally rather than killing QEMU with SIGFPE. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index b36b0f8875..99aa5e039c 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -95,6 +95,7 @@ enum { enum { CMD_DSM = 0x06, + CMD_READ = 0x20, /* READ SECTOR(S) */ CMD_DIAGNOSE = 0x90, CMD_INIT_DP = 0x91, /* INITIALIZE DEVICE PARAMETERS */ CMD_READ_DMA = 0xc8, @@ -1194,6 +1195,66 @@ static void cdrom_read_impl(int nblocks, unsigned flags) free_pci_device(dev); } +/* Zero sectors per track has to abort (ATA-5 8.16.6), not divide by zero */ +static void test_specify_zero_sectors(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint16_t buf[256]; + uint8_t data; + int i; + + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + qpci_io_writeb(dev, ide_bar, reg_nsectors, 0); + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_INIT_DP); + + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), ERR); + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT); + + /* The refused request has to leave the default translation in effect */ + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY); + for (i = 0; i < 256; i++) { + buf[i] = qpci_io_readw(dev, ide_bar, reg_data); + } + g_assert_cmpint(buf[55], ==, 16); + g_assert_cmpint(buf[56], ==, 63); + + /* READ SECTOR(S) of CHS 0/0/1, which used to crash QEMU */ + qpci_io_writeb(dev, ide_bar, reg_nsectors, 1); + qpci_io_writeb(dev, ide_bar, reg_lba_low, 1); + qpci_io_writeb(dev, ide_bar, reg_lba_middle, 0); + qpci_io_writeb(dev, ide_bar, reg_lba_high, 0); + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_READ); + + data = ide_wait_clear(qts, BSY); + assert_bit_set(data, DRQ); + assert_bit_clear(data, ERR | DF); + for (i = 0; i < 256; i++) { + buf[i] = qpci_io_readw(dev, ide_bar, reg_data); + } + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), ERR | DF | DRQ); + + /* A supported translation is still accepted */ + qpci_io_writeb(dev, ide_bar, reg_nsectors, 32); + qpci_io_writeb(dev, ide_bar, reg_device, 7); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_INIT_DP); + + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), ERR); + + ide_test_quit(qts); + free_pci_device(dev); +} + static void test_cdrom_pio(void) { cdrom_read_impl(1, CDROM_PIO); @@ -1265,6 +1326,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); qtest_add_func("/ide/read_native", test_specify); + qtest_add_func("/ide/specify/zero_sectors", test_specify_zero_sectors); qtest_add_func("/ide/identify", test_identify); From 5e16adf5550e50e7d792d7a328f4bc0b17a53673 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 15:35:23 +0200 Subject: [PATCH 602/627] tests/qtest/libqos/ahci: allow a count and an expected error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A command that transfers no data can still take an argument in the count register of the register FIS, and a test may well expect such a command to be aborted. AHCICommand is private to the library, so add two setters: ahci_command_set_count() writes the count of a non-data command, and ahci_command_expect_error() records the error register bits the command is expected to complete with, which is what ahci_atapi_test_ready() does inline for a sense key today. INITIALIZE DEVICE PARAMETERS is the first user of both, so describe it in the command properties table as well. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/libqos/ahci.c | 14 ++++++++++++++ tests/qtest/libqos/ahci.h | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/tests/qtest/libqos/ahci.c b/tests/qtest/libqos/ahci.c index e3019a1eca..50b63239c2 100644 --- a/tests/qtest/libqos/ahci.c +++ b/tests/qtest/libqos/ahci.c @@ -74,6 +74,7 @@ AHCICommandProp ahci_command_properties[] = { { .cmd = CMD_READ_MAX, .lba28 = true }, { .cmd = CMD_READ_MAX_EXT, .lba48 = true }, { .cmd = CMD_FLUSH_CACHE, .data = false }, + { .cmd = CMD_INIT_DP, .data = false }, { .cmd = CMD_PACKET, .data = true, .size = 16, .atapi = true, .pio = true }, { .cmd = CMD_PACKET_ID, .data = true, .pio = true, @@ -1180,6 +1181,19 @@ void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size) ahci_command_set_sizes(cmd, cmd->xbytes, prd_size); } +/* For a no-data command, whose count carries an argument of its own */ +void ahci_command_set_count(AHCICommand *cmd, uint16_t count) +{ + g_assert(!cmd->props->data); + cmd->fis.count = count; +} + +void ahci_command_expect_error(AHCICommand *cmd, uint8_t err) +{ + cmd->interrupts |= AHCI_PX_IS_TFES; + cmd->errors |= err; +} + void ahci_command_adjust(AHCICommand *cmd, uint64_t offset, uint64_t buffer, uint64_t xbytes, unsigned prd_size) { diff --git a/tests/qtest/libqos/ahci.h b/tests/qtest/libqos/ahci.h index 2a48a7523d..6d861c79ee 100644 --- a/tests/qtest/libqos/ahci.h +++ b/tests/qtest/libqos/ahci.h @@ -278,6 +278,7 @@ enum { CMD_READ_MAX = 0xF8, CMD_READ_MAX_EXT = 0x27, CMD_FLUSH_CACHE = 0xE7, + CMD_INIT_DP = 0x91, /* INITIALIZE DEVICE PARAMETERS */ CMD_IDENTIFY = 0xEC, CMD_PACKET = 0xA0, CMD_PACKET_ID = 0xA1, @@ -324,6 +325,9 @@ enum { #define ATA_DEVICE_DRIVE 0x10 #define ATA_DEVICE_HEAD 0x0F +/* ATA error register bits */ +#define ATA_ERR_ABRT 0x04 + /*** Structures ***/ typedef struct AHCIPortQState { @@ -638,6 +642,8 @@ void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size); void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, unsigned prd_size); +void ahci_command_set_count(AHCICommand *cmd, uint16_t count); +void ahci_command_expect_error(AHCICommand *cmd, uint8_t err); void ahci_command_set_acmd(AHCICommand *cmd, void *acmd); void ahci_command_enable_atapi_dma(AHCICommand *cmd); void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer, From d6960ecdded35b2d4ef8b23763d19038b2d190b6 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 15:35:23 +0200 Subject: [PATCH 603/627] tests/qtest/ahci: cover the sector count of INITIALIZE DEVICE PARAMETERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sector count register of a legacy port is eight bits wide, so ide-test can only reach the lower end of the range the command has to refuse. A register FIS carries a 16 bit count, which leaves AHCI as the only way to ask for a translation of 256 sectors per logical track or more. Ask for 0, 256 and 65535 sectors and expect each to be aborted, then ask for 32 and expect it to be accepted, so that the check cannot pass by refusing everything. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ahci-test.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 71d23fe56a..30d7005626 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -905,6 +905,30 @@ static void ahci_test_flush(AHCIQState *ahci) ahci_test_nondata(ahci, CMD_FLUSH_CACHE); } +static void ahci_test_specify(AHCIQState *ahci, uint16_t sectors, + bool supported) +{ + AHCICommand *cmd; + uint8_t port; + + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + + cmd = ahci_command_create(CMD_INIT_DP); + ahci_command_set_count(cmd, sectors); + if (!supported) { + ahci_command_expect_error(cmd, ATA_ERR_ABRT); + } + ahci_command_commit(ahci, cmd, port); + ahci_command_issue(ahci, cmd); + if (!supported) { + ASSERT_BIT_SET(ahci_px_rreg(ahci, port, AHCI_PX_TFD), + AHCI_PX_TFD_STS_ERR); + } + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + static void ahci_test_max(AHCIQState *ahci) { RegD2HFIS *d2h = g_malloc0(0x20); @@ -1012,6 +1036,21 @@ static void test_identify(void) ahci_shutdown(ahci); } +static void test_specify(void) +{ + AHCIQState *ahci; + + ahci = ahci_boot_and_enable(NULL); + + /* A register FIS carries 16 bits of count, the legacy ports only eight */ + ahci_test_specify(ahci, 0, false); + ahci_test_specify(ahci, 256, false); + ahci_test_specify(ahci, 0xffff, false); + ahci_test_specify(ahci, 32, true); + + ahci_shutdown(ahci); +} + /** * Fragmented DMA test: Perform a standard 4K DMA read/write * test, but make sure the physical regions are fragmented to @@ -2220,6 +2259,7 @@ int main(int argc, char **argv) qtest_add_func("/ahci/migrate/dma/halted", test_migrate_halted_dma); qtest_add_func("/ahci/max", test_max); + qtest_add_func("/ahci/specify", test_specify); qtest_add_func("/ahci/reset/simple", test_reset); qtest_add_func("/ahci/reset/pending_callback", test_reset_pending_callback); From 0df27c66dc7271ee2e63636b5183c0b3acdf7eed Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 17:41:34 +0200 Subject: [PATCH 604/627] hw/ide: report the default CHS translation in IDENTIFY DEVICE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IDENTIFY DEVICE words 1, 3 and 6 describe the default CHS translation, and ATA-5 8.16.8 requires INITIALIZE DEVICE PARAMETERS to leave them alone; the translation in effect is described by words 54 to 56 instead. Words 3 and 6 were filled from s->heads and s->sectors, which the command replaces, so a guest that selected a translation of its own was told that its choice was what the drive came with, and could no longer find out the default. Word 1 is already right, as no command changes s->cylinders. Report s->drive_heads and s->drive_sectors, which ide_init_drive() keeps for exactly this, along with the retired word 4 derived from them. The CompactFlash data labels those words as the default geometry too, and INITIALIZE DEVICE PARAMETERS is accepted for CFA drives, so fix both. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Cc: qemu-stable@nongnu.org Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev Reviewed-by: Philippe Mathieu-Daudé --- hw/ide/core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 747fa71677..befbab9486 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -138,11 +138,12 @@ static void ide_identify(IDEState *s) memset(p, 0, sizeof(s->identify_data)); put_le16(p + 0, 0x0040); + /* Words 1, 3 and 6 describe the default translation (ATA-5 8.16.8) */ put_le16(p + 1, s->cylinders); - put_le16(p + 3, s->heads); - put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ + put_le16(p + 3, s->drive_heads); + put_le16(p + 4, 512 * s->drive_sectors); /* XXX: retired, remove ? */ put_le16(p + 5, 512); /* XXX: retired, remove ? */ - put_le16(p + 6, s->sectors); + put_le16(p + 6, s->drive_sectors); padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ put_le16(p + 20, 3); /* XXX: retired, remove ? */ put_le16(p + 21, 512); /* cache size in sectors */ @@ -332,8 +333,8 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 0, 0x848a); /* CF Storage Card signature */ put_le16(p + 1, s->cylinders); /* Default cylinders */ - put_le16(p + 3, s->heads); /* Default heads */ - put_le16(p + 6, s->sectors); /* Default sectors per track */ + put_le16(p + 3, s->drive_heads); /* Default heads */ + put_le16(p + 6, s->drive_sectors); /* Default sectors per track */ /* *(p + 7) := nb_sectors >> 16 -- see ide_cfata_identify_size */ /* *(p + 8) := nb_sectors -- see ide_cfata_identify_size */ padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ From adf1152b3454673a19f84e830dce80203851864c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 20 Aug 2026 09:37:11 +0200 Subject: [PATCH 605/627] hw/ide: name the retired IDENTIFY DEVICE words the device fills in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Words 4, 5 and 20 have carried an "XXX: retired, remove ?" since the device was written, and word 21 is labelled a cache size when it is a buffer size. ATA-4 8.12.13 retired words 4 and 5, 8.12.17 retired words 20 and 21, and ATA-5 keeps all four that way. Retired is not a reason to drop them. ATA-5 3.2.3.6 says a retired word that is still used shall have "the meaning or functionality as described in previous standards", and that is what these carry: ATA-1 9.9.3, 9.9.4 and 9.9.7 define the unformatted bytes per track and per sector and the buffer type, and the ATA-1 IDENTIFY table gives word 21 as the buffer size in 512 byte increments. Software old enough to read them gets what it expects, so answer the question rather than leave it open. Word 22 is obsolete rather than retired (ATA-4 8.12.18) and already carries its ATA-1 9.9.8 name, so leave it alone. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index befbab9486..292908fb1c 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -141,12 +141,12 @@ static void ide_identify(IDEState *s) /* Words 1, 3 and 6 describe the default translation (ATA-5 8.16.8) */ put_le16(p + 1, s->cylinders); put_le16(p + 3, s->drive_heads); - put_le16(p + 4, 512 * s->drive_sectors); /* XXX: retired, remove ? */ - put_le16(p + 5, 512); /* XXX: retired, remove ? */ + put_le16(p + 4, 512 * s->drive_sectors); /* ATA-1 unformatted bytes/trk */ + put_le16(p + 5, 512); /* ATA-1 unformatted bytes per sector */ put_le16(p + 6, s->drive_sectors); padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */ - put_le16(p + 20, 3); /* XXX: retired, remove ? */ - put_le16(p + 21, 512); /* cache size in sectors */ + put_le16(p + 20, 3); /* ATA-1 buffer type: dual ported, read caching */ + put_le16(p + 21, 512); /* ATA-1 buffer size in 512 byte increments */ put_le16(p + 22, 4); /* ecc bytes */ padstr((char *)(p + 23), s->version, 8); /* firmware version */ padstr((char *)(p + 27), s->drive_model_str, 40); /* model */ From 747679ca5981f1d591dc53e076df8a39d3428061 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 17:43:26 +0200 Subject: [PATCH 606/627] hw/ide: factor out the IDENTIFY DEVICE current geometry words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Words 54 to 58 of IDENTIFY DEVICE describe the CHS translation in effect and the capacity it addresses. Both ide_identify() and ide_cfata_identify() fill them the same way while building their cached data. Move them into ide_identify_chs(), so that the next change can refresh them in place once the translation changes, the way ide_identify_size() does for the capacity words. No functional change. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev Reviewed-by: Philippe Mathieu-Daudé --- hw/ide/core.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 292908fb1c..e5fd570575 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -110,6 +110,18 @@ static void put_le16(uint16_t *p, unsigned int v) *p = cpu_to_le16(v); } +static void ide_identify_chs(IDEState *s) +{ + uint16_t *p = (uint16_t *)s->identify_data; + unsigned int cur_sec = s->cylinders * s->heads * s->sectors; + + put_le16(p + 54, s->cylinders); + put_le16(p + 55, s->heads); + put_le16(p + 56, s->sectors); + put_le16(p + 57, cur_sec); + put_le16(p + 58, cur_sec >> 16); +} + static void ide_identify_size(IDEState *s) { uint16_t *p = (uint16_t *)s->identify_data; @@ -128,7 +140,6 @@ static void ide_identify_size(IDEState *s) static void ide_identify(IDEState *s) { uint16_t *p; - unsigned int oldsize; IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master; p = (uint16_t *)s->identify_data; @@ -158,12 +169,7 @@ static void ide_identify(IDEState *s) put_le16(p + 51, 0x200); /* PIO transfer cycle */ put_le16(p + 52, 0x200); /* DMA transfer cycle */ put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ - put_le16(p + 54, s->cylinders); - put_le16(p + 55, s->heads); - put_le16(p + 56, s->sectors); - oldsize = s->cylinders * s->heads * s->sectors; - put_le16(p + 57, oldsize); - put_le16(p + 58, oldsize >> 16); + ide_identify_chs(s); if (s->mult_sectors) put_le16(p + 59, 0x100 | s->mult_sectors); /* *(p + 60) := nb_sectors -- see ide_identify_size */ @@ -321,7 +327,6 @@ static void ide_cfata_identify_size(IDEState *s) static void ide_cfata_identify(IDEState *s) { uint16_t *p; - uint32_t cur_sec; p = (uint16_t *)s->identify_data; if (s->identify_set) { @@ -329,8 +334,6 @@ static void ide_cfata_identify(IDEState *s) } memset(p, 0, sizeof(s->identify_data)); - cur_sec = s->cylinders * s->heads * s->sectors; - put_le16(p + 0, 0x848a); /* CF Storage Card signature */ put_le16(p + 1, s->cylinders); /* Default cylinders */ put_le16(p + 3, s->drive_heads); /* Default heads */ @@ -350,11 +353,7 @@ static void ide_cfata_identify(IDEState *s) put_le16(p + 51, 0x0002); /* PIO cycle timing mode */ put_le16(p + 52, 0x0001); /* DMA cycle timing mode */ put_le16(p + 53, 0x0003); /* Translation params valid */ - put_le16(p + 54, s->cylinders); /* Current cylinders */ - put_le16(p + 55, s->heads); /* Current heads */ - put_le16(p + 56, s->sectors); /* Current sectors */ - put_le16(p + 57, cur_sec); /* Current capacity */ - put_le16(p + 58, cur_sec >> 16); /* Current capacity */ + ide_identify_chs(s); /* Current C/H/S and capacity */ if (s->mult_sectors) /* Multiple sector setting */ put_le16(p + 59, 0x100 | s->mult_sectors); /* *(p + 60) := nb_sectors -- see ide_cfata_identify_size */ From b5542796b3cbe052daa3660d00ec1d4a1033e7ff Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 17:43:26 +0200 Subject: [PATCH 607/627] hw/ide: keep the IDENTIFY DEVICE current geometry in sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bit 0 of IDENTIFY DEVICE word 53 says that words 54 to 58 describe the CHS translation in effect, and ATA-5 8.16.8 has INITIALIZE DEVICE PARAMETERS set words 55 and 56 to the heads and sectors per track it was given. The data is built once and then cached, so those words kept describing whatever was in effect when a guest first asked for IDENTIFY DEVICE: the device reported one geometry while addressing the medium with another, and nothing reported an error. The revert SET FEATURES 0xCC asks for on the next reset left the same disagreement. Do not drop the cached data on a change, as parts of it are guest state rather than a description of the drive: SET FEATURES records the write cache setting in word 85, which ide_drive_post_load() reads back after migration. Refresh the affected words in place instead, the way ide_identify_size() does for the capacity words. An ATAPI device has no translation but does take SET FEATURES 0xCC, so leave its IDENTIFY PACKET DEVICE data alone, where those words differ. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index e5fd570575..048655b2d0 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1360,6 +1360,10 @@ static void ide_reset(IDEState *s) s->reset_reverts = false; s->heads = s->drive_heads; s->sectors = s->drive_sectors; + /* An ATAPI device takes SET FEATURES 0xCC but has no translation */ + if (s->identify_set && s->drive_kind != IDE_CD) { + ide_identify_chs(s); + } } if (s->drive_kind == IDE_CFATA) s->mult_sectors = 0; @@ -1668,6 +1672,9 @@ static bool cmd_specify(IDEState *s, uint8_t cmd) s->heads = (s->select & (ATA_DEV_HS)) + 1; s->sectors = s->nsector; + if (s->identify_set) { + ide_identify_chs(s); + } ide_bus_set_irq(s->bus); return true; From 33db64cf28829103e6b60905666082a01d011fc8 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 4 Aug 2026 18:34:44 +0200 Subject: [PATCH 608/627] hw/ide: restore the power-on device state before loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loading a snapshot reuses the IDEState of the machine it is loaded into: load_snapshot() resets the machine and then feeds the stream into the existing devices. The reset does not help, as ide_reset() restores the logical CHS translation only when the guest asked for power-on defaults to be reverted with SET FEATURES 0xCC. A guest that replaced the translation with INITIALIZE DEVICE PARAMETERS therefore keeps it across the load of a snapshot taken before it did, while the restored guest expects the geometry of that moment. Every CHS access then lands on a sector other than the one asked for, with no error reported. s->reset_reverts survives a load the same way. Add a pre_load restoring the defaults, which docs/devel/migration/main.rst recommends for state a stream need not carry, and which the following subsections rely on. The RESET_TYPE_SNAPSHOT_LOAD marking that reset would be another way to recognise the case, but no IDE controller can see it while they all use device_class_set_legacy_reset(). Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index 048655b2d0..28219f5ef8 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2863,6 +2863,18 @@ static int transfer_end_table_idx(EndTransferFunc *fn) return -1; } +static int ide_drive_pre_load(void *opaque) +{ + IDEState *s = opaque; + + /* The subsections below are sent only where the guest replaced these */ + s->heads = s->drive_heads; + s->sectors = s->drive_sectors; + s->reset_reverts = false; + + return 0; +} + static int ide_drive_post_load(void *opaque, int version_id) { IDEState *s = opaque; @@ -2986,6 +2998,7 @@ const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", .version_id = 3, .minimum_version_id = 0, + .pre_load = ide_drive_pre_load, .post_load = ide_drive_post_load, .fields = (const VMStateField[]) { VMSTATE_INT32(mult_sectors, IDEState), From ba4a996631cd3882246e0892e805d398a63e9b09 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 4 Aug 2026 18:34:44 +0200 Subject: [PATCH 609/627] hw/ide: migrate the logical CHS translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INITIALIZE DEVICE PARAMETERS lets a guest replace the logical CHS translation used to turn the CHS registers into an LBA, but s->heads and s->sectors were in no VMStateDescription. The destination rebuilt them from the drive configuration, so a guest that had selected one of its own kept addressing the disk in it while the device translated with the default, landing on sectors nobody asked for. Add a subsection for it, sent only when the guest replaced the default, so that migration to an older QEMU keeps working for every other guest. s->cylinders is left out, as no command changes it. Validate what is loaded in the existing post_load: ide_get_sector() multiplies by these fields and ide_set_sector() divides by them. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index 28219f5ef8..b074325afa 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2879,6 +2879,13 @@ static int ide_drive_post_load(void *opaque, int version_id) { IDEState *s = opaque; + /* Only a disk has a translation; an empty slot and ATAPI keep these zero */ + if (s->blk && s->drive_kind != IDE_CD && + (s->heads < 1 || s->heads > 16 || + s->sectors < 1 || s->sectors > 255)) { + return -EINVAL; + } + if (s->blk && s->identify_set) { blk_set_enable_write_cache(s->blk, !!(s->identify_data[85] & (1 << 5))); } @@ -2962,6 +2969,25 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { } }; +static bool ide_chs_translation_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->heads != s->drive_heads || s->sectors != s->drive_sectors; +} + +static const VMStateDescription vmstate_ide_drive_chs_translation = { + .name = "ide_drive/chs_translation", + .version_id = 1, + .minimum_version_id = 1, + .needed = ide_chs_translation_needed, + .fields = (const VMStateField[]) { + VMSTATE_INT32(heads, IDEState), + VMSTATE_INT32(sectors, IDEState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ide_tray_state = { .name = "ide_drive/tray_state", .version_id = 1, @@ -3025,6 +3051,7 @@ const VMStateDescription vmstate_ide_drive = { }, .subsections = (const VMStateDescription * const []) { &vmstate_ide_drive_pio_state, + &vmstate_ide_drive_chs_translation, &vmstate_ide_tray_state, &vmstate_ide_atapi_gesn_state, NULL From 67a6d29c28cc1a2628b0e1bdeac93621a9d4d9cb Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 4 Aug 2026 18:34:44 +0200 Subject: [PATCH 610/627] hw/ide: migrate the power-on defaults revert flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SET FEATURES 0xCC asks for the next reset to revert to the power-on defaults, and 0x66 cancels that; ide_reset() restores the default CHS translation only when the flag is set. It was in no VMStateDescription, so it always arrived cleared. That was invisible while the destination had the default translation anyway. Now that the translation is migrated, the flag decides how long it stays in effect: without it, a reset after the migration reverts the geometry on the source and keeps it on the destination. Send it only alongside a translation the guest replaced. On the default geometry it reverts to what is already in effect, so such a guest need not lose its migration to an older QEMU over a subsection that changes nothing. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index b074325afa..5a5f072630 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2988,6 +2988,25 @@ static const VMStateDescription vmstate_ide_drive_chs_translation = { } }; +static bool ide_reset_reverts_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->reset_reverts && ide_chs_translation_needed(opaque); +} + +/* The flag decides nothing on the default geometry, so it travels with one */ +static const VMStateDescription vmstate_ide_drive_reset_reverts = { + .name = "ide_drive/reset_reverts", + .version_id = 1, + .minimum_version_id = 1, + .needed = ide_reset_reverts_needed, + .fields = (const VMStateField[]) { + VMSTATE_BOOL(reset_reverts, IDEState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ide_tray_state = { .name = "ide_drive/tray_state", .version_id = 1, @@ -3052,6 +3071,7 @@ const VMStateDescription vmstate_ide_drive = { .subsections = (const VMStateDescription * const []) { &vmstate_ide_drive_pio_state, &vmstate_ide_drive_chs_translation, + &vmstate_ide_drive_reset_reverts, &vmstate_ide_tray_state, &vmstate_ide_atapi_gesn_state, NULL From ef64d2758e439871500c726c0d536b05d19c2532 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 4 Aug 2026 18:34:44 +0200 Subject: [PATCH 611/627] tests/qtest/ide-test: cover the CHS translation across migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both defects here are silent: the guest addresses the disk in the translation it selected while the device translates with another, so reads and writes land on a sector nobody asked for. Put a marker in each of the two candidate sectors and name the one the translation picked. CHS 0/1/1 is LBA 32 under 8 heads and 32 sectors per track and LBA 63 under the 16/63 the test drive is configured with; both markers are written by LBA, which no translation can influence. A translation the guest selected has to survive migration, and one it selected after a snapshot was taken must not outlive loading that snapshot back. The second needs a qcow2 image, so it is skipped without qemu-img. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 231 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 99aa5e039c..19e9734d3c 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -96,6 +96,7 @@ enum { enum { CMD_DSM = 0x06, CMD_READ = 0x20, /* READ SECTOR(S) */ + CMD_WRITE = 0x30, /* WRITE SECTOR(S) */ CMD_DIAGNOSE = 0x90, CMD_INIT_DP = 0x91, /* INITIALIZE DEVICE PARAMETERS */ CMD_READ_DMA = 0xc8, @@ -1255,6 +1256,233 @@ static void test_specify_zero_sectors(void) free_pci_device(dev); } +/* Addressed by LBA, so no translation can influence where it lands */ +static void ide_write_marker(QTestState *qts, QPCIDevice *dev, QPCIBar ide_bar, + uint32_t lba, const char *marker) +{ + uint16_t buf[256]; + uint8_t data; + int i; + + memset(buf, 0, sizeof(buf)); + memcpy(buf, marker, strlen(marker)); + + qpci_io_writeb(dev, ide_bar, reg_nsectors, 1); + qpci_io_writeb(dev, ide_bar, reg_lba_low, lba & 0xff); + qpci_io_writeb(dev, ide_bar, reg_lba_middle, (lba >> 8) & 0xff); + qpci_io_writeb(dev, ide_bar, reg_lba_high, (lba >> 16) & 0xff); + qpci_io_writeb(dev, ide_bar, reg_device, LBA | ((lba >> 24) & 0xf)); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_WRITE); + + data = ide_wait_clear(qts, BSY); + assert_bit_set(data, DRQ); + for (i = 0; i < 256; i++) { + qpci_io_writew(dev, ide_bar, reg_data, buf[i]); + } + data = ide_wait_clear(qts, BSY); + assert_bit_clear(data, ERR | DF | DRQ); + + qpci_io_writeb(dev, ide_bar, reg_command, CMD_FLUSH_CACHE); + data = ide_wait_clear(qts, BSY); + assert_bit_clear(data, ERR | DF); +} + +/* The marker read back names the sector the translation selected */ +static void ide_read_chs_marker(QTestState *qts, QPCIDevice *dev, + QPCIBar ide_bar, uint8_t cyl_lo, uint8_t head, + uint8_t sector, char out[9]) +{ + uint16_t buf[256]; + uint8_t data; + int i; + + qpci_io_writeb(dev, ide_bar, reg_nsectors, 1); + qpci_io_writeb(dev, ide_bar, reg_lba_low, sector); + qpci_io_writeb(dev, ide_bar, reg_lba_middle, cyl_lo); + qpci_io_writeb(dev, ide_bar, reg_lba_high, 0); + qpci_io_writeb(dev, ide_bar, reg_device, head & 0xf); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_READ); + + data = ide_wait_clear(qts, BSY); + assert_bit_set(data, DRQ); + assert_bit_clear(data, ERR | DF); + for (i = 0; i < 256; i++) { + buf[i] = qpci_io_readw(dev, ide_bar, reg_data); + } + data = ide_wait_clear(qts, BSY); + assert_bit_clear(data, ERR | DF | DRQ); + + memcpy(out, buf, 8); + out[8] = '\0'; +} + +static void ide_set_translation(QPCIDevice *dev, QPCIBar ide_bar, + uint8_t heads, uint8_t sectors) +{ + qpci_io_writeb(dev, ide_bar, reg_nsectors, sectors); + qpci_io_writeb(dev, ide_bar, reg_device, heads - 1); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_INIT_DP); + assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), ERR); +} + +/* CHS 0/1/1 is LBA 32 under 8/32, and LBA 63 under the drive's own 16/63 */ +#define CHS_MARKER_CUSTOM "CUSTOM__" +#define CHS_MARKER_DEFAULT "DEFAULT_" + +static void ide_prepare_markers(QTestState *qts, QPCIDevice *dev, + QPCIBar ide_bar) +{ + ide_write_marker(qts, dev, ide_bar, 32, CHS_MARKER_CUSTOM); + ide_write_marker(qts, dev, ide_bar, 63, CHS_MARKER_DEFAULT); +} + +static void ide_hmp_quiet(QTestState *qts, const char *command) +{ + g_autofree char *out = qtest_hmp(qts, "%s", command); + + g_assert_cmpstr(out, ==, ""); +} + +static char *ide_migration_status(QTestState *qts) +{ + QDict *ret; + char *status; + + ret = qtest_qmp_assert_success_ref(qts, "{ 'execute': 'query-migrate' }"); + g_assert(qdict_haskey(ret, "status")); + status = g_strdup(qdict_get_str(ret, "status")); + qobject_unref(ret); + + return status; +} + +/* Waiting for the other side's event would hang if it refuses the stream */ +static void ide_migration_wait(QTestState *qts, const char *expected) +{ + while (true) { + g_autofree char *status = ide_migration_status(qts); + + if (g_str_equal(status, expected)) { + return; + } + if (!g_str_equal(status, "setup") && !g_str_equal(status, "active") && + !g_str_equal(status, "device")) { + fprintf(stderr, "Migration status is %s, expected %s\n", + status, expected); + g_assert_not_reached(); + } + g_usleep(5000); + } +} + +static void ide_migrate(QTestState *src, QTestState *dst, const char *uri) +{ + qtest_qmp_assert_success(src, "{ 'execute': 'migrate'," + " 'arguments': { 'uri': %s } }", uri); + qtest_qmp_eventwait(src, "STOP"); + ide_migration_wait(src, "completed"); + qtest_qmp_eventwait(dst, "RESUME"); +} + +/* A translation the guest selected has to survive migration */ +static void test_migrate_chs_translation(void) +{ + QTestState *src, *dst; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + g_autofree char *mig_path = NULL; + g_autofree char *uri = NULL; + g_autofree char *dst_args = NULL; + char marker[9]; + int fd; + + fd = g_file_open_tmp("qtest-ide-migration.XXXXXX", &mig_path, NULL); + g_assert(fd >= 0); + close(fd); + uri = g_strdup_printf("unix:%s", mig_path); + + src = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s,locking=off " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(src, &bmdma_bar, &ide_bar); + + ide_prepare_markers(src, dev, ide_bar); + ide_set_translation(dev, ide_bar, 8, 32); + ide_read_chs_marker(src, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_CUSTOM); + + dst_args = g_strdup_printf( + "-machine pc " + "-blockdev driver=file,node-name=hda,filename=%s,locking=off " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 -incoming %s", + tmp_path[0], uri); + dst = qtest_init(dst_args); + + ide_migrate(src, dst, uri); + + /* Talk to the destination instead of the source */ + qpci_free_pc(pcibus); + pcibus = NULL; + free_pci_device(dev); + dev = get_pci_device(dst, &bmdma_bar, &ide_bar); + + ide_read_chs_marker(dst, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_CUSTOM); + + free_pci_device(dev); + qtest_quit(dst); + ide_test_quit(src); + unlink(mig_path); +} + +/* A translation selected after the snapshot must not outlive loading it */ +static void test_migrate_chs_snapshot(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + g_autofree char *img = NULL; + char marker[9]; + int fd; + + if (!have_qemu_img()) { + g_test_skip("QTEST_QEMU_IMG not set, snapshots need a qcow2 image"); + return; + } + + fd = g_file_open_tmp("qtest-ide-snapshot.XXXXXX", &img, NULL); + g_assert(fd >= 0); + close(fd); + g_assert(mkimg(img, "qcow2", TEST_IMAGE_SIZE / (1024 * 1024))); + + qts = ide_test_start( + "-blockdev driver=qcow2,node-name=hda,file.driver=file," + "file.filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", img); + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + ide_prepare_markers(qts, dev, ide_bar); + + /* Snapshot taken while the default translation is in effect */ + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_DEFAULT); + ide_hmp_quiet(qts, "savevm s0"); + + ide_set_translation(dev, ide_bar, 8, 32); + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_CUSTOM); + + ide_hmp_quiet(qts, "loadvm s0"); + + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_DEFAULT); + + free_pci_device(dev); + ide_test_quit(qts); + unlink(img); +} + static void test_cdrom_pio(void) { cdrom_read_impl(1, CDROM_PIO); @@ -1327,6 +1555,9 @@ int main(int argc, char **argv) qtest_add_func("/ide/read_native", test_specify); qtest_add_func("/ide/specify/zero_sectors", test_specify_zero_sectors); + qtest_add_func("/ide/migration/chs_translation", + test_migrate_chs_translation); + qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot); qtest_add_func("/ide/identify", test_identify); From 5be90dfbc000a279b7cec668f9dbb131ce2b0c40 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 18:17:34 +0200 Subject: [PATCH 612/627] tests/qtest/ide-test: cover a rejected CHS translation in the stream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ide_drive_post_load() refuses a logical CHS translation that no command could have selected, as the fields are a divisor in ide_set_sector() and a factor in ide_get_sector(). Nothing exercised that, a fixed QEMU having no way to produce such a stream. Migrate a guest that selected a translation to a file, replace the number of sectors per logical track in the subsection with a zero, and let a destination read the result back. The load has to fail rather than take the value, so the destination is asked not to exit on a failed incoming migration and its migration status is what the test looks at. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 19e9734d3c..4fa58ac525 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1483,6 +1483,86 @@ static void test_migrate_chs_snapshot(void) unlink(img); } +/* A migration stream holds NUL bytes, so this cannot be a string search */ +static char *ide_stream_find(char *stream, gsize len, const char *name) +{ + gsize name_len = strlen(name); + gsize i; + + if (len < name_len) { + return NULL; + } + for (i = 0; i <= len - name_len; i++) { + if (memcmp(stream + i, name, name_len) == 0) { + return stream + i; + } + } + + return NULL; +} + +/* A translation no command could have selected has to be refused on load */ +static void test_migrate_chs_rejected(void) +{ + const char *name = "ide_drive/chs_translation"; + QTestState *src, *dst; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + g_autofree char *path = NULL; + g_autofree char *uri = NULL; + g_autofree char *dst_args = NULL; + g_autofree char *stream = NULL; + char *subsection; + gsize len; + int fd; + + fd = g_file_open_tmp("qtest-ide-stream.XXXXXX", &path, NULL); + g_assert(fd >= 0); + close(fd); + uri = g_strdup_printf("file:%s", path); + + src = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(src, &bmdma_bar, &ide_bar); + + ide_set_translation(dev, ide_bar, 8, 32); + qtest_qmp_assert_success(src, "{ 'execute': 'migrate'," + " 'arguments': { 'uri': %s } }", uri); + qtest_qmp_eventwait(src, "STOP"); + ide_migration_wait(src, "completed"); + free_pci_device(dev); + ide_test_quit(src); + + /* + * Behind the name come version, heads and sectors, each big endian 32 bit. + * The name recurs in the description at the end of the stream, so the + * first match is the one carrying data. + */ + g_assert(g_file_get_contents(path, &stream, &len, NULL)); + subsection = ide_stream_find(stream, len, name); + g_assert(subsection); + g_assert_cmpint(subsection - stream + strlen(name) + 12, <=, len); + memset(subsection + strlen(name) + 8, 0, 4); + g_assert(g_file_set_contents(path, stream, len, NULL)); + + dst_args = g_strdup_printf( + "-machine pc " + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 -incoming defer", + tmp_path[0]); + dst = qtest_init(dst_args); + + qtest_qmp_assert_success(dst, "{ 'execute': 'migrate-incoming'," + " 'arguments': { 'uri': %s," + " 'exit-on-error': false } }", uri); + ide_migration_wait(dst, "failed"); + + qtest_quit(dst); + unlink(path); +} + static void test_cdrom_pio(void) { cdrom_read_impl(1, CDROM_PIO); @@ -1558,6 +1638,7 @@ int main(int argc, char **argv) qtest_add_func("/ide/migration/chs_translation", test_migrate_chs_translation); qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot); + qtest_add_func("/ide/migration/chs_rejected", test_migrate_chs_rejected); qtest_add_func("/ide/identify", test_identify); From 07209133238f0d660ff33e33c32ce7dd95127adb Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 18:19:34 +0200 Subject: [PATCH 613/627] tests/qtest/ide-test: cover the IDENTIFY DEVICE geometry words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INITIALIZE DEVICE PARAMETERS has to leave the geometry the drive came with in words 3 and 6 and describe the translation it selected in words 54 to 58, and the data is cached, so which of the two a guest is told depends on when it first asked. Cover both orders, as each alone leaves half of it untested: one test has the data built while the default is in effect and then replaces the translation, which the cached copy has to follow, the other replaces it before the first IDENTIFY DEVICE, where the words describing the default have to keep doing so. Factor the reading of the data out of test_specify_zero_sectors() for the three of them to share. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 89 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 5 deletions(-) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index 4fa58ac525..e7a56e0710 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1196,6 +1196,18 @@ static void cdrom_read_impl(int nblocks, unsigned flags) free_pci_device(dev); } +static void ide_identify_words(QPCIDevice *dev, QPCIBar ide_bar, + uint16_t buf[256]) +{ + int i; + + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY); + for (i = 0; i < 256; i++) { + buf[i] = qpci_io_readw(dev, ide_bar, reg_data); + } +} + /* Zero sectors per track has to abort (ATA-5 8.16.6), not divide by zero */ static void test_specify_zero_sectors(void) { @@ -1221,11 +1233,7 @@ static void test_specify_zero_sectors(void) assert_bit_set(qpci_io_readb(dev, ide_bar, reg_error), ABRT); /* The refused request has to leave the default translation in effect */ - qpci_io_writeb(dev, ide_bar, reg_device, 0); - qpci_io_writeb(dev, ide_bar, reg_command, CMD_IDENTIFY); - for (i = 0; i < 256; i++) { - buf[i] = qpci_io_readw(dev, ide_bar, reg_data); - } + ide_identify_words(dev, ide_bar, buf); g_assert_cmpint(buf[55], ==, 16); g_assert_cmpint(buf[56], ==, 63); @@ -1563,6 +1571,74 @@ static void test_migrate_chs_rejected(void) unlink(path); } +/* Words 54 to 58 follow the translation even when the data was cached first */ +static void test_specify_identify(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint16_t buf[256]; + unsigned int cyls; + + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + /* Have the data built while the default translation is still in effect */ + ide_identify_words(dev, ide_bar, buf); + cyls = buf[1]; + g_assert_cmpint(buf[3], ==, 16); + g_assert_cmpint(buf[6], ==, 63); + g_assert_cmpint(buf[53] & 1, ==, 1); + g_assert_cmpint(buf[55], ==, 16); + g_assert_cmpint(buf[56], ==, 63); + g_assert_cmpint(buf[57] | (buf[58] << 16), ==, cyls * 16 * 63); + + ide_set_translation(dev, ide_bar, 8, 32); + + ide_identify_words(dev, ide_bar, buf); + g_assert_cmpint(buf[1], ==, cyls); + g_assert_cmpint(buf[3], ==, 16); + g_assert_cmpint(buf[4], ==, 512 * 63); + g_assert_cmpint(buf[6], ==, 63); + g_assert_cmpint(buf[55], ==, 8); + g_assert_cmpint(buf[56], ==, 32); + g_assert_cmpint(buf[57] | (buf[58] << 16), ==, cyls * 8 * 32); + + free_pci_device(dev); + ide_test_quit(qts); +} + +/* Words 3 and 6 keep the drive's own geometry even if built after a change */ +static void test_specify_identify_default(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint16_t buf[256]; + + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + /* No IDENTIFY DEVICE before this one, so nothing was cached yet */ + ide_set_translation(dev, ide_bar, 8, 32); + ide_identify_words(dev, ide_bar, buf); + g_assert_cmpint(buf[3], ==, 16); + g_assert_cmpint(buf[4], ==, 512 * 63); + g_assert_cmpint(buf[6], ==, 63); + g_assert_cmpint(buf[55], ==, 8); + g_assert_cmpint(buf[56], ==, 32); + g_assert_cmpint(buf[57] | (buf[58] << 16), ==, buf[1] * 8 * 32); + + free_pci_device(dev); + ide_test_quit(qts); +} + static void test_cdrom_pio(void) { cdrom_read_impl(1, CDROM_PIO); @@ -1635,6 +1711,9 @@ int main(int argc, char **argv) qtest_add_func("/ide/read_native", test_specify); qtest_add_func("/ide/specify/zero_sectors", test_specify_zero_sectors); + qtest_add_func("/ide/specify/identify", test_specify_identify); + qtest_add_func("/ide/specify/identify_default", + test_specify_identify_default); qtest_add_func("/ide/migration/chs_translation", test_migrate_chs_translation); qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot); From cafb3d96254fee4705d58cea2a8221498a361475 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 17:46:55 +0200 Subject: [PATCH 614/627] hw/ide: revert the CHS translation on a hardware reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A power on or hardware reset returns the device parameters to their power-on defaults (ATA-5 9.1). A software reset keeps them unless the guest asked with SET FEATURES 0xCC for the next reset to revert (ATA-5 9.2 and 8.16.6). ide_reset() applied the second rule to every reset, so a translation a guest selected outlived the reset of the machine it selected it on, and the guest that came up next addressed the disk through a geometry it never asked for. Neither ide_reset() nor, for AHCI, ide_bus_reset() could tell the two apart: a guest clearing SRST in the second host to device FIS of the software reset protocol lands in the same ahci_reset_port() as a COMRESET or a reset of the host adapter. Pass the kind down from the callers, which do know. ide_drive_pre_load() stays necessary: it restores the same fields, but a vmstate cannot depend on its device having been reset first. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Signed-off-by: Denis V. Lunev Reviewed-by: Philippe Mathieu-Daudé --- hw/ide/ahci.c | 12 ++++++------ hw/ide/cmd646.c | 2 +- hw/ide/core.c | 18 +++++++++--------- hw/ide/ide-internal.h | 7 ++++++- hw/ide/isa.c | 2 +- hw/ide/macio.c | 2 +- hw/ide/mmio.c | 2 +- hw/ide/piix.c | 2 +- hw/ide/sii3112.c | 6 +++--- hw/ide/via.c | 2 +- 10 files changed, 30 insertions(+), 25 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 749f0efa1d..49f3047e6f 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -37,7 +37,7 @@ static void check_cmd(AHCIState *s, int port); static void handle_cmd(AHCIState *s, int port, uint8_t slot); -static void ahci_reset_port(AHCIState *s, int port); +static void ahci_reset_port(AHCIState *s, int port, IDEResetKind kind); static bool ahci_write_fis_d2h(AHCIDevice *ad, bool d2h_fis_i); static void ahci_clear_cmd_issue(AHCIDevice *ad, uint8_t slot); static void ahci_init_d2h(AHCIDevice *ad); @@ -334,7 +334,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) case AHCI_PORT_REG_SCR_CTL: if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && ((val & AHCI_SCR_SCTL_DET) == 0)) { - ahci_reset_port(s, port); + ahci_reset_port(s, port, IDE_RESET_HARDWARE); } pr->scr_ctl = val; break; @@ -619,7 +619,7 @@ static void ahci_set_signature(AHCIDevice *ad, uint32_t sig) s->lcyl, s->hcyl, sig); } -static void ahci_reset_port(AHCIState *s, int port) +static void ahci_reset_port(AHCIState *s, int port, IDEResetKind kind) { AHCIDevice *d = &s->dev[port]; AHCIPortRegs *pr = &d->port_regs; @@ -628,7 +628,7 @@ static void ahci_reset_port(AHCIState *s, int port) trace_ahci_reset_port(s, port); - ide_bus_reset(&d->port); + ide_bus_reset(&d->port, kind); ide_state->ncq_queues = AHCI_MAX_CMDS; pr->scr_stat = 0; @@ -1244,7 +1244,7 @@ static void handle_reg_h2d_fis(AHCIState *s, int port, * COMRESET or by setting and clearing the SRST bit. Therefore, * the logic for this is found in ahci_init_d2h() and not here. */ - ahci_reset_port(s, port); + ahci_reset_port(s, port, IDE_RESET_SOFTWARE); } break; } @@ -1650,7 +1650,7 @@ void ahci_reset(AHCIState *s) pr->irq_mask = 0; pr->scr_ctl = 0; pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; - ahci_reset_port(s, i); + ahci_reset_port(s, i, IDE_RESET_HARDWARE); } } diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index d44a90a162..79ab65d64a 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -214,7 +214,7 @@ static void cmd646_reset(DeviceState *dev) unsigned int i; for (i = 0; i < 2; i++) { - ide_bus_reset(&d->bus[i]); + ide_bus_reset(&d->bus[i], IDE_RESET_HARDWARE); } } diff --git a/hw/ide/core.c b/hw/ide/core.c index 5a5f072630..3716cf1b5d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1347,7 +1347,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static void ide_reset(IDEState *s) +static void ide_reset(IDEState *s, IDEResetKind kind) { trace_ide_reset(s); @@ -1356,7 +1356,7 @@ static void ide_reset(IDEState *s) s->pio_aiocb = NULL; } - if (s->reset_reverts) { + if (kind == IDE_RESET_HARDWARE || s->reset_reverts) { s->reset_reverts = false; s->heads = s->drive_heads; s->sectors = s->drive_sectors; @@ -1424,7 +1424,7 @@ static bool cmd_device_reset(IDEState *s, uint8_t cmd) ide_cancel_dma_sync(s); /* Reset any PIO commands, reset signature, etc */ - ide_reset(s); + ide_reset(s, IDE_RESET_SOFTWARE); /* RESET: ATA8-ACS3 7.10.4 "Normal Outputs"; * ATA8-ACS3 Table 184 "Device Signatures for Normal Output" */ @@ -2348,7 +2348,7 @@ static void ide_perform_srst(IDEState *s) ide_cancel_dma_sync(s); /* Cancel PIO callback, reset registers/signature, etc */ - ide_reset(s); + ide_reset(s, IDE_RESET_SOFTWARE); /* perform diagnostic */ cmd_exec_dev_diagnostic(s, WIN_DIAGNOSE); @@ -2553,7 +2553,7 @@ static void ide_dummy_transfer_stop(IDEState *s) s->io_buffer[3] = 0xff; } -void ide_bus_reset(IDEBus *bus) +void ide_bus_reset(IDEBus *bus, IDEResetKind kind) { /* pending async DMA - needs the IDEState before it is reset */ if (bus->dma->aiocb) { @@ -2564,8 +2564,8 @@ void ide_bus_reset(IDEBus *bus) bus->unit = 0; bus->cmd = 0; - ide_reset(&bus->ifs[0]); - ide_reset(&bus->ifs[1]); + ide_reset(&bus->ifs[0], kind); + ide_reset(&bus->ifs[1], kind); ide_clear_hob(bus); /* reset dma provider too */ @@ -2679,7 +2679,7 @@ int ide_init_drive(IDEState *s, IDEDevice *dev, IDEDriveKind kind, Error **errp) pstrcpy(s->version, sizeof(s->version), QEMU_HW_VERSION); } - ide_reset(s); + ide_reset(s, IDE_RESET_HARDWARE); blk_iostatus_enable(s->blk); return 0; } @@ -2816,7 +2816,7 @@ void ide_bus_init_output_irq(IDEBus *bus, qemu_irq irq_out) for(i = 0; i < 2; i++) { ide_init1(bus, i); - ide_reset(&bus->ifs[i]); + ide_reset(&bus->ifs[i], IDE_RESET_HARDWARE); } bus->irq = irq_out; bus->dma = &ide_dma_nop; diff --git a/hw/ide/ide-internal.h b/hw/ide/ide-internal.h index 281d07c9d5..094772209d 100644 --- a/hw/ide/ide-internal.h +++ b/hw/ide/ide-internal.h @@ -393,7 +393,12 @@ extern const VMStateDescription vmstate_ide_drive; #define VMSTATE_IDE_DRIVE(_field, _state) \ VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_drive, IDEState) -void ide_bus_reset(IDEBus *bus); +typedef enum { + IDE_RESET_HARDWARE, /* power on, hardware reset or COMRESET, ATA-5 9.1 */ + IDE_RESET_SOFTWARE, /* SRST or DEVICE RESET, ATA-5 9.2 */ +} IDEResetKind; + +void ide_bus_reset(IDEBus *bus, IDEResetKind kind); int64_t ide_get_sector(IDEState *s); void ide_set_sector(IDEState *s, int64_t sector_num); diff --git a/hw/ide/isa.c b/hw/ide/isa.c index c97b7a1ff4..30f02867b1 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -51,7 +51,7 @@ static void isa_ide_reset(DeviceState *d) { ISAIDEState *s = ISA_IDE(d); - ide_bus_reset(&s->bus); + ide_bus_reset(&s->bus, IDE_RESET_HARDWARE); } static const VMStateDescription vmstate_ide_isa = { diff --git a/hw/ide/macio.c b/hw/ide/macio.c index a7ed41fa26..40fb4f3b4f 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -368,7 +368,7 @@ static void macio_ide_reset(DeviceState *dev) { MACIOIDEState *d = MACIO_IDE(dev); - ide_bus_reset(&d->bus); + ide_bus_reset(&d->bus, IDE_RESET_HARDWARE); } static int ide_nop_int(const IDEDMA *dma, bool is_write) diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 0de904ac56..00819d559d 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -55,7 +55,7 @@ static void mmio_ide_reset(DeviceState *dev) { MMIOIDEState *s = MMIO_IDE(dev); - ide_bus_reset(&s->bus); + ide_bus_reset(&s->bus, IDE_RESET_HARDWARE); } static uint64_t mmio_ide_read(void *opaque, hwaddr addr, diff --git a/hw/ide/piix.c b/hw/ide/piix.c index a0f2709c69..a8472f3e58 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -111,7 +111,7 @@ static void piix_ide_reset(DeviceState *dev) int i; for (i = 0; i < 2; i++) { - ide_bus_reset(&d->bus[i]); + ide_bus_reset(&d->bus[i], IDE_RESET_HARDWARE); } /* PCI command register default value (0000h) per [1, p.48]. */ diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c index 9b28c691fd..03313eb271 100644 --- a/hw/ide/sii3112.c +++ b/hw/ide/sii3112.c @@ -185,7 +185,7 @@ static void sii3112_reg_write(void *opaque, hwaddr addr, case 0x100: d->regs[0].scontrol = val & 0xfff; if (val & 1) { - ide_bus_reset(&d->i.bus[0]); + ide_bus_reset(&d->i.bus[0], IDE_RESET_HARDWARE); } break; case 0x148: @@ -194,7 +194,7 @@ static void sii3112_reg_write(void *opaque, hwaddr addr, case 0x180: d->regs[1].scontrol = val & 0xfff; if (val & 1) { - ide_bus_reset(&d->i.bus[1]); + ide_bus_reset(&d->i.bus[1], IDE_RESET_HARDWARE); } break; case 0x1c8: @@ -243,7 +243,7 @@ static void sii3112_reset(DeviceState *dev) for (i = 0; i < 2; i++) { s->regs[i].confstat = 0x6515 << 16; - ide_bus_reset(&s->i.bus[i]); + ide_bus_reset(&s->i.bus[i], IDE_RESET_HARDWARE); } } diff --git a/hw/ide/via.c b/hw/ide/via.c index 3a77d744ca..6c0610ff41 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -127,7 +127,7 @@ static void via_ide_reset(DeviceState *dev) int i; for (i = 0; i < ARRAY_SIZE(d->bus); i++) { - ide_bus_reset(&d->bus[i]); + ide_bus_reset(&d->bus[i], IDE_RESET_HARDWARE); } pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy mode */ From d1634ae78dd4910a37f11c07d313adb7e1bf5c97 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 18:20:23 +0200 Subject: [PATCH 615/627] tests/qtest/ide-test: cover the CHS translation across resets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A translation the guest selected has to survive a software reset and not a hardware one, and the two arrive at the same ide_reset(), so a fix for either direction can break the other. Select a translation, put the drive through a software reset and then through a machine reset, and name the sector each translation picks along the way. The marker read says which translation the device is addressing the disk with, while IDENTIFY DEVICE words 55 and 56 say which one it reports. The machine reset leaves the PCI command register cleared, so the device has to be enabled again before the ports answer. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index e7a56e0710..f14a0851f0 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1639,6 +1639,51 @@ static void test_specify_identify_default(void) ide_test_quit(qts); } +/* A hardware reset reverts the translation (ATA-5 9.1), SRST does not (9.2) */ +static void test_specify_reset(void) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar, ide_bar2; + uint16_t buf[256]; + char marker[9]; + + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + ide_bar2 = qpci_legacy_iomap(dev, IDE_BASE2); + + ide_prepare_markers(qts, dev, ide_bar); + ide_set_translation(dev, ide_bar, 8, 32); + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_CUSTOM); + + qpci_io_writeb(dev, ide_bar2, 0, IDE_CTRL_RESET); + qpci_io_writeb(dev, ide_bar2, 0, 0); + ide_wait_clear(qts, BSY); + + ide_identify_words(dev, ide_bar, buf); + g_assert_cmpint(buf[55], ==, 8); + g_assert_cmpint(buf[56], ==, 32); + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_CUSTOM); + + qtest_qmp_assert_success(qts, "{ 'execute': 'system_reset' }"); + qtest_qmp_eventwait(qts, "RESET"); + qpci_device_enable(dev); + + ide_identify_words(dev, ide_bar, buf); + g_assert_cmpint(buf[55], ==, 16); + g_assert_cmpint(buf[56], ==, 63); + ide_read_chs_marker(qts, dev, ide_bar, 0, 1, 1, marker); + g_assert_cmpstr(marker, ==, CHS_MARKER_DEFAULT); + + free_pci_device(dev); + ide_test_quit(qts); +} + static void test_cdrom_pio(void) { cdrom_read_impl(1, CDROM_PIO); @@ -1714,6 +1759,7 @@ int main(int argc, char **argv) qtest_add_func("/ide/specify/identify", test_specify_identify); qtest_add_func("/ide/specify/identify_default", test_specify_identify_default); + qtest_add_func("/ide/specify/reset", test_specify_reset); qtest_add_func("/ide/migration/chs_translation", test_migrate_chs_translation); qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot); From e8a3b42ae54e688360c8ac4e6d9f7c4f28c1411f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 14 Aug 2026 18:07:36 +0200 Subject: [PATCH 616/627] hw/ide: drop a redundant interrupt from INITIALIZE DEVICE PARAMETERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ide_bus_exec_cmd() raises the interrupt for every command handler that reports the command complete, which cmd_specify() does, so the request it raised itself was the first of two. The one from ide_bus_exec_cmd() is the one that belongs there, being raised after BSY is cleared and after ide_cmd_done() has let the bus master post its own completion. Cc: John Snow Cc: Peter Maydell Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev Reviewed-by: Philippe Mathieu-Daudé --- hw/ide/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 3716cf1b5d..8190549ee8 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1675,7 +1675,6 @@ static bool cmd_specify(IDEState *s, uint8_t cmd) if (s->identify_set) { ide_identify_chs(s); } - ide_bus_set_irq(s->bus); return true; } From 1332990194b53f5ca6a4fe7ac93cf4ad6eecfa9c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 617/627] hw/ide: reject an out-of-range PIO transfer window on load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ide_drive_pio_post_load() validates end_transfer_fn_idx but takes cur_io_buffer_offset and cur_io_buffer_len straight from the migration stream, so data_ptr and data_end can be placed anywhere within +-2GB of the 131076-byte io_buffer allocation. Both fields are signed 32-bit. The subsection loader consumes every subsection present in the stream without consulting needed(), so a crafted stream can inject ide_drive/pio_state for a drive that was never in a DRQ state. Once data_end is out of bounds, ide_data_writew() only compares the guest's pointer against that same bogus data_end, and the resumed guest turns a repeated outw to the data port into a controlled 16-bit heap write. end_transfer_fn_idx picks the direction, so the read side of the same code path leaks host heap instead. Validate the window against io_buffer_total_len and fail the load. The subtraction form avoids overflowing the addition. Reported-by: XlabAI Team of Tencent Xuanwu Lab Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4179 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3738 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index 8190549ee8..0dca2b5c52 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2898,6 +2898,12 @@ static int ide_drive_pio_post_load(void *opaque, int version_id) if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) { return -EINVAL; } + if (s->cur_io_buffer_offset < 0 || s->cur_io_buffer_len < 0 || + s->cur_io_buffer_offset > s->io_buffer_total_len || + s->cur_io_buffer_len > + s->io_buffer_total_len - s->cur_io_buffer_offset) { + return -EINVAL; + } s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx]; s->data_ptr = s->io_buffer + s->cur_io_buffer_offset; s->data_end = s->data_ptr + s->cur_io_buffer_len; From e46245cd3ba0b7a558fd33dc24dd630a0a9d59d0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 18 Aug 2026 01:05:36 +0200 Subject: [PATCH 618/627] tests/qtest/ide-test: cover the migrated PIO transfer window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ide/migration/pio_state_rejected leaves a drive in DRQ so the source streams ide_drive/pio_state, rewrites cur_io_buffer_offset to the end of the io_buffer, and expects the destination to refuse the load. It asserts the window the source wrote before overwriting it, so a wrong guess at the stream layout fails the test rather than passing it for the wrong reason. Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index f14a0851f0..a3109da908 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -1571,6 +1571,83 @@ static void test_migrate_chs_rejected(void) unlink(path); } +/* A PIO transfer window reaching past the io_buffer has to be refused */ +static void test_migrate_pio_state_rejected(void) +{ + const char *name = "ide_drive/pio_state"; + /* IDE_DMA_BUF_SECTORS * 512 + 4, the length of the streamed io_buffer */ + const gsize io_buffer_len = 256 * 512 + 4; + /* cur_io_buffer_offset and cur_io_buffer_len, big endian */ + const uint8_t in_bounds[8] = { 0, 0, 0, 0, 0, 0, 0x02, 0 }; + const uint8_t past_the_end[8] = { 0, 0x02, 0, 0x04, 0, 0, 0x10, 0 }; + QTestState *src, *dst; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + g_autofree char *path = NULL; + g_autofree char *uri = NULL; + g_autofree char *dst_args = NULL; + g_autofree char *stream = NULL; + char *window; + gsize len; + int fd; + + fd = g_file_open_tmp("qtest-ide-stream.XXXXXX", &path, NULL); + g_assert(fd >= 0); + close(fd); + uri = g_strdup_printf("file:%s", path); + + src = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + dev = get_pci_device(src, &bmdma_bar, &ide_bar); + + /* WRITE SECTOR(S) waits in DRQ for the data, so pio_state is streamed */ + qpci_io_writeb(dev, ide_bar, reg_nsectors, 1); + qpci_io_writeb(dev, ide_bar, reg_lba_low, 0); + qpci_io_writeb(dev, ide_bar, reg_lba_middle, 0); + qpci_io_writeb(dev, ide_bar, reg_lba_high, 0); + qpci_io_writeb(dev, ide_bar, reg_device, LBA); + qpci_io_writeb(dev, ide_bar, reg_command, CMD_WRITE); + assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRQ); + + qtest_qmp_assert_success(src, "{ 'execute': 'migrate'," + " 'arguments': { 'uri': %s } }", uri); + qtest_qmp_eventwait(src, "STOP"); + ide_migration_wait(src, "completed"); + free_pci_device(dev); + ide_test_quit(src); + + /* + * Behind the name come the version and req_nb_sectors as big endian 32 + * bit, then the io_buffer array, then the transfer window this rewrites. + * Asserting the window the source streamed keeps that arithmetic honest. + */ + g_assert(g_file_get_contents(path, &stream, &len, NULL)); + window = ide_stream_find(stream, len, name); + g_assert(window); + window += strlen(name) + 8 + io_buffer_len; + g_assert_cmpint(window - stream + sizeof(past_the_end), <=, len); + g_assert_cmpint(memcmp(window, in_bounds, sizeof(in_bounds)), ==, 0); + memcpy(window, past_the_end, sizeof(past_the_end)); + g_assert(g_file_set_contents(path, stream, len, NULL)); + + dst_args = g_strdup_printf( + "-machine pc " + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 -incoming defer", + tmp_path[0]); + dst = qtest_init(dst_args); + + qtest_qmp_assert_success(dst, "{ 'execute': 'migrate-incoming'," + " 'arguments': { 'uri': %s," + " 'exit-on-error': false } }", uri); + ide_migration_wait(dst, "failed"); + + qtest_quit(dst); + unlink(path); +} + /* Words 54 to 58 follow the translation even when the data was cached first */ static void test_specify_identify(void) { @@ -1764,6 +1841,8 @@ int main(int argc, char **argv) test_migrate_chs_translation); qtest_add_func("/ide/migration/chs_snapshot", test_migrate_chs_snapshot); qtest_add_func("/ide/migration/chs_rejected", test_migrate_chs_rejected); + qtest_add_func("/ide/migration/pio_state_rejected", + test_migrate_pio_state_rejected); qtest_add_func("/ide/identify", test_identify); From d7f16bad8f0263ca01c1da61d5d69ee79fca837f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 619/627] hw/ide/ahci: refuse a PIO transfer with no command header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ahci_map_clb_address() already clears cur_cmd, so every consumer of it has to cope with there being no current command. ahci_pio_transfer(), ahci_commit_buf() and ahci_populate_sglist() all dereference it unconditionally instead. Give the three of them a NULL check. Declaring the data transferred anyway is not enough: ide_transfer_start() goes on to call the end transfer function, and for a multi-sector write that is ide_sector_write(), which commits an io_buffer the guest never refilled. Clearing PxCMD.ST during a WRITE SECTOR(S) of two sectors therefore writes the first sector's contents over the second, at a sector the guest chose. Let pio_transfer report that nothing was transferred and halt there, so no callback acts on a buffer that was never filled. Only the AHCI HBA implements the callback, so the signature change is local to it. Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/ahci.c | 47 +++++++++++++++++++++++++++++++--------- hw/ide/core.c | 11 +++++++++- hw/ide/trace-events | 2 ++ include/hw/ide/ide-dma.h | 3 ++- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 49f3047e6f..995b40efd5 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -906,12 +906,12 @@ static int prdt_tbl_entry_size(const AHCI_SG *tbl) static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, AHCICmdHdr *cmd, int64_t limit, uint64_t offset) { - uint16_t opts = le16_to_cpu(cmd->opts); - uint16_t prdtl = le16_to_cpu(cmd->prdtl); - uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr); - uint64_t prdt_addr = cfis_addr + 0x80; - dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG)); - dma_addr_t real_prdt_len = prdt_len; + uint16_t opts; + uint16_t prdtl; + uint64_t cfis_addr; + uint64_t prdt_addr; + dma_addr_t prdt_len; + dma_addr_t real_prdt_len; uint8_t *prdt; int i; int r = 0; @@ -923,6 +923,18 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, trace_ahci_populate_sglist(ad->hba, ad->port_no); + if (!cmd) { + trace_ahci_populate_sglist_no_cmd(ad->hba, ad->port_no); + return -1; + } + + opts = le16_to_cpu(cmd->opts); + prdtl = le16_to_cpu(cmd->prdtl); + cfis_addr = le64_to_cpu(cmd->tbl_addr); + prdt_addr = cfis_addr + 0x80; + prdt_len = (prdtl * sizeof(AHCI_SG)); + real_prdt_len = prdt_len; + if (!prdtl) { trace_ahci_populate_sglist_no_prdtl(ad->hba, ad->port_no, opts); return -1; @@ -1371,18 +1383,27 @@ out: } /* Transfer PIO data between RAM and device */ -static void ahci_pio_transfer(const IDEDMA *dma) +static bool ahci_pio_transfer(const IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); IDEState *s = &ad->port.ifs[0]; uint32_t size = (uint32_t)(s->data_end - s->data_ptr); /* write == ram -> device */ - uint16_t opts = le16_to_cpu(ad->cur_cmd->opts); - int is_write = opts & AHCI_CMD_WRITE; - int is_atapi = opts & AHCI_CMD_ATAPI; + uint16_t opts; + int is_write; + int is_atapi; int has_sglist = 0; bool pio_fis_i; + if (ad->cur_cmd == NULL) { + trace_ahci_pio_transfer_no_cmd(ad->hba, ad->port_no); + return false; + } + + opts = le16_to_cpu(ad->cur_cmd->opts); + is_write = opts & AHCI_CMD_WRITE; + is_atapi = opts & AHCI_CMD_ATAPI; + /* The PIO Setup FIS is received prior to transfer, but the interrupt * is only triggered after data is received. * @@ -1430,6 +1451,8 @@ out: if (pio_fis_i) { ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_PSS); } + + return true; } static void ahci_start_dma(const IDEDMA *dma, IDEState *s, @@ -1492,6 +1515,10 @@ static void ahci_commit_buf(const IDEDMA *dma, uint32_t tx_bytes) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); + if (ad->cur_cmd == NULL) { + return; + } + tx_bytes += le32_to_cpu(ad->cur_cmd->status); ad->cur_cmd->status = cpu_to_le32(tx_bytes); } diff --git a/hw/ide/core.c b/hw/ide/core.c index 0dca2b5c52..06c18dbf09 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -80,6 +80,7 @@ static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval) } static void ide_dummy_transfer_stop(IDEState *s); +static void ide_transfer_halt(IDEState *s); const MemoryRegionPortio ide_portio_list[] = { { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write }, @@ -568,7 +569,15 @@ bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size, s->end_transfer_func = end_transfer_func; return false; } - s->bus->dma->ops->pio_transfer(s->bus->dma); + if (!s->bus->dma->ops->pio_transfer(s->bus->dma)) { + /* + * No data reached the buffer, so the caller must not act on it. A + * write would otherwise commit whatever the previous phase left + * there to the next sector. + */ + ide_transfer_halt(s); + return false; + } return true; } diff --git a/hw/ide/trace-events b/hw/ide/trace-events index 57042cafdd..f1472f5852 100644 --- a/hw/ide/trace-events +++ b/hw/ide/trace-events @@ -85,6 +85,7 @@ ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port" ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address" ahci_unmap_clb_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL CLB address" ahci_populate_sglist(void *s, int port) "ahci(%p)[%d]" +ahci_populate_sglist_no_cmd(void *s, int port) "ahci(%p)[%d]: no command header" ahci_populate_sglist_no_prdtl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: no sg list given by guest: 0x%04x" ahci_populate_sglist_no_map(void *s, int port) "ahci(%p)[%d]: DMA mapping failed" ahci_populate_sglist_short_map(void *s, int port) "ahci(%p)[%d]: mapped less than expected" @@ -109,6 +110,7 @@ handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cm handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80" handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x" ahci_pio_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist" +ahci_pio_transfer_no_cmd(void *s, int port) "ahci(%p)[%d]: PIO transfer without a command header" ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma" ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32 ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed" diff --git a/include/hw/ide/ide-dma.h b/include/hw/ide/ide-dma.h index 296010a4e0..34154b7cbc 100644 --- a/include/hw/ide/ide-dma.h +++ b/include/hw/ide/ide-dma.h @@ -10,6 +10,7 @@ typedef struct IDEDMA IDEDMA; typedef void DMAStartFunc(const IDEDMA *, IDEState *, BlockCompletionFunc *); typedef void DMAVoidFunc(const IDEDMA *); +typedef bool DMABoolFunc(const IDEDMA *); typedef int DMAIntFunc(const IDEDMA *, bool); typedef int32_t DMAInt32Func(const IDEDMA *, int32_t len); typedef void DMAu32Func(const IDEDMA *, uint32_t); @@ -17,7 +18,7 @@ typedef void DMAStopFunc(const IDEDMA *, bool); struct IDEDMAOps { DMAStartFunc *start_dma; - DMAVoidFunc *pio_transfer; + DMABoolFunc *pio_transfer; DMAInt32Func *prepare_buf; DMAu32Func *commit_buf; DMAIntFunc *rw_buf; From a2fbf1785b7a464d61c0f60c4ad0a86d82925e5d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 620/627] hw/ide/ahci: clear cur_cmd when the command list is unmapped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ahci_unmap_clb_address() drops the CLB mapping but leaves cur_cmd pointing into it. The cancel added by commit d9f78431d8 covers the buffered reads, and ide_cancel_dma_sync() drains bus->dma->aiocb, but neither reaches IDEState::pio_aiocb: a PIO write started before the guest cleared PxCMD.ST completes afterwards and runs its second DRQ phase against the stale header. That is harmless while the CLB is direct RAM, because unmapping it changes nothing. It is a use-after-free once PxCLB points at an MMIO region, where address_space_map() hands out a bounce buffer that dma_memory_unmap() then frees. Clear cur_cmd after the cancel, so nothing reachable from a later completion still refers to the freed mapping. Reported-by: Katherine Leaver Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3719 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4043 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/ahci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 995b40efd5..4c138b0c51 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -743,6 +743,12 @@ static void ahci_unmap_clb_address(AHCIDevice *ad) /* Cancel in-flight reads that would complete against a cleared cur_cmd. */ ide_cancel_dma_sync(ide_bus_active_if(&ad->port)); + /* + * Whatever survives the cancel must not be left pointing into the + * mapping this function is about to drop. + */ + ad->cur_cmd = NULL; + if (ad->lst == NULL) { trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no); return; From d05ae87e7a6ab519a99f8c44f40d97152adb8b08 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 621/627] tests/qtest/ahci: regression test for a PIO write vs. engine stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add /ahci/io/pio/engine_stop: hold the backend write of a two-sector PIO write with a blkdebug breakpoint, clear PxCMD.ST so the command list is unmapped underneath it, then let the write complete. The second DRQ phase runs from that completion and reaches ahci_pio_transfer() with no command header. Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ahci-test.c | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 30d7005626..84d4e6b0a5 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1793,6 +1793,76 @@ static void test_atapi_engine_restart_dma(void) test_atapi_engine_restart_in_flight(true); } +/* + * Regression test: a PIO write outlives the command list it was issued from. + * ide_cancel_dma_sync() does not reach s->pio_aiocb, so the second DRQ phase + * runs from the write completion after PxCLB has been unmapped and must not + * touch the command header any more. + */ +static void test_write_engine_stop_in_flight(void) +{ + AHCIQState *ahci; + AHCICommand *cmd; + unsigned char *tx; + unsigned char *rx; + uint64_t ptr; + uint8_t port; + size_t bufsize = AHCI_SECTOR_SIZE * 2; + size_t i; + + ahci = ahci_boot_and_enable("-drive file=blkdebug::%s,if=none,id=drive0," + "format=%s,cache=writeback " + "-M q35 " + "-device ide-hd,drive=drive0 ", + tmp_path, imgfmt); + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + + tx = g_malloc(bufsize); + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); + ptr = ahci_alloc(ahci, bufsize); + g_assert(ptr); + qtest_memwrite(ahci->parent->qts, ptr, tx, bufsize); + + /* Zero the second sector, which the abandoned command must not reach. */ + rx = g_malloc0(AHCI_SECTOR_SIZE); + ahci_io(ahci, port, CMD_WRITE_DMA, rx, AHCI_SECTOR_SIZE, 1); + + /* Suspend the backend write so the first sector stays in flight. */ + g_free(qtest_hmp(ahci->parent->qts, + "qemu-io drive0 \"break write_aio wr\"")); + + cmd = ahci_command_create(CMD_WRITE_PIO); + ahci_command_adjust(cmd, 0, ptr, bufsize, 0); + ahci_command_commit(ahci, cmd, port); + ahci_command_issue_async(ahci, cmd); + + /* Drop the command list while the write is still outstanding. */ + ahci_px_clr(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST); + + g_free(qtest_hmp(ahci->parent->qts, "qemu-io drive0 \"resume wr\"")); + + /* Round-trip through the device to confirm qemu is still alive. */ + ahci_px_rreg(ahci, port, AHCI_PX_TFD); + + /* + * The second DRQ phase never fetched its data, so the sector it would + * have carried has to be untouched rather than hold a copy of the first. + */ + ahci_px_set(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST); + memset(rx, 0xff, AHCI_SECTOR_SIZE); + ahci_io(ahci, port, CMD_READ_DMA, rx, AHCI_SECTOR_SIZE, 1); + for (i = 0; i < AHCI_SECTOR_SIZE; i++) { + g_assert_cmpint(rx[i], ==, 0); + } + + ahci_command_free(cmd); + ahci_free(ahci, ptr); + g_free(rx); + g_free(tx); + ahci_shutdown(ahci); +} + /* * Regression test: a multi-sector ATAPI read fetches its later sectors from * inside the first read's completion; a concurrent drain (as a guest reset @@ -2281,6 +2351,8 @@ int main(int argc, char **argv) test_atapi_engine_restart_pio); qtest_add_func("/ahci/cdrom/engine_restart/dma", test_atapi_engine_restart_dma); + qtest_add_func("/ahci/io/pio/engine_stop", + test_write_engine_stop_in_flight); qtest_add_func("/ahci/cdrom/drain/pio", test_atapi_drain_pio); qtest_add_func("/ahci/cdrom/drain/dma", test_atapi_drain_dma); From 2713717148f538577e5f2a5d4d9dc272f7a8dc4b Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 622/627] hw/ide/ahci: treat a failed PRDT walk as a PIO transfer failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ahci_dma_prepare_buf() returns -1 when it cannot build a scatter-gather list, the PRDTL of zero case among them. ahci_pio_transfer() tests the result for truth, so a failure sets has_sglist and the transfer goes ahead against whatever s->sg holds. AHCI 1.3.1 is explicit about the zero case: "If this field is '0', then no data transfer shall occur with the command." Test for a positive byte count instead. A successful walk that yields nothing to transfer is already handled by the size check below. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4043 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 4c138b0c51..436a0eaab6 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1428,7 +1428,7 @@ static bool ahci_pio_transfer(const IDEDMA *dma) goto out; } - if (ahci_dma_prepare_buf(dma, size)) { + if (ahci_dma_prepare_buf(dma, size) > 0) { has_sglist = 1; } From 795af987ce4cbac260582189cff2394a27eff7cb Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 623/627] hw/ide/ahci: reject a command header with an invalid FIS length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AHCI 1.3.1 defines CFL in the command header as the "Length of the Command FIS", where "A length of '0' or '1' is illegal" and "The maximum value allowed is 10h, or 16 DW". handle_cmd() never looks at it, so an all-zero command header is executable: its zero tbl_addr maps a command table at guest physical address 0, and a guest that has put a valid Register H2D FIS there gets it run. That is the reachability a guest gains by pointing PxCLB at an MMIO region, where the CLB is a zero-filled bounce buffer rather than anything the guest wrote. Reject a header whose CFL falls outside the legal range. Nothing else consults it; the command FIS is always mapped at its full 128 bytes. The slot is dropped without reporting anything, as the unmappable command table beside it already is. No PxIS bit describes a malformed command header: HBFS is for a host bus error, "such as a bad software pointer", which is why the short mapping below raises it and this does not. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4043 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/ahci.c | 9 +++++++++ hw/ide/trace-events | 1 + 2 files changed, 10 insertions(+) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 436a0eaab6..2b2ef873e0 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1334,6 +1334,7 @@ static void handle_cmd(AHCIState *s, int port, uint8_t slot) AHCICmdHdr *cmd; uint8_t *cmd_fis; dma_addr_t cmd_len; + uint8_t cfl; if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { /* Engine currently busy, try again later */ @@ -1346,6 +1347,14 @@ static void handle_cmd(AHCIState *s, int port, uint8_t slot) return; } cmd = get_cmd_header(s, port, slot); + + /* AHCI 1.3.1: a CFL below 2 dwords or above 16 is illegal */ + cfl = le16_to_cpu(cmd->opts) & AHCI_CMD_HDR_CMD_FIS_LEN; + if (cfl < 2 || cfl > 16) { + trace_handle_cmd_badcfl(s, port, le16_to_cpu(cmd->opts)); + return; + } + /* remember current slot handle for later */ s->dev[port].cur_cmd = cmd; diff --git a/hw/ide/trace-events b/hw/ide/trace-events index f1472f5852..3ab5e7bd1d 100644 --- a/hw/ide/trace-events +++ b/hw/ide/trace-events @@ -106,6 +106,7 @@ handle_reg_h2d_fis_res(void *s, int port, char b0, char b1, char b2) "ahci(%p)[% handle_cmd_busy(void *s, int port) "ahci(%p)[%d]: engine busy" handle_cmd_nolist(void *s, int port) "ahci(%p)[%d]: handle_cmd called without s->dev[port].lst" handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port" +handle_cmd_badcfl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: guest provided an invalid cmd FIS length: 0x%04x" handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS" handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80" handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x" From 5bdc12fed592a1673f64ca1e8243046632f83a26 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 18 Aug 2026 09:55:48 +0200 Subject: [PATCH 624/627] hw/ide/ahci: drain the ports on teardown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ahci_uninit() frees s->dev without touching the requests still in flight. The only blk_aio_cancel() for them lives in ahci_reset_port(), which the unplug path does not run, and the ide-hd child's own drain is deferred through call_rcu so it happens after the free. A guest that powers the root port slot off through SLTCTL, or writes the ACPI ejection register, while a read is outstanding therefore leaves the completion to run against freed memory. A plain device_del is not affected: the pciehp attention-button flow resets the secondary bus first, which cancels through the reset path. Surprise removal is what skips it. Cancelling the NCQ requests alone is not enough. IDEDMA and IDEBus are embedded in AHCIDevice, so a plain DMA read reaches the freed array through dma_blk_cb() and a PIO read through ide_buffered_readv_cb(), neither of which the NCQ bookkeeping covers. ide_exit() drains nothing and frees io_buffer, which an outstanding request may still target. Move the NCQ cancel loop into a helper, run it from ahci_uninit() too, and drain each port before ide_exit() so no class of request can outlive the allocation. Delete check_bh there as well; qemu_bh_new_guarded() in check_cmd() has no counterpart on this path either. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4069 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/ahci.c | 72 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 2b2ef873e0..6b04762c4a 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -619,12 +619,37 @@ static void ahci_set_signature(AHCIDevice *ad, uint32_t sig) s->lcyl, s->hcyl, sig); } +static void ahci_cancel_ncq_requests(AHCIDevice *ad) +{ + int i; + + for (i = 0; i < AHCI_MAX_CMDS; i++) { + NCQTransferState *ncq_tfs = &ad->ncq_tfs[i]; + ncq_tfs->halt = false; + if (!ncq_tfs->used) { + continue; + } + + if (ncq_tfs->aiocb) { + blk_aio_cancel(ncq_tfs->aiocb); + ncq_tfs->aiocb = NULL; + } + + /* Maybe we just finished the request thanks to blk_aio_cancel() */ + if (!ncq_tfs->used) { + continue; + } + + qemu_sglist_destroy(&ncq_tfs->sglist); + ncq_tfs->used = 0; + } +} + static void ahci_reset_port(AHCIState *s, int port, IDEResetKind kind) { AHCIDevice *d = &s->dev[port]; AHCIPortRegs *pr = &d->port_regs; IDEState *ide_state = &d->port.ifs[0]; - int i; trace_ahci_reset_port(s, port); @@ -645,27 +670,7 @@ static void ahci_reset_port(AHCIState *s, int port, IDEResetKind kind) return; } - /* reset ncq queue */ - for (i = 0; i < AHCI_MAX_CMDS; i++) { - NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i]; - ncq_tfs->halt = false; - if (!ncq_tfs->used) { - continue; - } - - if (ncq_tfs->aiocb) { - blk_aio_cancel(ncq_tfs->aiocb); - ncq_tfs->aiocb = NULL; - } - - /* Maybe we just finished the request thanks to blk_aio_cancel() */ - if (!ncq_tfs->used) { - continue; - } - - qemu_sglist_destroy(&ncq_tfs->sglist); - ncq_tfs->used = 0; - } + ahci_cancel_ncq_requests(d); s->dev[port].port_state = STATE_RUN; if (ide_state->drive_kind == IDE_CD) { @@ -1659,8 +1664,29 @@ void ahci_uninit(AHCIState *s) for (i = 0; i < s->ports; i++) { AHCIDevice *ad = &s->dev[i]; + /* + * Unplug does not go through a reset, so this is the only chance to + * detach the requests and the bottom half that would otherwise walk + * s->dev after it is freed below. + */ + ahci_cancel_ncq_requests(ad); + if (ad->check_bh) { + qemu_bh_delete(ad->check_bh); + ad->check_bh = NULL; + } + for (j = 0; j < 2; j++) { - ide_exit(&ad->port.ifs[j]); + IDEState *ide_state = &ad->port.ifs[j]; + + /* + * Everything the port still owns points into the allocation this + * function frees, io_buffer included, so nothing may be left in + * flight once ide_exit() has run. + */ + if (ide_state->blk) { + blk_drain(ide_state->blk); + } + ide_exit(ide_state); } object_unparent(OBJECT(&ad->port)); } From 0b7cc42531eafa02742c783bd895035f3c867400 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 18 Aug 2026 09:55:48 +0200 Subject: [PATCH 625/627] tests/qtest/ahci: regression test for a request outliving an unplug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add /ahci/io/{ncq,dma,pio}/unplug: arm a read against a null-co backend whose latency keeps it in flight, then eject the controller through the ACPI ejection register. Each of the three reaches the freed AHCIDevice array by a different route, so covering one command class would leave the other two untested. That register is what a guest writes to finish a PCI unplug, and unlike the pciehp attention button it reaches ahci_uninit() with no secondary bus reset, so nothing cancels the request on the way. It also dictates the machine: q35 has no ACPI hotplug on pcie.0, so the eject has no effect there. The latency is what holds the request; a blkdebug breakpoint cannot stand in for it, because cancelling a suspended request waits for it and the unplug would never return. Unfixed, all three fail reliably under AddressSanitizer. On a plain build the use-after-free only faults when the freed page has been returned, so expect the odd pass there. Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ahci-test.c | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 84d4e6b0a5..b143862ce7 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1793,6 +1793,78 @@ static void test_atapi_engine_restart_dma(void) test_atapi_engine_restart_in_flight(true); } +/* + * Regression test: an unplug runs no device reset, so it is the last chance to + * detach an outstanding request. Its completion would otherwise walk the + * AHCIDevice array that ahci_uninit() has freed, which each of the NCQ, DMA + * and PIO completions reaches by a different route. + * + * The ACPI ejection register is what a guest writes to finish a PCI unplug. + * -M pc is what puts it in reach: q35 has no ACPI hotplug on pcie.0, so the + * unplug never happens there. Unlike the pciehp attention button this reaches + * the unplug with no secondary bus reset, which is the ordering that leaves a + * request outstanding. + */ +static void test_unplug_in_flight(uint8_t ide_cmd) +{ + AHCIQState *ahci; + AHCICommand *cmd; + uint64_t ptr; + uint8_t port; + QTestState *qts; + + /* + * The latency keeps the backend read in flight across the unplug. A + * blkdebug breakpoint cannot stand in for it: cancelling a suspended + * request waits for it, so the unplug would never return. + */ + ahci = ahci_boot_and_enable( + "-M pc " + "-blockdev driver=null-co,node-name=drive0,read-zeroes=on," + "latency-ns=100000000 " + "-device ich9-ahci,addr=1f.2,id=ahci0 " + "-device ide-hd,drive=drive0,bus=ahci0.0 "); + qts = ahci->parent->qts; + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + + ptr = ahci_alloc(ahci, AHCI_SECTOR_SIZE); + g_assert(ptr); + + cmd = ahci_command_create(ide_cmd); + ahci_command_adjust(cmd, 0, ptr, AHCI_SECTOR_SIZE, 0); + ahci_command_commit(ahci, cmd, port); + ahci_command_issue_async(ahci, cmd); + + /* Eject slot 0x1f of the root bus, which frees the AHCIDevice array. */ + qtest_outl(qts, 0xae10, 0); + qtest_outl(qts, 0xae08, 1u << 0x1f); + qtest_qmp_eventwait(qts, "DEVICE_DELETED"); + + /* Four times the backend latency, so the completion has surely run. */ + g_usleep(400 * 1000); + qtest_qmp_assert_success(qts, "{ 'execute': 'query-status' }"); + + ahci_command_free(cmd); + ahci_free(ahci, ptr); + ahci_shutdown(ahci); +} + +static void test_unplug_ncq(void) +{ + test_unplug_in_flight(READ_FPDMA_QUEUED); +} + +static void test_unplug_dma(void) +{ + test_unplug_in_flight(CMD_READ_DMA); +} + +static void test_unplug_pio(void) +{ + test_unplug_in_flight(CMD_READ_PIO); +} + /* * Regression test: a PIO write outlives the command list it was issued from. * ide_cancel_dma_sync() does not reach s->pio_aiocb, so the second DRQ phase @@ -2351,6 +2423,9 @@ int main(int argc, char **argv) test_atapi_engine_restart_pio); qtest_add_func("/ahci/cdrom/engine_restart/dma", test_atapi_engine_restart_dma); + qtest_add_func("/ahci/io/ncq/unplug", test_unplug_ncq); + qtest_add_func("/ahci/io/dma/unplug", test_unplug_dma); + qtest_add_func("/ahci/io/pio/unplug", test_unplug_pio); qtest_add_func("/ahci/io/pio/engine_stop", test_write_engine_stop_in_flight); qtest_add_func("/ahci/cdrom/drain/pio", test_atapi_drain_pio); From 60faaa8c3bd6b9b420adcb2530a9d5fbc52a0c5e Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 17 Aug 2026 23:44:59 +0200 Subject: [PATCH 626/627] hw/ide: report ATAPI UDMA5 with a matching standard and cable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IDENTIFY PACKET DEVICE claims UDMA mode 5 in word 88 while word 80 reports support only up to ATA/ATAPI-4. UDMA5 first appears in ATA/ATAPI-6; ATA/ATAPI-5 stops at mode 4. Bits 3:1 of word 80 are obsolete in IDENTIFY PACKET DEVICE data as well, so the old 001eh claimed three standards that mean nothing for a packet device. Report 0070h, ATA/ATAPI-4 through ATA/ATAPI-6. Word 93 was left unset, so nothing reported the 80-conductor cable that UDMA5 needs. Fill it in, but only for a parallel attachment: ACS-3 7.13.6.41 gives word 93 of IDENTIFY PACKET DEVICE data the meaning of word 93 of IDENTIFY DEVICE data, where "For SATA devices, word 93 shall be set to the value 0000h". A cleared ncq_queues is how both identify paths already tell a parallel attachment from an AHCI one. The device 0 reset result is 0fh rather than the 01h ide_identify() reports: bit 3 says diagnostics passed, which they did, and bits 2:1 say the device number came from some other method, the only one of the four encodings that is not a jumper, CSEL or reserved. Raising word 80 has a second effect. Linux decides a device is SATA in ata_id_is_sata(), which wants word 93 clear and word 80 at ATA/ATAPI-5 or later. An AHCI CD-ROM satisfied neither condition before and was taken for a parallel device; now it satisfies both. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4038 Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- hw/ide/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 06c18dbf09..ef573798d9 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -292,7 +292,7 @@ static void ide_atapi_identify(IDEState *s) put_le16(p + 76, (1 << 8)); } - put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ + put_le16(p + 80, 0x70); /* support up to ATA/ATAPI-6 */ if (s->wwn) { put_le16(p + 84, (1 << 8)); /* supports WWN for words 108-111 */ put_le16(p + 87, (1 << 8)); /* WWN enabled */ @@ -300,6 +300,10 @@ static void ide_atapi_identify(IDEState *s) #ifdef USE_DMA_CDROM put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ + if (!s->ncq_queues) { + /* word 93 is parallel ATA only, a SATA device reports zero */ + put_le16(p + 93, 0x600f); + } #endif if (s->wwn) { From dd90d3cd73b9b2b0f27a9e51bfe542b3a510545b Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 18 Aug 2026 01:05:36 +0200 Subject: [PATCH 627/627] tests/qtest/ide-test: cover the UDMA5 identify words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /ide/identify/udma and /ide/identify/udma_atapi check that a device advertising UDMA mode 5 claims a standard that defines it and reports the hardware reset result, on the disk and on the CD-ROM. The ATAPI case also checks that the words obsolete in IDENTIFY PACKET DEVICE data stay clear, and that the reset result reports a passed diagnostic, which only the packet path does so far. Cc: John Snow Cc: Philippe Mathieu-Daudé Signed-off-by: Denis V. Lunev --- tests/qtest/ide-test.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c index a3109da908..92e3d9b343 100644 --- a/tests/qtest/ide-test.c +++ b/tests/qtest/ide-test.c @@ -104,6 +104,7 @@ enum { CMD_FLUSH_CACHE = 0xe7, CMD_IDENTIFY = 0xec, CMD_PACKET = 0xa0, + CMD_IDENTIFY_PACKET = 0xa1, CMD_READ_NATIVE = 0xf8, /* READ NATIVE MAX ADDRESS */ CMDF_ABORT = 0x100, @@ -1571,6 +1572,72 @@ static void test_migrate_chs_rejected(void) unlink(path); } +/* + * A device advertising UDMA5 has to claim a standard that defines it, and a + * parallel attachment has to report the cable word (ACS-3 7.12.7.47). + */ +static void test_identify_udma(bool packet) +{ + QTestState *qts; + QPCIDevice *dev; + QPCIBar bmdma_bar, ide_bar; + uint16_t buf[256]; + int i; + + if (packet) { + qts = ide_test_start("-device ide-cd,bus=ide.0"); + } else { + qts = ide_test_start( + "-blockdev driver=file,node-name=hda,filename=%s " + "-device ide-hd,drive=hda,bus=ide.0,unit=0 ", + tmp_path[0]); + } + dev = get_pci_device(qts, &bmdma_bar, &ide_bar); + + qpci_io_writeb(dev, ide_bar, reg_device, 0); + qpci_io_writeb(dev, ide_bar, reg_command, + packet ? CMD_IDENTIFY_PACKET : CMD_IDENTIFY); + for (i = 0; i < 256; i++) { + buf[i] = qpci_io_readw(dev, ide_bar, reg_data); + } + + /* UDMA5 supported and selected */ + assert_bit_set(buf[88], 1 << 5); + assert_bit_set(buf[88], 1 << 13); + + /* UDMA5 arrived in ATA/ATAPI-6, so word 80 has to reach bit 6 */ + assert_bit_set(buf[80], 1 << 6); + if (packet) { + /* Bits 3:1 are obsolete in IDENTIFY PACKET DEVICE data */ + assert_bit_clear(buf[80], 0x0e); + } + + /* Word 93: reserved bit clear, fixed bit set, 80-conductor cable */ + assert_bit_clear(buf[93], 1 << 15); + assert_bit_set(buf[93], 1 << 14); + assert_bit_set(buf[93], 1 << 13); + assert_bit_set(buf[93], 1 << 0); + /* Device 0 clears the device 1 result */ + assert_bit_clear(buf[93], 0x1f00); + if (packet) { + /* the disk path has yet to gain this */ + assert_bit_set(buf[93], 1 << 3); + } + + free_pci_device(dev); + ide_test_quit(qts); +} + +static void test_identify_udma_ata(void) +{ + test_identify_udma(false); +} + +static void test_identify_udma_atapi(void) +{ + test_identify_udma(true); +} + /* A PIO transfer window reaching past the io_buffer has to be refused */ static void test_migrate_pio_state_rejected(void) { @@ -1843,6 +1910,8 @@ int main(int argc, char **argv) qtest_add_func("/ide/migration/chs_rejected", test_migrate_chs_rejected); qtest_add_func("/ide/migration/pio_state_rejected", test_migrate_pio_state_rejected); + qtest_add_func("/ide/identify/udma", test_identify_udma_ata); + qtest_add_func("/ide/identify/udma_atapi", test_identify_udma_atapi); qtest_add_func("/ide/identify", test_identify);

j_dnA{ckfU@|Pb@?L2E;965Hc-xi|^{f?8 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 x~^*4y38OA#=F{1 zyFm*(T`KNmEvt>wfH$D-Fs<9)>YZg@z7*-K8@_D^S|rnD9x5dc=4+2-UM&}2V;~%E zSpo_8+C$*xm5BT4-}5-kE#Zw@(QRkc#;~{p?#tM^4VF)Tjfgvn+~;~P0Z;_;&%%wj z(oo^c7Uj>UldpiN<^nH4)|4Iu5=wRCOH0}cOCLUhGKHU z6^s-AGO#ywqh+URWCcP{T?*}UtYh>AF90^48Vfu6k9`H|fN+7*m0tyRk+k4AQ*e()+sj@h#t!R}4M6`>2F-m1K zU66QxJEWZ8<)(VZmC5Ki#T`PW6M9u1`+w{T5F z1y%5yhtj|;5Kl^#bgAqqBcci^XT~fr!UF(N$SU!!h>5$$f6PE~*H-g^g zi%peAOherLx<-Rr+cwHr-iQh`e_f;kF(>Tr9qPiQZblyc>W>^!Dot;m^ zB=a&pLh6p6^g>$LM15S9sALEd>8pp$bF!_HoqpPv)Lc{ldeZU8;I4c;)agGm+>zz1 zn=A)L`-#7E=^?PZML;16Y-$w~UP^zVaLOqUeL)gqUdG)DfO7k#d!0OU{lLY{6I7?;1k^Sz2u%FkDlO1=!*; zl4q6@VSZU*a*hvzofEwAQqD2=72boHFu%bv!-!^#YgGN>Wmsske6yPFn2IrOP?wGt zFwNJr%Qt)1*z^rK(a~Hb&$bs0u-uE~@)z;c`;tZ&*J+&=wWlsA(=&QOUbOV1*l_#` z1A*wIDr-ZX>4dJhGlMw8{FSeFUcTJnkOVI7C=q>U+^4hULP312gQ8gZPEe3JZ-S(l z_f}{^qfri-N`u`#r$9{(LN?*3L7onEbwDuYIavdNghqgk&bsKUONc)J1 zzC@0da9UqIv+VxGgE-nurmXXD0G|8@yz?Mw(R--MmYJ0~bLdMu%Sn}oFD z>d$?rqs<+@W9zK5-bpF9XM1lqg6$crt<%|d!=i1I-QE_L?t>+*XQsM;WCGqUeCxk! ztalw}>71S_W&q#Tj zy2zpXfN7<#1&MD??ww(#64EhPbQzWKQCQl>PCyhhOwz5zG=CI5J1UzqAwsUy9o8ji zG9FRPfg-YjcQF5d>#K({fPxrk%RR(dc&#O)n<1u_8C74LJB4DJ7MJlA%HJ`tWv<2D zG~1I|Y`AVnOz2#+sk?0$qy0N-Fp86T4o;2b8QW@+t<2jbr~s5cdKyV@w4p zt<`EkzRqGkjLugn8UmP7$ox%}mQ_!8kj0(bQ!_LOM9X_dKh*x-vzDA*8FlZ(&?_;7 zQ_?Zej?*Foj4N3zZhk4ofIl$saqL4DmCMr3)}lEQhd0zQcB7K^py%xBK)W$^xE*Wt zy-1~}g-ZEB2sbxTB(6G2hZOP$m~d2kO*u$qDnkRzZ9D>+8u8j$n!0rNl!)W8k=(HL zRQoq(KlJJwiA*TtXL3{+CHa~r8p8#Qx<}h(fz$knm+m9xs^lqH5*88Q%^C?g%S$J= zn^~l6iQ1*>k<>Uf(oiMB9Zs(Fu#sThwNoK7~l6{hJ~s@z2Kb;Y!or(P$*7VVv_g&BA9%QU;8UT>dcibnxD zc)u^Ro*lcXrJ&Xi4T+mn5Z3Olpg-Qi6_k;^vKf_)VGB^f7}x7`$SsM4p6o%ySl(|mo(eW>6bB2X@l%AQ3!qk z?B_kehUgW-FEGWXj=62q|# zCB5z&KqN2Yi)!7c{zk7fz6IrGje&d9>3^vL7_BVQ&R3d!TLFoLE|{Yhy7Hx%#vFIR0=Uw}mCn+|TC*|1IpcfMnVo*Eh}84o&?(HMs&&5M(<8U9ymZmhFiJ_OsIOP7vWgKQ$Y4l}v=RoV;@02_S-Uv%?8B|yAY%jbUt-F6ksBON zDU7V#6J=@iNJ^i?Rw=?~A7A16=K=aa{~@nkoC_T=gAWcI@} zezH4#{OtQ=@_qb#_lKbO1cNm{p$U%OWM8&!FPZMnoTck*l+C$k^Z-RD0(VeS1u+e0_tZ4N4|Z68#LFgLIOw@f&m+(_-553T|%z8r8~Fb1Ag3f`2hK0=Q9h3 zz2)iLastB{Y@XjRHaNGO7>BjF7QOkzbanLC5|po9?CQ zTZYG?sEm5 z%)E<&|8^~2-3RC?M@VaS%}7&*A?9*0a-P%r)*z569Pc>np`akT&8-MbI(qhJ1ZY`e9fFH5@} zUnNU19&Z&Wtj))#P1nUgrXx^Os3P+yqft}Zd^VD(N|);eH}HGM(&BqDzbgRLo3Y3u z9i2T=*zMDh&yhuATuG(yLh8>4$Zph-&8jw{+GJ`2$<0wq<~*sZF`R>uCA*=v+)iq%h;3kA zv4&1F<1-n9?SApjNj3^+vb1*t>xO%2iuol05YTPp=90W9*aaudrjDgCO&dRJaT+nS z&Vq-l0B#Tm2|$rn+xiNDHSo{)McqK1&qJ0(@`cD~-o$qPu! zV+W+I)>6n}q&T%w)XW8EUA1;hb8DGbq>6l>URv^Q zRN_Rkt@wEK?1}QtZkCdDt?h(mRj;ee{MF>+uO!Nf5NC>?v?8w7h;f@$f(*-+)zCX^ z%PP|pSV#2budU!nYhuanEVLc-m2VT>=F>vO*noXM3$KL)cS8;NZ0I$`65^L=EC&^n zjAha^2LmNUYLX0!FDH)h_pod(XnQfoW~ZI_{=q4!^p*$C=rM<##bQ zrKIKtd0DqH3kE%P$>Ct1uplqRR}&WDR0N*8EP(X^nW+d+xv0(_9`h<&RXO8h7^8rh zkO?G_i54$i2!X3i(`5;?;5-eMn`F)t=VDNTL9oga#wleLJm3NEh^H|k6uPY&z9w|R z|KuiG=aoQK3jd@0eTCN_NreY)sfWU8H`w`)a)(!-yTy<@;RTC*gvTaxQ3t5-uN2OO zvoxlyXY=IYfh-{i8WIr&?JQgH3cvFU9gHh&3=5&gGb01Kmhf+IVD8wFx5a>ZqiKpL zY8?ilX^eOX)C&%QV4s~Uy^DU(>z%j4L#%PjN9~VW_Rr^p1#JD zYeFh-UNZKLb&_2LLcSsBUF4Y+ndJJ~%iU#3a8_pjN`o`3$dhV6{vUNkQ7Wl|w=c0v zFWFHOFn{>+6e;TUwRcv?$|~iK>J?ziOT6CuGU&bh_0`emgZHoA9lQjT-yuJD@F!~s z$i_J=#?2sX!V9iCx+Pxx?hKxH6d3pSpO23Czrl@D>c*WlAX>e%C|?1I$W~burARu0 z-hY>K-R}qPs^EvMIlGk2mUAySix@-rGAhzDIK$vX5i0`ld9VcWK+vL~xAPMDg!c@2 zVLJIT_1!+=hxT!i;>9H0$ARjGr?NW>f|c&E5%d*SnN@E%p2(l(@=4LfSYHv3yhd(m z5K|~;Bjh#X#@%Snjrx`WHx6S%}H%YLPxLdr0Y_MRn#|Q5_TUAFhk|Y#9fL8J6d?JZJtB z{jkJ6r_uZ`Cb=<&XX44*=&uKF58p?x5B86ao2aTYK8xOWAK!h`d+sqLm&WE)OupA# zcBiJX>ahE!TQ0hN)EMv0*1l^#`CTNqHb-JDBO_8>4+dq4!_XP`?0Bg@D^QCMjkppoqOC5+<3S-kJjmU62}lL|q4D&rWYP53x4N%sXA-Wvuqn33AHw-x z&Z&2wbn*O8;x#HaJ-R!~gTKLbzafic2jBe;{<4E( ztxE{(Yh7%jbhV6&a?UbabWQL`>Zo_zd5VR?^hN{vVb>Q!s8dlHutXQ-=_Rbgs5Zoj z-$ST-2%>EhzNt(hU1I=+tGuj$OG~z?vt2-=@;qA$d($?JC^i08s(TF6xyUc0bh)ms zB=`<#yX?ldo)Zj(Q(|NVhMfzZX|TRFiEpD&`VOhW($zb$E!vdm%3v(LpX3WM-!xf} zKDG;A^hgnAWnrkgx;<>2nE>H2QsHNcE<}@Z`f#)xV1x~Bbs}%2~n07SM%{p%y z1IM{yZ_b(bLTqzP9a`9b@5YEL6QZAYvMCBQ)yuom`7C&Qlud$Zo^rdhy!*_W()rVZ z-&bwXWLOM+bJj<}Z~2B_myRox`%tll&GEGz1;=R`w55b+gP7!tDP{+4KMvQM#p2PE z$IpHW`z?S`>K9vo1}xP=Y(!NF2XxLe_t0ERgfdz*Op^!SwjclTytvM{@Zk!&xN#X- zd(M>?*G`1m&EbxjpJe+mCxUB}f(F%bc~HX**70~YNq&0%_@^Idaq?{XH2vY(k3T$r zHhcQ)S^E9s=kX*?cOU;Wo6hK7z8^})_y>oym>1rS>%UD`d-XIR_By6ZA%_c!Zrx{g zUAy!>WY?jhg-mf^Vh~)HHpE@!g^$FZz154`WZ9 za1pLY#A(}Fu8@+A`0Ep(xdCra8>;og&NqxP;D)AdHFu5m#;uK0j^AkNVeBrBx6OOU&8CIJ7coF$wxmw|2#A&Tp*M)Aro6>1+Z zR+I$Gf{E+8o$QQ&-!3?We>=^>Yu-C_x%jGhYf9I8R&R&h{(uu&Gs4m~;KIn2rP`kw zrDAab62}Eq9I{>}sLfetAhjpw@mbn@^FbDJTpkYvze2<4qioQgT*Zi4?+Z!)EA&q6 z#DO?Urnbn=6t}isy2ZRO&ba_+-eOi1s6jb3@L2> zuSzj2u~WQ}#WBgGfm01$LadyO&EHl|%APf4iWHNNV1ib855s%W!9M}!1(X=WF1bkU z357rc>Qx*uunoLYAO%?yGVs!R(yZ|4vZK;7ccpF@cz01*B%KqY+%_>5?*IqE$ha?; zFn)l}-YPrGSL%!4Nl6uzUG4Po`1Hl_`!OE36;R_~gvjLuq_B>f2H}~^G0O+-?}V@J zSytS(>iYal*2A$iRJ44yeIDCJdAT1{nzhyz@s$mo*;@-)J*B@SRF&T5tqSB&d#|5C+IVO)+sb{#WURJ?*0-PW7 z%uA<)Mlm|8#xpS1Y+&|#U{3eI>Z_4Rhuhv5&(U~@6ZisUabeV03*w9#Hb7j1G z9apiT#pAo)bH^@$4kh!5`ZLaiFRVc$I1JS@CP3ma$f~0DA;@8hdNXdP4KG7X)0E_B z*xw5QV~5YfKKef9h`VmGc6qwi(tkD@tUF@Pnmt+JJLXK_WIEE5(K|IXzdf$tk%MCW z?VD3-{V=M-Vwui~Dp42}#e^hgr&40r!qTBI{}_%2^2!-y;04pgR-BLID4THOrJfZ9 z=tWIY_k@LI)2Eh^bChJ$vGZG+=OdK#W?=Fhy{dyM?n}CE&fUp?zs(9U3k@JqlG5Uw zHL*rJ0wL7fHd_6G7O z=uOT{;wxk=`Lwh9IFU1#ujiZUs|lo8iyVsBAPpl%2Sg^=%n?ex0f6Q7N^nFdVN;;Y z=#+bAT!JbmkgGZ6UAudi0MqQ-B?>i2bR9DX7;~neqM0-1=1x3IYI10lzU-&$W;wr( zg$7Wr>_c&Gktb06ib-vksq7yJaJE9Yw68f^LKi2j3z;y~qSj=D*6nHI#3QV1>0GvE zAXO){8p-772wr>}Z9G3I_Ud%a+e;>LwrR3{5#yF?+Qq}2FgIh+c1 zH$qBP6@MhJ6UvD<0L0TNFx-puB8K85|2g)Os*}k^O_)~G$*tQn@CeSZ5p3D-Y<7f; z0zS8%Q-a2-qRf*hi!&34%fI%Rk1p$*R#K~Dfd5n>1?2nd8>-MIXR~+b6&H?d=QpO9 z)d4Y(XU6M3m_7MlDbKgM1_t<0UvA|5?^_h=I8crc%N&iB_}<0OMPp1@XechCu3ifoM-Q>2cM8S4h~ z-?yq?>=z|XoIL^di0rQF>Uwomb+=xSk3V1k*X&)M(z2nmn~auizRhVpC*K~DbVp}@ zj;=;8$eZeLtn<5FOa6TI>Kn4$QSuXQs*+^%o)*<%4{)TV$$m82*43WG@wRKbn#M87 z_lK%(Nm7dOIibD zc}KD;?QkfDhjb0T+f^;R28^ST7^-Tfr0F(*HKk1>-?qmCc263z6huanwzr>Km_DHV ziP1A9{O<<}Qz(B;icY<{DYumXR?wR+FS04wBR`6K1K*13PIh9AvgezwX{-G*sqbhz zHJ)zDjDD6d89h*VF4G)XB0#U@yW^DHlr62xr0CyC$Q)Y^HHH5-Nkb)YI3n=5Desda z&%Uki7!QF-W%YB_!1(Ozj}QDC@QG&eC-L+hO;C<7R87;QrP-9>dQ*WAa*)dsdLvV& zgu(N#9L1q(VvgjdC+l|e8%^8M#6z+Ey<*+e>|>o*KU76VYaap}HwL9mKcS=r?E9*u zNTmdja+2-e><>cF*C^txq_Khh&; z<$wSDHh%NN+c!Vny#IdA_{RXbM#fZXpF)7-X4g6Jsqd`RjVt0uumP&IMzp-o>#Agi zD5>pV={+@$$)1{k272o1#O5Ovggx9RH77M*k_FBfCh%)ghe5myCcGsrlBOZwb6cj@ zRm$}(RCAqh&furXTe?pUbHMaV35;1aZ9Nr&I%7j?g(SzvFGB(1M>UM^X^rxk6F{OG zckRAF+0{wh?&zN4P+am!fure^q(zs}_>i=_2D`n>o7U{2o4o2FN!M+k`I88xpQrEg zO`X*J%Ux2_OualeOM7s4+{-cC<#8G}Rad7puB)mYm?h^H=m9<5Ls`TrmT?cy+=S{7 z{J<6iPGq1ai&k&B&U%D`UQ@h7B#YQ2p8slrc8@waQV<0o>iWa(YEYYDlgn`{0fMk=Rp%W7e2T`zQBhD6@@Q>NR<_;~5S}0VL zz5p!r8Qa|qwV4d@YC^XGo$6sYh# zKG<%f1M)|okc5Vwp-$W81iWdu1$Jb zn7ur5kc+7>13w?tT+9~yaQ{Ejd%LSFuHzFEPGX%qRwGR`N)D)eVro5aY2h8iTFLSA zf?QXO{aFRfKeju}GawVC`$KzV0L_Ioy@2?!Jv8&LzS?vsbHD{kQ`L80Fdi=+rMb)pXW@!>UW3mz(7U=ZOq-2!0FjH}1vfY4OM)pMtf?XFrbzWF{QrT63kWQXv*u zbg3BR3y%tq&vB<0IWIJ%`xA!53HQ+iUw{yE^0u31wIwT0K`$+{6`rHs@R;&CubZ<8 zjD%qkKYwqmhyMIaqr;kio#ddpb`>lPs0)enO>^@st>B~55eR~Xm= zW6Uu)4CvWMA~8lH5Sthf=M=#8G|z||k}R_$Nuld1$LHC%mSb$5Sh_(qh!tfB)s?-L=_IrVt+0 zbt*qY8k}$SggMe`3@gZAc1hDSWpS7H58!mkzb(ks=^$|^jt(69f{6*Fgku_ylSV0C zN#3zE5p@=Suk;86{j#_A>)jz5r%4ZFEM2Zb1HlqZ zFg4`L)1>Cix3VZqSqg+hKghFC1^6%YgMSGw*qcC7nN3SoW4+*h?nhpdgBecb`iUZ5 zDFR71^WwiYXn>=-jvP?dh-@2P{^LGG@>BUJ%{Yn*SXqh39k2IO(*{w1n9sgIjB-#9 z%;{+~Og4RjMf|r}lMs zs|c>qP$P8Sr$wnOwX*zHa4b_AS95z~eGaOYLAofMzxEJQEK%0-Iwh80b5&r*WUy>? z#E7-wn(6&{sGFRCV@1JWX2S2;6*bfz-}!@l%+R7l>d#k_++xg|)J6vlB>eX}yt?(!Z(gj7QDR z#=a!$U`*9lwro(okk{S35s7LnD=RHuc4NLp@D^c?=|TJHlzq%W2x45y8NBjGDr$H^ z;N?Vb=wQ3A=6&uk!W_1`)3E`z4*cYM;3l^Yl(> zERN6~HEtLyWtH&(rKzacF>Q1K4m~gnc>EySg^Y6U*~8lttq(xfUS9;DeDJ~|vpx4zMI=vtZGc!|h1lS7>PY0y&_*#+Jc zzxZHH%1#80$-HBL(j6WNu+pYohGD9r-x$be32~jRk)>JeOj9wDRlbj=gznz~V(Ny)E$5SPqv&c>BCx9NVzuW-Wb zFtE3^2&vKQS8+^lYlmtiW@lq_Yo9=GGST;w&hmx{J0D6L3<37>hXL`FlMk4?D&4|p z8ACphgnC#CGrxRF_6{BdErEp?IHp)hpf08ZWLO@T2xL2HL_H&TSxEK#@izF=n!r6b zKbBU-C#>otUtr>bZ4!|)p2ej^B&=c1F^?zXtUd}4^3i}lkCK(c+gh|!=`2b(rkw<8ySlcU;CGM{@d2?RdR83q1G@TnQ1 z!XfjuY9&?eMz zwyA=WqX$I3Q#eWE5sUMcOF*Set~<0JxcagJu4DsqJ2<4-*P7h@MG`m9EpyMGqiz;y zX?A~GV5C4+qDZpKY7SZo_svsM&8Gj58?=pfLNVGw``B0KLL|W;*Gd;Oj_oecXAmmJ zYOg@FT;jO>3nbS^OMb}$UCf(3Ddt#b+5b@cOv@ARph#o3-`cAA&U%v*21_5^nRUfU6|5$h-r9Kk=kf(!gZgcv z97Dvam^4h0@7K!4p{tF%h3F^G0`0r^?Owg3-&r_9*MPD%?}YVwnwXni8>Y3$t)*!T zFYp7C5$IS>CtY7xa;|r5xjakkxIIW`f^PlMz2$h?Gtby{HFy@o4L1N*JmDzxZQv@D zI{0fBXP!~YMrGoI?3mLsqKBy+v?DoQq_D3O(XZX`D%bLtv1a0r1<@}>yXAu(BpojK zm{V2_Jj*v<-30ukxfK0C7=QEJNr3``TKEp&MhWHlQI`aEtSdJ7VvR*GN8@zxV)ARI zrYF`y^sLzfSZvLofA!XDE0cDgp{udKksWmJPQKk*{mOeM>5UPcE7a##cLn}oP1yC3 zx$QpXjG}&bR3TE^muDHtG^Zm?eTEiy+d)1`XGi!7{WMIb5CMLq@yMnL?3c>~i+g#A zxRQ&-0%mUi*=UpB8s#`!2rqSEeqfwF${L20ywl`_xsIz_sq{Q#9EuEfjq! z72MZ(430I@XjfwXG-xpld)Zx-GlwdWx!vdOToBro0rMZdfQVRHrMe;QMrgh%z}rWr z6neeq$O6bBIham#!(!?qY}kxb-O0`xr|%MeCjgA_PVwk(&(g|jrC+gZt*NB|#(JBAB5W;JvF`UHN1?htV5Q6K%3t z@J1gazu99ViO*MXfTZ1yIDU6VOd^%th_nv=W5k0Jx>L&Cf31RfJW7doRl#OdZzRp`X>3`wXI!|46ev-*yk&)gKzkeMyfG!xvpq z>h^WKt=1N*_otV;%WeDub`lXVk#>XgJMT8Fv#4;p2U|5ls z&8DUa`1<7_w=j9nY(R16=(aG;h!W3xt>#{r6-VLJx8m~YkNB{i0H zBID&X&(82fRP1gjeLUV*xyfnWWLov;*NfwO_#Nlru3SxBG`)!$O+C96hFNQkE zE!zg8^WkRpAoGA7?chDNfDVo-MP#R{T1| zl>#XqdUhQ6R&UI|AIP1TQm29YizJs#K)s1AGW@r(SB|tSg%zpZ4{jMbH zV=Y-++Mls zd^hu6jNSX&#|8ss4Tm#RQI$rrj+n=P5f%-ObFP@HGKx?B!)=$RS0&&KCasXn#cpbU zuIww1(VEL{GSeH1s^Y+SADd`0IH)y(n-0w2x^wLgtSEnICg@FJcP|L7prs2du|I5; zR}g*FCv7VnHHR-VDil?R-qG)M{Ffz@Z8NxZ8cGaXqXTL*vcx#ArrE%rXV7+7vVPtt zKhK_acXNN7U4IjAAIWx^u{N&f1r8j$!Uz-!I`O)nYH0Nf>_X4*1? z8G27#n6bh3q7lTU92vAz=ndjqYPNX#qLn;0pa5c~rLPP}S%*fVf(UM5v&x;vtj+C!T-V)T1!nE=>Sbo-ana1I|g(+&hSvsd4qZz6ofWP$nN5%at1cknr8OFR|gDvPeg5 z(kd~f?(kBT5bN;zT)1LHu7aG@=?i67&0*D%VMmni@8iSaHkVN5fd`zF1z^C^LGkuC zp+hb`*0FZVpmJb9!e%q3%*b1g9NHVQMJS`nLcpq@o9ic9F|=4h!Q5~1eBkl7hsn># zS7kaVjaxmMMv(Lm<67R-AB&(Lo1`SlOs{MojPCnTX9hWC4DH7?5V5B@C;MfVOpmYc zS0=C!23yS}YqXT*2Tz?7&$XY)tovSZ^HKYmLDj|?${T7|H)XYR5~fs@*jdk>;3_K`BA{HEeY(Lp zMUHUXzdE=5F55a5zC^3!j2OZ{--5DC@d0u6`FL<3#&{s?YM;=-C%y&hga%wNvhjKS z-km#8&c)bF7d_~o=$Q|eEw94GZhrP9(y7M68;Pt7D9SW@Fg#kNl&@8Q8|iQZV=c4z zFs$_u#LE==gf8Tf{X)KxBU*|h!sCPxOoMRVC=XZ<>xJFQ(0Zgjl@BIQbkAZAuLCsj z+Mo^E4t5MnZ@+ZURx3X z=vOsW(ax@fgkWSK!Qg-P%I6{goblBJs0voc!zpyK-b4^6g$a^yKfd!&^Kj-Gu=ngN zj~_JPG_RvTe4ay~H`hR(8TziVu`*dzsNqq&X@Pk_%eXoHm{XW#hO?|vw6;`8{IScj z%J175>B<(MNP~pV@G$0d6`ct1pk(FTLC=G(V4$i)vu=d)0+mGIfE=J!QeEeFFk8!Q zA#Gg#r8=rN`1_B($_mdZE_rxDYPI8AC?}`+T?3L>@jKr$J4-Biu?c@SR;7~Cd@O?; zmGD{(*F3FgC2tDe;JxY381ht>c^qBhs3yZb1_o=NjsS$D82QzLf#KZr$1y3o1Qvo| zc%_3F6QcZ3TG_4`*Po0Mp@uW-0i%)6lQlo0T}!&I`wd1LsbbGKN!_hT)R zO-mXWeioBqa2$;VQ>ZhyVz)G%WNMMfOe{^9(L!!k76=@PESlACMdL6J&`EWZ&}SBg z3@}#R6jar;ZZyKZC>zD$6?hjVz;~<&!l;>sk6Xq1$4|n*8P_F#-6rn20W6G3u_H780jetuxHNPCJy1Zc?q zG4*Wxlq0nvcpYEU~!&hA4@+3fesw| zOZ9a}Z>mNyT!RsUw@M>K2m*W>-e_ze1ek*$P;VB3Z8DB-Bnwe`ucbo+o7e>3-|JBL z2T~9S@~_6WiFKDuSb|H2Iq06raD%4d&Odxy zwZ@QrRhU5tUe+B`uz=Hnedh2P>@+*cx~Gm5KBtH2zpz@~@_K$E%|e8cMmbk$LZ*h--p5T#Qr5D0`#@6(#Kp}v670YvRcrhG2v}|(JKcHBL zE>lf4n$L=mD_6rcRCM-_-%HUrLzWJCi^1+yuT}mt^i*^2vs_nw7v?n&3UNZY|g1#ghAt8pQnl-FZ1l}#Qc8GS=DS$ z{(T-xp`qN~t%|eBzMY0E^P=YRMV%33b+xKO^mulhb%PqxC={n_xh{Ineel9_**C1a zu&T3Y?KOup`&#|9;)O5A_nAZ%cpl%J%$MC^9zpGkUq&xv^!GrS_ZS?3&3plmOc61; zZ~xYtTS-`Vu1V@jQK^O<;S5B@LpTsXy}4@S;_3hatlKl<67aGnPxu_oE4~aX03E5? zD6KL?=X!%W{pf8j0-8SIiZj>qf$oj66vOa^($L;2W>s9iGjcFZmX%#VK__aNn z>&UjuQXYq(h+NRJdNRY7tsQWbCnC5pCPt8AI^r1NTx*pcfKsg8#3Pp7&PpI_Ws8AF zs-r|sn_Ud5EEm+f6olmRawNaFM>yYt3=k^lRbkpK0TAZ%#*;%bBs|ihXuAQtv)tgC zaJNn7N+zjhsK^Q23B~Y9F)aMTI)#pj?Kz3}m z`_&m4ufnC~jDhy7voH}-l)MDmV6sbdp=|Mw(aWuLZWR)X19lU?`P`iugO9?}_Xjxh zg`Kb`XvND)M9Z`rU5Eeg=rlz%bN=4AWiw&u%km6j3OtLMgJ80sf>0C8o_lwrmZP!5(mE6^v!iOf_`@4k% zzvUizQ?>g;k;?WBQ3P=gdb|m{phLp#O0j`yyF=rs7z8^rZ2RPPF9}`z4$UIgQ_5lU z5IuxjM>#Sc1l{%<8SxB-&3{g$v5{yEhV7X`_&DPQn{tMM&(Ug$tHLZ4Y69-W!QN&d zd|-5f&6j_5lAzR z+4v|gBkiq$FEs3r5l)A|{XqQ2Tt$?<)gY+E-Q8tU6Q2gzt1_PxA&%4sJ1e&DbL&_S z_L6G@J4{unR6UFHu@%BC*Jp29&-KXl|3H*yZy{^WjmQ?|EZS0r17m{&i+uS)hjJ%3 z);TM4cJy+WT2UlACb(IpZXb@)1og#b%u5Q1a>A3k|^w8uu^5xY}#4fe5#M7YTQ<|U$YC5l6f?TEA?BXt#DmAMD_;J)DP z_JBpIg-4E9J9i+0aQOQ`V;7kIvEUTe5!rLlZLG+5k!mQ5$nlN>T6N3h&b5NzT7Ll* z5^h;ao=^1))ODk|{*G|zGZDx$e(U*Z3RDjj*aLMf*G7$S!A$pDaWsQK zIFS2Yw0wH}jEro>-__U9n1ZTjjPLopfxtE$+SfsK5oD3M(c2ye*JWoA7wz>67xr8O zu0Zwz_a^?r+&+ch?{FTn#Puz79W)!iha1^(>MiZ@&rR>tyN#8qL@SXtiE+(LSCLqa zBZW*7`h~`<=$Zp{zxj^8rv|i#C8G*dkzdK2KN{1d8SdcIgk`}>L1vGS1Rd;C%cLYc z<8rQUiXf~Rd0+?Fxj*2{vy-By4b`~riK2h(Bs8aHBUoNgPfl0S7Yu!&ZULQhyJa+{oz_7{X|e&BQKMoa8@oJX>Aw<~>01U(pd zf`aUxs#R5%30m@vaklcf_UZnbbD6Gh#qH?t>s#-1W82OBnl#Tj$onFP&Chw(nI5`q zIoVVgSc2@kbAM4EhOLykgk-8`L0bd*am}6*Y2v3My`okjeZ)Y@pQu%J%vuN}CbJEau-pvRa>kn=4of@x1i?Ms*U#p%@%YFRl$93}hQ#t?G1+XeQRc$IGX#% z4qdz{LX8=w39L(>`E%Dq(NUu(#UJy!`!dPws#_xyORm zs;{%|)p^I6Na>O5CO_P6lYe<5f1rSqJrE&WZ!;v^M?LkaCsFJNtiT_?%c`)YhEedQ zuqKks`7-9HrCxeKn1@{Q`Dly=d;{|&>u-$HnZ0&cMpS<@cgX^2ar2?MXD3>cl_p=Y z>eo_*rWiVcjxJ~k2X@zy$%AO7cRo#C?i}r$!sS{71zIOG|Hzi4(ZO6z#!6H7D7wmr z2*dY^amQN@9v@1T2aHY2t=b^UMbVlbTZ&iOH~%fDRE3w*s}tZ8ssEH!j>+ugI!#0jl5WqfMKaOM45Y4fdNLjbp7N zQ65IOKTrSXm!VzxB~v5_0KghN007?q13HaOot*6*ZU4c}X?0usO*Vv|8hyb$d=kKh z6f|5gjIlT(StepzB$f$11B@V=c}Vnh6-lZ}^rPNe2`LoPP0AFbv#0(R_pU?U+3xw; zx##82U2=R2!8DRYP06$ZYN;WV?#jo57@3_S@P2CNsmtiRRyU|_PWNx*i5rLy2@>-% z68NHnXRN07N;`JMH+|ZAQJHe)_O&sr1y2Y2hJ5D*}>g3P?$c z!44#n%~EmbLFMwkQDppu&@*FAr?utbVFyc^cg}}C=xMUDoR(6~FeiP=3&S>m0C>3} zovR|-_ev$Qx*;58unP{Gspv;yUeb{D66bQUw`f7|vQ ziG{CA6=l_v1idwG3)MQHZ+NCao2bNIE?OQWr-$&M=YI3Hw{M&0#$T-mXUvVC!1}Lp!1I8T;D{5k0wd0;j@tmOFJW2`o2_j}q#jIL zU0$QC3P5!xBUk{Xp11M92ijA1;FwxJqYB1m(LiRi;6 z76R1}xuHu&a!VwRaWh*&rga8s4>@ebwwj8nYoyx%;I}B7xNlH-InU+Pt>BUt+5$Fc zrl?%S+cY2ONv#2+W}SboDe&yhTN&EO@?Gw;mOqznF}Q^0Bkkhlg}=by>h72*{1w;o zFp0RMz#$Do_n-F%E-Dx7xI^xRFQCzzz%TOw|Jdp}hopHvz5L9XilOW7n-&^94(t1y zs(XkBy3)ObWevN&%yUKNCb=G&nAmVDP=h@zjP$y&YCijjV#!j78v@t0WpLK@SGl}; z=gLRO{`fB^*@N<6&&0t{MTowjO$~fFdNpI(urD4Yd`*vi7erNi84vvOj>`|bLNKP@ zW};1)(yo@co=0=KJM9#B3d|$f{a;-_c>kQY4>|eAh#%Pv&+nIA|NUMRZVByPabJU~ zV2(HN|J>JTmMKIlg8~55ApXDm8Y@Fr!+#RCtg-#S66X7=FIWVh0F?gcfdK`Kr^#ty z#yS(MTHA&J#y@2S5nFSKVj^7o$ahzEO(L_qCIoN`CC~GIBSx_Ai7b z+@K~%`GGZ@qfCxDO_ZU#oOmF)2~|V(5qmw+Y2hO?Q>=fNzfKWJ04)j8W*&}WA6sC* zRs<|$fJ;6Uq@chX8L|>$N{JBTuxJK6SV{^bD!G?xcZKfABKCkIQ>zu*#z@7Uq)Is@ zrIy)kmTOyyXw8t>%n>X_?<1Quaog*-w1glN=)83faVY2IIm|HGA>>%s0=9pE0w^l4 z2J|}eK{-&m8t=9ukn%pXAofITD-T`o}((eZu+WhGy#}cDV)}np_8I7F8-L(`m%1#9wu*2x|L);LjmLD{gVEW%n2w9w5deP$Y9iTfPv<+=jgZ~i~4+1dipe@ z*=2An)tk!Ki4`f}C`QcxTFM+bBA~S zhIhA^FiYa8{}B_9_HyfKbMcF{D1UE}vFe8`(fD|7E1_@0!`J7I?~Y+MYxC};eqM6U zZkQAl-^A{*Q>p=QUVUUu(u^+~H#$d_J-ysEp?gkCyfg2wPdcu2n}eX6(sl*57y{9c zZcovZZRkI*;Y1popScg88Pb@YB9b;>EalRUluOy2c$GS+)1~X2_C8}wU;dzTFGDL{ zb^2giw9X*?@NTE+Y-WEQ?wAp~=D*OQv4-24<=UFfea7t@ah$>&WM}*W zpK2+N30`@KXrKvXaa^5A)$4=rPvz}|XL0Qy1F(nOE$J#QOIbW58Oo#SfY+&-&{iS# z1IJDgqfiQ5l!JAfzb{#m*~gnOTI(&RL{ln<_YV-RC<5uyaQ*r3H zr(k{gIrOjgaKkaLp32JC4vONc2cy=7*15DnFl+YeMKPkvahF*C%iGF1D;9o8$$aQ{ zyw@8iUjOdhM&{n?eJg!dEW}y{UxhjfQ;=6dCKmE3vSL}4!h2Cibs}mBtRXui-dd~L zM{XSEPK#4O+j{(_%2u(+uuMGjM^emKwghgmGz$zVolPGzK^i`c<`^!ixw#1O?NwSK|sV@yce zZPh+@-D2z==q}UnkTgGLICtAG!nSpMe;B{WkQLBE5>b*8(?O8y<%1Y!66nZXTBJTeuk)5J6`B!eBKjjQHI8w*ih z2PJB0&RWkj*}B>3N;De`G*}k;w+0-Fhr%e{2$h<`0jvGWtCV1yfa@X_>&$FAmE)uh z0Q}4Z2cwldy$3Qta}zYijRdzadK1@1$-Y0GK6CJWbMf)!>iC57gjnnAS6Vl4UJ!0> zW?aC2z~-bL4QRQ-U3$i^qW8zx8y=}jk)@ieUlpBN?Cq)={rJ5T`*=->w>8R5nbP?R zdkBTv-!W7jD~~Y%D@me{`Umr1*JXGNec>7MS9KSfP6EjwJjhj{L9hd;465&?a5Z<) zC^=KQU)Wi`x1*KgFH3B|cU+!^tcgpL#w}T~sX*eGBLOQxv_@seAXhWB3+T=S*}MTZ zK4_BJh2$Q!wr?Y_8%%DAdO}3)E;@xen&H~Ud&k+0I|Evc9{Kr8IY$h;AEeS@_dE($ zOxS35Of<34q(W6n;dYb+A0OergAnW)!c>dYmiZf{^AXt&7?l^_VdOc#sh3ZBS14MEgvg}{z9f1RS$jcHwFqe-WAmwSi`W@g945r zP#q8y$Uennw0KvJiJ#2jjvlYfoWLu#Cw~!>$O5}=+FK^URu@`}5Io6+tQt<@oGxQp zUvv%U5x;`W+0?6S->*`J9WGheBvkgbh0kcouB7Xq165si^_rRUz;L}5%qxj3_Xfyp zV^>$mQc(hynIsBL?=3!^*fMZl8tBEX>kLI}w@jw|Em~>)J!6dYC!1flP}W`;c~m-q ztDO%`61DFLSrZkQS^J`SS*uH}$$(lp$Z}dRcF!AM}5wJdAuk>o!0DfT(}( z68FDPdA9Z@&j04Te~;2dso!dg0j2Ab8t=#eyNe9=$;d)t-3~j^q%)4UDaa`4`BAHy z7E)3!Bjv}FWO74Qq9Tyyyn8;%%nPVBQ+^k1)h1Nuu)rz~dxc4b)GNt(b^oA>gOt1u zO(GvgVJ0{~1hQt_ z%Or>7&@&IKg}Dl1+uBR#n@uh8x)*VJ%^2=S`(ABo8uSn>S;gYivx3pDz0IS@s@AD< z1L8U*s1B`V_~p|~m7ZRGveN3in8aXIT5s0DI@m}hI{d&zKy|e6H!rJeK=$B={3Z%+ zOmePP^SbG8UIaqJWqC_W9-E%x$3|Qg39@GM&lf76$W75W0hV#TB zNY6B3g4)OfvqsjS)}N=7wtVq$s_BS9*!6moTPiS?Yzt?`iII+!A6}JhiJ}G-mr!r| ze{tIdg2UB|G!0W_Zj`ubUHP?l}L-nvXF5Q-;A&d`;xZ0RW~; z0RZs-`<4H(HaE7nGqe2HS@-vv_uFl&CBFBvR^a-@p;dFfA@Rwh!w$=rbiVQ6&4#p{ z&vZAVb4aSH?I`6)YD4+Cch?JmKpH!ZE}!YTs|kPQJS(R)iftu zLvNBrpEkd-%%q8jLj&bqNv1T?rJ3%?nJVF!ik=G5R8vn>HNl*eJ^j>@>hwvVHT;-J zt5h{>irNlYT$M$>up!9>`#Vg#s^Ef2*6iaN8{-j{2kYMcZ~E3jF8GCu(s;qdW7876 zf;c zzfE?L!=oXMI#VEO8hL|Fk2X=hVa&(h9>=g3;O}=SJFV}9uY$taMtpg>Svfs<{j9F+ zpSzQ*qtMk`XKC!jKQ1nevyGyThG(8G_gQ#dbJJ{vAN!JEPr4#b%%>puRZx(>A(cd$ zWU7v|*lE3$Py}7I;56Y`K*Te(e@sb8~ul|9)IOk@k9Ln?Jz#{RK-GEndp&jYoW-p?Q_~g zJb%2^Wo)H-dTlNdsg$g~MOp68ggD8}ywuNNEsqHoP%am4R3}A8&L+Be3($ zn7VRZiW~BKQv%e8NyMVJMZv4_$OHo<4xr4W{JEPJ6_^B54S?SP4>gRxG+Bby5nlRQ1|9Sr%9ScdZ{c@kN3* z%cmJJv8t+oC3^tsiRQ&w65FC;ts)Sq&YWhfPBhYjOTTDdbai8)b44ecZM9Bpp2qZm zIQ3D1F4NQsjX=!R8h#49`o*sMk^>xkk-fGjdmzOJ8tMI?`BdvA`}3?t)QV-L$^1FD zc9KfJ!S9}z8?di6aU29By5B+o8FtDQLhLDzv=5wej~6LWFA8?Pi=SKG9G!uC+J(bJ zV`2m=SN_dDOS)k#YBr)72Nz~JpxgU>mp`X#yGO5+Ui$Rsk=B3bi@Ul{{IHJM5-u+| zP3#zD1ox=17a#f!+-5DG;|uCNJDEA7(!x5WNwlGTsH6!$1e|7lj%}z0;Qn$W$JFJe zyQ%>FPR6oM>)V1Ck^Gn{noU_v`@=G0mUu-#Dll|5Z}pPLj28ZB+GMH%@a$VQDFsRF zlu%#8ZAi&PvRDKr#2sYl>@7@f3c)1Yj^vU;Jzw}^u~uB zJm%4M3i2+A&3A%{6I(=<-gzc$2hO=n4 zm_=+~Zx_l~MHnfKBwwoO_@8!MsL1?W=gmJP z0hwhe)J<3xpX#YfAlqj8cYSN6@I%R4TSuZaep%K~{l|S~6aqDgUb+#S5OaDO3|V?= z1bB0MOtIte35rp5XasK5^%Ijp-uZe4Sm6j{SUk~(B%OasWI&p#Qw?KXBFlK)E2sLv z{la97k0PMX5|a#c`gx3zv(AUD$>@oT!~t~+rM5@}lHN^|bR|sCi|K|F@5<1j6atBI z^4$}qV6goAO4qROeVGlS)DU{}fF>TMI z!*f1r^9PqBU~po2kBj2`J+)|&Y=E4mk|b+p#jGyvSat08X`=O zEM`#rG@%3EuQ6^jPYlq+ThO^<*d)}0^%Qoc;3-2#lMb|>;ruAl$U8=j+c>t$&~WO_ zo*_2o`8h{2M^Q)Xx){n*VLWxqK*-<8!~vb8=0OnA-`c46whHhH)?rAnsdH`p3vj9~ z*^cb`-pRSk;>RGq z2GDA*@P}69K^G5y#@leUuYNupHnzWXJ^2*~7Yvya*{b7}M;5Db5-xW$Y`jXpTA1!t zU95;RXzR4kcEBckERmE!BKELc%KGGHyH5RZ^~)aZp0 zMhzcJN7R8cK0qs&s#7l$i~u0YC-72dIc%)MF8UtPS#Lv@EUkA=ASDm3+j=BoA>p#qiEgL$UrP$5b{4?*8TCH&w(n216<}RcSMUH%? zG*%bKF@AE+l|sJ<3jxPRXp=49A3_$rDu(N38{nxX?1lm0%EJ@1BRST~WnWMKmyFDw z2xOFU989t-4{(7n*AB74-StEnKCRfFsTAhE_3oClZ|`0}()%99i>|Y zX%plR;#u%Wb|@Zt_<<&^0PcN5JivVp+2hDQ^$*4CsZF=kv3O4Yl}i(A!{3ef!G}H- zftq8&{l|>4XFXT4U+t*@mkZaIpNkM};j5HFiN;S~`%CqQmY3GR+QKIw5bLl0kh|XO zz}D%8-@5T~HXCy1HK(`6;R`5rrv?~j=gK%}O#=z!6oz)W16GXp3ABDQQw$jRE@SUF z#2T`PO3Z_|$NUkFA7|_%pD~|8FKDNSb}87fnOlZbn?3OgO7iQTN3Zq((~HZQ1Tak; zu$+x4&ObUJCoX*AHasAgfZQosfdjtlb_GLhCiWiN!fRNNxt69wsF{i;`7j~)h*)nL z@AufW@osW>rYe!TCmhXunUu!~f4>gVIoCBST{5^>h(sqCE~1zifxR2S@)dO_VC@Xx z1#l!nL5)I$I;99q`>NnT@yRSk7|IO~n5cN~7>M-A>QNl)1vC@sgSv*9VE_Pc`&3MX zVuq$onR-PA5%D|$^68TeZF=|w0W|jDaVv^6cwzv&PL;ai8c8M;RsiuMOmDI+Tp(qc zC?QE|Ko)9YcxiVfDd{S$RPp#dShV$%_6z##j#ZOu2fEtaRrF5S4IK4@9wU!xC3$?j zo{m$0?~BB9iB~nXDhE$?oY13Th#N4w7kjX->=6Gh{q(vDb#alq&k;k9mnwv4atZ;w ztbZyu5$_rY!Sa+QsABvc=jaZxJM^jEvSWa(pmmXBWkH3vx90{!7#&nl+?B`YZFYjp;f{!(Hn! z7k^Yl;t*?HB(Ydb-;$=4u_@zaJwxd@7RQl>2a4l0qyUQsX6t$rw#D@wSI(QSL#>E3 zTi5gTSYxj7)_5qlbC_mq9`*^2f^HiSNY-cL?GXCAK(U`B*Ic^zDb}R;I&2}uOm(`} zS3QSWy4cn;T4svK0whxndkt%}^ts9T^=y7BzeRgC3uTQ<;2VGu(&^Zuz<}qy+TOUi z3OCEL^EM^RuDpP(rX0jpZr~b%dE-vHbWT%YH#gzzL9t^6j2}hNgsWgl;B8Ai5w5C& zQ(m_+n?56)zb!Ngg{?tVmtPlBrEG?@Zj~O`VCe^(S)z9vUj~JMQI?(Ju3n)N2pHTk zx6F_R<(XI+#`2LQ})Cr5SeR+W14w^RL$PhN(7$=7HNoX=!8t} z6W8LJ(IU{S>{hv9@NU3|XOsXhXVR`|y8-B~jcUzx*yaOzjI5V|34Xe4ver*?<7x{o z;U=(`@19|Jg`WbQhDwXwZT?jr(FWU)6WYNG~ zSAxOXWRR}u-SO2T*0n~gKQ}wjop+_|ws??oqC;j$Ye$h&eXgikpDgiif+hkRnN8q1 z9<%9M1-t>oG^!gB3D1&`cJ$O1gJ0f3fvn3!-n7@9;0P*2nxUUBW!qRm;WT6lw+Gce zRZBXF$HfH}I~5RAe~I*tt6T;^Y8;;mMU&&3f2&VkL>!~qki=$o7IYuC=-v%< z3lLy1b=3&st5mYsoUfo4m|*zQtYfKBq{`F_gv%j33d-{+l~QT3qd)_%7A zWKjAQ(FDZzEyWLfS-EcQKeJ3jrIH(e&awcnovk(gbSjY{*`_z_9(4w02dlbC$$D`B zGT-EYc7(GZonh{=!U(ICK;7jA+M72l2p&`EKWJd#v~jJ|po~>A!G{B4@6t5fAkGM# zETqwv&&bG#?ATtxHW39o97!^QBFd1!x!_Ou)}g9`GJjGF3odNwXae68e3{cx^`|ul zTt9l={|);4ll#MM>i2+Of47lvu~FDZrPBWpH`XM&kL8=0?fMF= zf>C<*+KE1!^)TnoIQutgD`I{6dTgKhBm|pDH}d_e2QwG5j|BaB7GT-~V_PE*B}40; zeF2OLOc(OogEAxYgfs?v_DKPiqAVf4Cz_Bhj&}I02*B@WR7Z9xQ{hV@neLr!B$93_ zyv#|UaJ*2;Wz&YE$HcgQx&`#7b%!Z~-K0`feR)@pYe`N)=qW+Od_M#Sq_Hq~fIU6y z4>QS;h3Nep3w>W}K6-KTS}Z>ML9ZKvMbGovD&JV6} zg0ox{3%s2qA{9YBVy*Y>kf1oSqqeQ&ee=Jh7B zZdv-tOG59F=rQYzj0sjN41NMti5QiN36zE0($!uK4p!{Nw0(QP8BKcfz_ zw0#^kD-YP=*-5sD5?ZCqu<4LsHmLFg zl?bs|V0J!oF==zqGVaqjo!BqCWvhhUaT~8WdxJRw`P)Spt!k|`sG1=aAPH%-PkXz2DO@A2EoKpTZbsGhoVXf2#20eR@!OXpyJ?wt0Ong{g^Dt20$QE0|$~%i=mnh_%&`p$n|Y!qG3!Zx}(O%ziR_IfMQHc3WkH}2VGddh+)}KisbhWC+O6uP6Br7FF z2;f_T{A4Ln%BJ~v-zZ#dkC$g5`WHAfQ1OGzt~NodJ&vl~MVG9jH?hyU*po{Zoe~JjTqBw_CPxK#jjG~!@x-rNJeI#;(Y*;y%$!!uj*U~GW!C11VuPsa) z>a?b-o2+VV4IBa5&4=@Jre)M3IX%9o;Q{JsuT6FI=SQ9410>Nam!Q@-3u=QjlD0`_ zmPAzQJm$DWGb5x_Dfl~V;Y8WTfz^RNN%cu0U$srG=)LtE^_OWJ0$5%ftjGw>x*k*4 zT@;TnplWiRb#SwPYXnPOqhn70!ZmTdrd;;nIVB^B=j@1uK2CG4s;(IRzEZdTFTKqeo4MJHX3o&T)<2JF(=h`8+ns%w*RC5 z9`7T`zpiB-aVZHk{d)?|hP{>vR!>2r)a}e5I&>Lg)&3!UE@5G3ZT~JvU-8H2tze9t zIbV$hqu{{*3;Df1mS^!)U|-%<4c77bn_*Y+x_HR1uDzq@J!?BHvmDOy^X0xjhZuDz zkY~oBPNCwED_9~$HBpc+pcO}M7q>0NZ}dj{QK8yw1aJQv23f2=j{W)=-QYbP53+{E zjORiIeo91NZsrtZR^DP_t+-V1ZUQ9JN3)yvRP|(I5rPv4!>%0yT;2s+@Ye|}*ofwV z8)8^uL=jws1NZWes<%3&jRDvQpew%@#FLYP{z9Nk8M89F{s^m4AM$#OG2D9==pu#c z3nE;ka1$Oo7yIDn z`Z0RO$0%nl`R6i7WkLjAilx>32elTP-OUm%>LaNz8P$RlRAyL^Oj1*B3g#<6o9Y7CTD?WojNp{^#wN)-(cV= zTQQFE7Spe_l}s$x?T)Kjp_@9oTgp!07d1IpHk463ew{ZA{?!v#iG0EeL2s@J()+hh zwQ%xGGO#^ER2^H@0fI?$n$Sf@&z1ht%6{in_f+tXr-@=+e+@+`b4I7fsRB%^IW{S{ z5dh{b-Q?hog}F4kN2g@dKgs1BLMxfeVNyQPK=Zg7kT|;?f|By<4=_@9p7pB8viOKT zO9d=3d&!MHwuS1+d4|(_m6Wsft36M~-m6>GxX+xn&LxU{yHF<}uyuwMJzrOX3}oDv z3fb&k277T9zGtN&B-j(>fYp2S z+H?x@8e1qjl(~)?crd*V&=}gwz>U*42Y}Jkj92rUzIH$*_6?}byeKN`W_HfMZXbXT zd38tsTd}+nMK$UbCPms6)1kjv`9`@A^)J=?!!Ik}hkM)rH(7uApt!X_{M*=7IIuf5 z)4vKk-y9K*hB^$d);)J(WQN+p>fF?13T^Q<^M&D0JU$i;6N`>mI(dgfUYyWB)w*$lsV{T1P4c9@ zWdGYiF${~1WCA#Yy2dFS*?^Kfp@x!Lh#C2))stjtIF$qRv7fw^q|Q`B!3~Rn>0qB6 zQ@T{sfZrc4j#R~pSL_~gc%W!?V$!5g+6zm6A&6MuN>Qke8b(aNF+SMC@#92&17x%e z&LY|Gvj|<_#8FdSf9rioE~WRr@GQRJOFWqX8P`=Y+oK4Sp|=v zbiAwjJh~~<=mQ0YZMk?QBP_5F{E`~%wW1fJYpL?K0rW+26l_|p4NMJRwyY*g;2+a% ziB;O7C4JHSvd?2SF8r?UF4rIhDM#KlMK%q5Ln@gg6 z-DTa$2WE1NRvZhXrzlRVR>z9|tkZJX#o4`+AS|{yCuVW<6Tj0Su$`RBTzpG}h^R@D z^Hq2}{nw^XVrwLHw~~?J)3rpmev9&b;;cydGhn1mNIG^Vnh*{Og5YM_Ny2Py&Xq#4 z1jKyJIC9oLVjZLr^Gi3U6v1L8>C``>k4o3qPL)uJ)jfS#lH>{mMg{^rY1Cw1<1ETOh zl+6MD-R5hr5#=@fUDecl4*dBZdI?AE9Al!aBz z6{g;@nz#0kDsI=Cu^DS0v>Ti`tx#p@pS4+ZWCuV#zhEI1BDuV<(kZiiOO*}w)V%I~ zD}%r+mnDQCM-F#}pb)5-ojscb>zqTDXNS5P)G$A|(BFG_;`!}fbK;6BbL$36^Uyvj ziq-Q-Uzg@u4iNHR3voc{X|Ti2PrU|yu|N+O6>K$*6dVz&4=Ei085JJ#M&Q>|WtLXd zLRZ=Io1N?!puC&P3y*e0nvilcrnT2|=W_Ah>|Md&V>x)6_5icFjUo`#4NIjKu+aNZ z8d>Y~N-clparb5XJr^W9uefdpT@ZcP*!~ln{T)6gv=J*Pq^)?2WlPB%863>Dz!_++ z2zxV^C!i6CK~#Uf9v)EsxjATlG0YYKj%C1buI2n(-N-#MoVzxq{8(4;DLjQ$nX&oC z#nEW0wHi&~6^hrb&}XejnsTn~W1%^7vQBS&+H@+W+(Wy)snCOV zPIGFJxp*+rK3e5|2u??7XM)uVJ)oXJZHOVPR$i6nTQK)m4#K&=HDT9p z7v&O(R%D|JK8k)AY*x=(L^^&6t^f9;E|xxf^hQ~FNKDPdPCYh8wgu}J{ckY_8?^W6 zWF-hb9Z;uhjZqUZk5$;rme9xWig+%N{FE^u+{$F-T)A}a%rf*Z49)wu@IshDTC!X8 zo{^^f@^*co7omsxjWV+E6c{Yikhh;tuh5_ zP#UsNY*RhS>pK*43%TDd`a|X|U#HSAIGsOCB{*mkJdElqnk&W5$ zY>Ro5M;KJ){~@-|%IOjJ??No=8HVM`I+YT>*|mY=8Nn6X{Iw-<<10U_f`z12%+f%l zT^C_K8>H|fFF)C6DRg~`yX4LQtp_LfR+m^2h5KXUU!14T{S;S}$K_{=H+gM+-<>}#ea!u$ zbZ(effXNFBFNTVsZHfCQ}2d{qQ&FR>`o2t)gjr_PhyL^~$qjUTLaQMTp%5*~g z)aIL-1TGk#p05HVHY#4!v)X6F9k2qnC%1aOaaMGb|{v$w&b#t><$I=#SW{OYGP4WAH3*&N{|4Hrsr64 z!R1ssHOr$CAzStErJA-DT_F8Hle=XoEp!5%^74#PH{xLdk2b1BFYgM2XFEL6L~3Ij zdYsFvz1z1;FDcC`i{KzAywhnt`NY1CAy{G6Y>Rq||w&SR>^ zr8*drt*>I5?>iokw;L8My7OVEU-7Q+SZs3pnf_T^?K18)hdWmj((f@%W@2Tlv2oiD zdlrlrLLAIu)2tUh6eRS}Dfp+Nk1`#-J#Pf(l9Cf;x8S#fht3H{LB7&h^F0k>Y~XL5 zBhK&ZSSHZiUNJ<9ZtlcO9|I1n;I1+l4W=Xvk!i*r&+-X&SZA}g@jNfeY5{eHQZQvW zxbuf=uD7M=Gofamk)%Nm+VIuWFDtE;o47e*bsdCODJPGWoID?0E7z1L4f$tc1=ThC z8iOTvonj;0E@5gSrf;&ub(p&96RXKR$dJw=So9;Amv7-19#%Ss*y)&WA=>?5{cU6& z3+}QRjwsmr40+7>QYp4hGz?g(h|iV-8Zc+3o5UEntre|rscoIEJ5D{djI*gsb>o+y zD$SB??movexQ!SJ>jJvJ4F-jel<29>{#1pShBR$T*W_!*V~jyc(^45k(;JR6ZG(<6 zaNvPhf(mnZDDWpyum=WIhAdAPA7&!HBurv3mcdnYww2J*U&-^MV*5z3OPlv;WO;<} zS#hCi&cHYC{0oq%V9(#)SnG2IF}4vgZZ=3n~w}7X+5CkaaxvAhpgD>W^rIS%TC)9CoS!bvlQ)*V3+x&XyHvh zw}A8|2Ogv@s{s>YaXnmUn1O(%^lG{%yi4kGN)6RJwh)6`mG>pE+fdnc$JV1ws3-^v zAQ`2tci^{3BYsy5d?kdIM_2vE2~bqK!i&GBE6*4%1|!|#hZ`O)x|OYEnIGOfD%g9{ zD#ENq6*@ieQe{$*tG52b|IY8y*xM{?9Mcf{7wX|D`pn-3E-7r)+4VM~uCg z7`STWZ0adpj>+!*6LsGh#wN0hrwr5gs zbL=lr>2q*n20VBH(2z1FwAVv`nBE8!a0~lRs1gO z17OvSE?h`bH*2$+1i9Sf@g{?&ByZ86ttQyv{ACw!5vxD7859-(J3zGtIAJAOy8c{( z_=3AD2l+$TW00s_`kg=3m#AmdBA?_&L3IW_;|={}JgR;8pZ@GOE{AL3@Ly#LdAi|C zwo_v7S6}EquWG2`kicDdf^{Iva433CFn*Q~_0_xwPC%hs@bQ~bXpjJlHvip5sSp#7 z$yj}K3n@l5who>jAaL>lvZw}va)7fp5a}1tDZRrgD&(wu*6Xdb>oiaoEVh=BE>4Rd z#3y==4sVfMDd>ox9qD4IGTG5tb)PxoP5!t5*{PklvPzH9{A@kZv0At&(`&p}|2gok ztDt`L_)~tt8-piJz#2i=!rO?!dNHd3kpJFs#0Y|(0}Pb%w9Zvk7`D9Z_&S(PL|Gb> ziYkM^+mN^HrVliMVXY$qd9|@JTfpHcCmjR1mflD#Q!&kuLO_&NSCLnBA(`-AKI-o2+xD(hpraieoJzs%QYr&f5I z?uOfDIWjt9RcCG;&`0#!)B_X#%Bg$jk+9=EVM-cP-OaP?f#d3E#n@CO>K}rqmw69f z_iM37XOz_@c?(w5C1&4~%@C-sD%5;Xs*RDUF^8(P5MS?30@vj%(Fuxxy(PbS#rR_Wd^@yL|3S<$>)i!hGA|l7U9OC`@6j#fdB5r za{#7J2>E6Bn^^simS}qqXLGy%;E7H1{PM)u6L!C;>Sk2pGm3%ytvEoct zC5fFPrK_AXCl80a_ehR7c|0+5^12i2o>a=j&zvN?dwv~pIk2Q2WK%y%OCLpRA61e( zAtg(v{F;*p^&;4FR#bGx*ip|NlhKmJ8>nj&D5o1A_W1d*fR}pSVE3LxbYDa`YAc=R z(L$JMDyAu?O$jN6lS8pF{LONy`Y`soC&``#UqU{7a%7yg7g%)&D2H5%nKX!#v$|xY-aIu>p3%XxwNG3aQUKsjG>DDN?+uyBKd-dsgm>f!a!t^ic*c*_*58&=#39hyI-D7>^U?T!FQ2 zC_CxHz}|=`mK;KRI+p-yBfnRPr}*S+jwq$+=mHQ8Rpd;_N&*~e58>&44FZS!WK%6*_F)dk+wW zI+{H|={^ltHbyqS*3RtoezEvIKAPxhdvkYkf4(hhc;A0rfV+c8y$wFbn$;e-;prMc z&ms_|bpT@HLcAHji|A6KPCl?@tgANomjgMafzv%!NhSEN_db@$F`h)ca@u@-Y4W z*_%681ks{MKeSaOeT5+2J6`FmO>lQnXj&gsQo2kii9jdNF7dLWf=v9_hc1zP#~QPD zM`CB3H~UYu$>-5&+`t_qh-Ne;rAJqqj^enny4LVd3o3a?s9=q!AmGvNE&yJwMHpEaLukN3G zNo)w4Kulx!2bi!F4G?7Q4<{JhaJ~5fWhcli@MwVIb7fTXNwEe^sq|)4rp%^&H*?{k z&IsSBJjjEc()IY@2?DtAh!f$WMryhv{q&SW+UxW_Sk0pqC!bVnQN?uVBqs;Uu&o-% z55hal0swtnW>jqbZ7`@rfDY=p6n|4`RSWyk43TF`pg(x7I{vueuEBE+#uP?-mlhuw z0t>4RIR~qqLBKYkIeuTCBvCwVsEb_)tNe2*$q465ijsacM8Tjhc>^b0;DNQ);elLP zP4VdP3Io@noAz@=_P|OA(sd07B!V9l6n|lj84=%++e8>dSW_~=cUfe&cQD&O`|nlnV+v0qJy?_t+}15n_5l!ls}q zif9;nY7)wL67`6Ep+ML*9B18@aO4Aep3M2mGQ!`HoRMN!_E8VVlsa)!=^Q{(1+o@t zUhKj-?Mlk&W98(D)YYs86lhBJmh<%Nj9B!Mi28a-(K+lNR03S}kuYn6lMP@*crS#o zO{?Nt$XZ$K+yO$ORCz?2TT0I?zY!8pB{)bFeUNSZGmj4-P`6hVSZ^OK=155mK$Zkg z1w;z|Zn;MRdm?CMynX~~fd+Du*jY3+XkV5hV~DND3?By?wxaIvyt~XrCxN`FBV=At z$~zeh81Okic6Ud{BWF=SB_giIl|S@ys`}HC`ZRlrj3(lccN%fohI_M6-G-&5*%g?p zJ-~F;DMiyG5*i_Zdw6FOV&ag;`d(oVTTX9*eQj+6N}!}PMsfW>TkiIk z0`(SgUX*<(1s#^Ai|A?5O$(fEcSu3_Q3{klfUPj=-LF7}!^s z60IB-G7F3*aMnP6BE82JC*snIMQ0TFZeW_7@SiPaOk4<4H)X-5VQ7B~c@{m+BD}_6 zFOZFV=3eN5g74bdh1bFgX7u5T*N#}K{URbTcE9qQZ;ava|1H%L9K{u?Bf{GZvZaII zJiuat?O`yan(HqyH^D@jH1zMUisVeUC}d9K>c>7>XUt%e*w3j*YijnJ>V3W4!$dLm z)#odUcOVY2Saah(@e42?PU7ixasI5G>u;iHAzz&Lp zI;xpWHN&xflKcz`4W5SrZP{k%SogO}h&?Wi);}E>g&J7yab%j5z$&dM+{YhJX^#@7 zppe16ZV#9gy(b05n}A37f)Wgmw#mTSyeP%O0>2{Ios=dz7P*48DTjx?=?s*Xtune& ziMa(?dnCew2iL!)e)`J&Q=m?~K_h#L_yWl)=GzxUzkUmBr0exrMfbENXPkVv-e$=r zOBo)23=GC0ejzY*ppxmQ_+#+?X6^DK4j|e{WPq+3RIK2x`b8y2k zBX0^lCR`jiU||)X1R?NY)=z_O;mn7fhtaL?c3Uoij76XN-_$4q>K1cL56L|NQ{k{z_-Rhb`IZh<_3zqcf- zl;mLr=79X*wgq77e?UGLmsSAcx&%N#V}m3CTKN4H;OKc7uK1e!_V03$eRG*Z=F;UT z3#`L6N-1?D)#Q|%@MCAFTn>pb+wEYxFIc>hqtrt z`W1Rz_e6qV`iaeH`k9Zy$xRp`Ewo!D8ds44zfJQ#E)+4XP#%R1#D1ve`Jsx85RgOR z^-Fakea#%VF34Coct;1{muuAF{rP$tq_2CYM`ZCM>TlkyF+E#>6YKT zwX57A#sZ;`Z_>Iyd4$kSoVbLV6yP?3H+t}o!JYHCkq*-KU_jIY>uNgYOMn%5WghCuP!oJk``wb<@ z^87c=(;#>%)?&6Yf@O^0oDFy^=*aRJfZ4?eui#@DE#I3|7(C#ma&d9q}!BbN|gMP+weY zh6&FQtS)uA{?#z7gc<&o4Dv8bEW|F+u#-8f#)(;{bjWT$21NQQ>Y>ibT-_HJAZqgA z;mOg;XsGi-4#z=uoB%4Q5di0?{UW#7pZk5Ir<*UHub}}VH{`uAZ6`xlSR(nl){%UN z4v}mVW!1nZjAf>++k^vB8DXF+W&MEJLY4Tb6iCB}C=f%Yi^##j79<$lgd$=KjQr1b zX~tt#;OYn$nw5Gm7imB42fqF4X@~n}JA`uU} zAY(7~fqB$g;?3X^lJpv6_JjwD$p=&HI5X27A_1DEzt-5|X=+3MyvWZ?$9NX-+%SY& zQn20)qPhX7HEAofD;h-8Z^k&dy+3(_bFHUzvdXnun2)qM_^lwH{6brF{Vv}4_MjV7 zI3Q;`A6qRipwi7e(UctT7@=DbIB0mFXY_=u&80C zE+6%Fva|Jw} zg)$!==D!sNh{ETQO*Ux)s z9k2dtY%I%9Y#!3?iKjaJ$)}Zs!g!dX6<^hp%N5xLx9M&|L!rJ^&tqbcBkMyI$Yl0r z<0Zdn7=YohY+y)a=$>Cj)Fw+@fYe^{Ok+;e0$4H9dVhT!bP27r_#K0`I%yPX7{9IU zqgBDN(Y`9Tz+&V)<0e3eNPT;P_AZmcZ5+`XxK~wKC&A3U-W(CRO|7rb zI*&>1MmSYCMMCEDG7Uh)Zi?0b1~0wfYdv6uA6ED;xHUBo+LLqZ9f92_65Gwfo#(dw zL-SJ%I0%?Qei7B*%#bc=?=k2#x3WPiUm52L^Rz3AOHv-{?%vzu_4xhbtlPyYgLk0# zy_Go8D~d90rq&+`NpzWiYf9mgKx^D~D~CA-ib|$%)g8^JlIug{CKXU+W_1ROrjQIZ zO;uq5s`Ie*^3g0o>{n$-cK@=PN$Hy`L{GiEd;K~>ghr(!6UUoCBQ=MWh}RyOF+fU0 zbEH9!f8*M%c4SWIaI_F%e0AL;`tVBB(bQPOeDwE89jmclHYlj;t#z$H@)rVj`GF0u@{TrFl zluFcwj^`D+N9-R=C{gU0YTK4SKAD;@qo!Pyg}Rzp8cl8}X$Lp{*Bb512bO~s?=vlx z%q2+FQH;fBO36}SzW2E(kT|YZ4_(rsRZ-~)+_8UPK59T*J6exsy&axnM0Zj6xbuT_Ba<@p9(P09V*bzYa|cuXQz^P3M#ysk8iy&E$S zM-U>vtdFI?xm+nZ6*qTyTe+0-{sd-k9=~o(xq@y3&@J0?B)TejjO4hpHgJ)}cuNN0 zSe>c*GBn>^Gc3m&+;(ei*bHHz%y~9i329vdpCShc&F|Z{xkV0>$N6VNKsNpBBe8NX zwXxa=nF7Ym&;K$EO}gfqNeddZ;4I>i!?6aI-lDe|P|(pd+`@P zCs|CWoP0A#YQx2r$P)Xa>~@`{dpd=X?Y@Aq$ZS*`1D{sL;bIg4NT5q{Ynqodco(45 zx~Fa98e9IFUC28fcuOp?7;_BjKs`LDly*Xnp=Xpcf*+e(vF1Mb9U2G>9kT2h??!=d z&PNr|b*4PDKJThFP@XS+_*vX+OT*~~=1EwVyrEe1aIgdXzL_-X%MhytK%1L6`s1kE z`rHG55kXq1AD0z2nUn*gSTZ@cTV3cu!iEF-BMA`*(gv@LqQ~= z2pzIXGCH4|X>UII(7Lqks`9#ABAp9=Omz31rhA!JyO9d1)!cU?fBXKqis#Rf(W$I{ z2k-Q=*vkAmvgkOwdBt8Ibk-SZhtNvjRqE_)JwHZ?Sk2+T$q88#d%)R^qHq;{trgY{ zG(r3T7>Kl7{a6rAeAB{_dE6$hmRwPlPjUI&96z;g#!+(~JW&ins#8P~V0wBZ4`9rC zU!3qvH3O(lvnftgM!glT^9B7dCqq0(`DQi3jUp!3r3oVU)PPG|u}=Dw^Ldd)xT9D$ z&r2;`w@kS=MbA}Th7xV@LveygD3uV@D_vhsNIc0XC&Dp%37XP0cf;G@Cb18sNsuUF zXHYB$vRX{-avb%t+Fw1a)0Z_P9H(0_@Te$R1i?BT>6`+D6AYCzj5*tg_D-3ukebPC z5xpc?7OZTz9pTO2<*l44I#*C8S#<{~#AbfhN|>Y@%V;##O z-ufN~ZcamWd^Na7XR*p8u~cb8RhhX=skq&Kck>as$N7Y181*~d-)aXC-(DHZpV?8F#Kd7^A;C|z&F_4HqIKr3~I z^yo*4jA_}RjtpF%(__a+0%EdfM-)zX;P%e5nAEeiBK6Ql;hfJxbb1fQZwdhDXrq4k z_q5mqRMR5|*@X{Phw=AN0l4Q2ZAqOrNzg#7(PF~Y~2DZ#9S-YT-s6aW3 z)EwfiHLYjC%^liq{rjnpN{ZVa8qmNksMfy3xi8YxX z%+ZyyLNP;KmCA>s`@?6?>f5i#2g4V4LOa~rqlzIsvC-L{pGhMWihU8BbM^Lvn%gef zMs>hED0s@*NoYo38Os(I*rdc%5x<02$80Rnk8;H-Ww3RMnnteNbn8JCHAT@&56&E- zD%bucqWs&E#Z-C=n`Jh7L`ZwyJ4RwHpbj@{6<==H7~A(Iu-zOOjRE!W1po)alhAjZ z=>1tC8`|q))SqxPLQ@rUytukEXgd5Om>{&%TfJ;QkOpkl4JJ{7EPx9i#K(#~Xk}K1 zbZL?Z6spNQ&Bv~_xnk-yhJowcWG{nw1;szLXOu#lYEZtY0hP z=Wi?iJz8V!@_%o*K;F0F@Cv06xu`dmu*=T;)mu=~8S6iL%h4aiB|pvcc@uAY5vL;H zH=~x@nX6|$XO@;wvHTjWx+{(;TOgW@1iO?ez#RQ&hf)W1!gqv74+8<4!(LgYWwEGV zW{a=QSw=&pJ%HL(QdB=@p3z~?toLu^V|EtY!A#9YVEM4qs+TXWsJ9dIXiaHw-ch%N z5QwQul9lu~C$tUkkb}gPvU$NsI20wgoGg@~Wpfm4>1qj>S5`HWeCp#=@=iDhp#v_G z-(aQW*xXqFvk?)a&E|l{Mhh~pY!jRX%7wH!sZ&dZSn11=@irWlS&VgB_KTN!+6VG^ zwzp5~mE5*nJ{cL#DW~YvmupcHPhK$Xo@F05v~$Ct*3=FPnLEP-zD`+?+e|o!GCeCl zT-cm>JEzNI6%zqJ;(ZyD9<#>KywhR@BxHQj2g^J zF9e%tP9v}i+m2(TeL_hT`$HeLT9N^5+vSQf%wt zZgiDy#W7&$u$e}?NfP`%dMM(p`{&SF!E&V121P0gGjMa7K_=wbI1w0tVMDtR9>cjJ z%8A2|WO~~AFF`UO?**&*nlIVr&(Gr=OFI{9h8*qmwowSzZ6a@2+WKw7#8*ixu$mbf zC)kYskc5SG%;(FaeH*+ijas&e?ykdP7WAv3geI`xV*y|rr(3TZDLO|vMwzkRH*iwx z{D8$uq&ya>@3RnL;PMT9a_XD190%NUt3ZK;^k*EiTcjPr*liap`v;swlZnaSL z8(FlF`sf8eV@w($=Z3D{aC!u9e>X zC!iu#2v{$QwMC%QxxKa8)T2_s=#Qljj@$>bT<}}A)o9q}ANq48O07UC7pI$-zG4OG z94QwZX7H}fxsR)9WCg(|6Y}ZyxBwQJC=3T2!(E+2+dnFu0ZY3D~p3 zCrt|V-G~b9bUo`Sfoq86%p9V2g#i;O(!klY?IHKK?ljc7YDI5RNgsH!!}qAWQ^m;= zTfe{A?(Q=a?DQET6lOBV0ORA!a`&6wtc99LnrNiaQ^iiIR$R+~Js9i|cDJ4{Pw0|$ z6C-ys-jCsK%MCl5gM{QdHmsLDjL<=Pv$V-4_VUc=9olo3ux=)J=o>YL zj&W`wrc~q7K`Au{GSoOYaok!)&lhaS1aHgpE8>=3+6|}vL)SQ5hz8~zGP$p~6;at| z1sbs2pdFEbJ&uCZ8I6`#FSfT=`q5X6&2yLEx=ePD`KPMtIHsR$H(6eW9QallZzv3J zW2q#OUB{a}7%kV)v2S!27==Hv8U+0k1zAw%a#dD&V*2Mox(Q3s@1E|aFMIsixDr%b z^Y3^VHx!Hq_$UtZ6ImV0a@mSR=7&f6$$2AA9jfT9PG8HEKC{DPP2eLQb^|NVT4 zYGWcs~dMyuJ#9kL_*+tD)!hqq7|YnZgWRW4s}>;p3Nm~Z*x zRv~{xnz*t$6k}al9QJn07IVlfF)7H4?8R-D<6%029d|$YzAMJ30ixYM?*gOU7#x6| zu$UzZ&HnKR`xS01eT*$(8ZE<{M9?@b`M^YU)wl?5A%lVd({5ct5zzs9 z3TFZW7|2OS0+#$NXc-nH?PpIE85?C{_koj`JT{I)Cqa~S<%qyOim|Bfq-n|yB0X-a zC%omIh&J(lvX@&Hx!^^5Ds@b*f4;GMuc-twWm!Ql;~M!*V=vb=9x$^#^#m401UfMI}w(SOV>3>DgWdN{vb9B_Aba>LkS4|xokD*UYnA!b7Lt{w9QJ5LV;$XmP0 z(;VY47TqzV?7BNlxl};r_OrVB5%qB4yon9Y&9Qbh@0@8QkAAupDU4~y1?@HMn~;X=TH@j4c%x%J&D{HD?U z)U`d1Iyu}sn%zTJW5{bC+p`WHstskYgEADan?pC_g!zP87$OT}%?t};B?iufc`OG~ z+QI{A=1+B*49^IJnM+g$6~Qe$|0m^R$qT;~Jy7+ugQZzcyKNUq5=DeC$;BBCRz8@e z$V+#IJ%A!!xFF$tj#J-J8qBc_O}12GE23K|?|Zw~+pAS|be8?J3E^v(s+GN%y_VOt zus}vd342(kccYyO?MuHXx?>}=P1>~S>YAa}SOZ2=dM)C2`Cw4!4#oo28HIwGOz~#W z_~Bzn4I?v4{(xL^oJ|(s;M<{eBPX}UysDa~GX$$m7ra1Fq9znNtgH#+Uz>)!1yhVa zs4&7_)<+MPQjaIC-2@n&1@d@hDy+ztWSe9zdlf zV&KV8=OvkwnbN$x3OQedr0WA@frmDquU@?pC-;WKqe)EokiUio}lW zLyqFmIg~~LNF=KJ7#50kTY-LS)}4%fiHuchQPqPR!)C`frNS5{QfI|_Z4P?eW}a2c zn`2N&r=ZZT5gSF(FjR>407?yx_S)b|vMa~SRx6ql{6Lh-@}RZ4BcMy%7~}X}cd1yA zI+8ofVC{h3ezzzT#Y9!(Aw%p4iCpzGYk$9PZ`^s zLj#71x@*0hjiJbTVbf@p>pLbgh@Ju;t}xEX<6AMS%537`Q3jK=(Q5Blu{$uVs`pH9 zL2hBDtQgvD4$afp<{pF3MtARf(7jZli!)KStcpoc9G@EcvD(MOH|6FJJSHwKes9wY zMAc-9J~}XGLw5%W^5~xjoU8q}*GEx$5bhl`R3aL9ml-KT z3)}VfND&Wo+FoC$PhfR z+X4dmUC#gC(Mt}_%>O~!imSIBphpOG;~SQMA^sCiULZwG*__m(01e6_#HFF?2qqPd za|Qj!=OY7CnDYq?{&n|s_7u>&3Xd<5O{Ks!?FhwEQ89mduLtEAE>VKh6gVyO#eCUS zj2>fmOR!!@y?_aml3U+qW5kJ{9CM_I1=gOH>w?-5uEHXk1VIz)Pf?WX)mDK~C>MO)0$!fX$kU$1FP=6$JF637Cjy_7;jKQm5jL-)Nhac zN2^E%)s+Dby3A0i!XDO{wOgI{i*p=P9vkMZMQ8M|Cc*Pp6-~s`_(9E>JhSPK9`>$l zWgoc@KHfl{dtl8|K3mpjQP+j+lH{^wHc^9@TF`{fOHqOI-#E-pPC(>3{C|Ik9(?1X z{=d4i{Fkn>ga2DsoD6XpWlEE9WnywrLURg2VCj_QEG?<{ z7Fe@@`R3?}E6jcES7nW39AzaeDg3{V#W==|dZ$R)>IE(YxCy3|2Vfn4w+=KowUP@< z?$T6pW@s8%BT2#Z6unFmJ#IQQy5SEBvpp(=@`d1*=CfI79c`_sdK;Ro#|CO`OxR|J z8Q)vVl~_A^JoCc)fCdNb1*qa(H4Bj}F*qxZfB+V}kAu6Gp3s~pKW`xL1F@zVzb)=Z z(Ur>&3lhucXoa+ItAL}I4h8v-yhhJDvpvHX;Qy{GW}+)E`R}|!|G(yy^*?o0kowit zfA^6J&f6T?iX4~>ne;46)7i-o?};M#xdU{gNUA32{c?J01z2$%MG~ipmGB?)np7ZE`UF-K^bqV&U&wSP`?|0{pzIS=deM%Y5K;qc zR1unxs#n>b#xrY1H~jFcD-nXWh2W;f(``B}Eyc)6wDU|SsevhX6Dh|hjtVv2u0Cho z$b1axJVZg1-tHZ>q@Z3%GoQAFh~N-hrY8un4=*yA!MG7j^p~GE2-hF4rkS5T=Y#00 zGA>uD^)kCCp<6xZqSn;Szy&nVN^mrAT7&-sz88O7@El4B0KnGrKeCA(UH+52x9xN3 zxhdYT=Eo-@_7Bi8Y@q(t*y+!)eQ!L;bd_Q3mHNZfx;X|62s23)zdy8pLi@)PzehB; zMn%PKG?;|N)%yBfX1#b`?Xt?U%jHGtZ=2G+-&HRaqi(bJ5A&&t+7$E-cHN*!#`fL! z?r5!Um$BHh<2Ldt8_s9%PuTar`kr)`JG zR5S~x=}t&4&1Ri$gkIUoEWez-JNK501uAR|m}ZH_n9~BcvTvSRcIl+k+lZFTF8%!2 z?K2S78(Nykuex?!8vW_~=%092B-b65N*IEq+|^3b!T9XmB3RZaAsr(~^o$MJAGa{-p7_* zbKpg#YnsK9V+pd-55%3U+RYfcnD+!=_DbvOi_;58>cEO^I+J}B7>F?>{HQC`d--b8 z{{6S3!SVI`@%8!hagT?WQb;d1&llGB^QQy3m0G@TKQ}?X*&pY(`y+M_w+}Gi9J#gO z@%NBV8V;{qY~Qbc+Wha|rIGNtv}G6P>+_v*qh#av=c9>*k*|39eCD^`rLkgj_pxDk z<$t)iy4b%Jo?KMbzJS1Z4MdWgx}?nS;~9lF$$lIhpUw~NU}3MZ!#=<;-y7cuz&{2* zjqbTToZNjAy12MMaeaHy!Tp1WO8K3X)pRrgJPm&Won>Xl6K65>2-VW+T3_pQ3jhY# zog_hkLVL_1KhJ|)1_=XfCpKWPECPXuGP{CzTfgANL=2>GxG(@vQ=_n#!TV)9j7OX2!~dWL{^8dTNP(n_QHuuAO3 z{j$p9g1FdL0xRzXI_!SRnmFlIN~EF*btYfU*^QMLh*Xki&Ex48XLCN=AgsTv-uNK| zRo%*VSwUhLB4EDaPztU-2W4h6MF_ROGVV?zTHw5Q@uV(9N}+8WuP~vRwDN^VT-Vm? zLS21jK$iqmrh9UE1CC?5XboYpv5nn*3|N(TaK9L7l*lYd{fA<@Ww7%*ZRRqhh?@aUuS1{{$PXQHQ0Rp?f z1`Th&J8&M=WXnjXb5`P^SlGAs7SA?R%n7rdJEs(VCsQG{Z&-6T?S;nid5hhZ=+pznT+Px;tbar&SCxxKx7ORgcR}bE)#X%FB zsAP~&k4>h9j)Ox{b*a=8ZWp%EM7RlpSxA)frn$M#{9*jW>h>ZI;dzp!IR`56BV=Ns9dcV^u&%c*=yIbzZp}~D0k1WZ}QQd{95;; z`f$K)NFSv7xELBbkOU^-Mk-so7gfyxlko`~F^l__MCVZOW+Nzrcm$vUDZ1Lg+gE}$ zlL6-dL8k7L8gc#AOicq=frfqlUBA%UY~)bs$_3Of2Gva~;7NIsxXps$>^I0 zh8A*;r@Pz3zCxYpjB>;^gj!UW2iH+Syma;U#ba8j%?f2}Bx3S_HJf|J*ilPXPK|k3 z^4Uq8Xd#*x-aY!Bx|U!JwSC5tun30%p{g_RkXUCwY(`ikRVIP2S!y(DA8R4iRzXxM z4nYP%F^-Be7|dC=h}2IAbs~SoL*mt_uz@GQl?9d6ssN>`p#%yzb>k-h){{2Uwba_- zXe&NKZ=54#cJ~RXdc=Ko3$DWr%?Z>v{yESp4mua|DkzS2B=d~O*dF+3tq`n-8<@wu zq*InhlG+;sm$hV)ASPg>>A>AvSE+*|ZGQXIEBF6G@R{!T-Q%E9Y2@hI{CdRd! zw2#$GULY8I7R0=GZX@`f8n@APq0HiG*|ujP%qHK9!i-`m+eBV{Bd{9lgPLR^6ban) zx$1j4i5fS6-x1F{an|h(SA+bnmPB)UgkcUwb7dxPNN=A!pjVH~suIwab*rj-y zGEmJ&JKWiT-&b9|Q8Ob-9&T3_o1%VcY3561gwglX4V(Q_=je!}DwaNeccdPvt1A45 zO>aX73yFdCDAdW@aHlHuQ9a$5ar(|>IOg`>_hx2jwjThZ4#2pWqoSW8(c}K^ZpdHk zPKW52a>Q8mZ~FHKDjh@P);_d0d>4Em!m|<(QT;BYWjEo44fa*NB1~cVIB&qpgY^`j z;==S%BmW>HC*R(3ef8=!rLjR@s9*<9ako$Jr9K;Ddr}&P5STqh1qZZd>N~ShC>HBM zK5O9fxg`g`vw;~Z$Ud;1a^SVj-|>C5GLFDv7mL1fXD`^ijlQCES1umPD@!_7S7>jy%Kx+S^&F!YWXhh+07US@4khJ{B>tZeqPLAk70HLH%;~yY-#&CH z^?|ZW9)Q1?__g26EBuRg^lExY)J7Dz+ZE~+P1{KW(1C5rq4SZx5;>v9zS3QpYM^VH zHh1I62kX&-Xxr14wrnm4J8M(sEL8>n>oTamv5H+QyuP}vTTuX~c|+w&r-jsRRg(AZ zC>XtJ&km5iqCCQ3v#pd1vNw)nthPQ}D{NETRQ*)k5#)>3hw#k=6>_@@adLtk`iroO zMV6z7Yw}?`iM-7aMZrHa#=oK6A!Z`(Lk5Xl)j&_-WzB-Z?5$$>PO%a|G8Zb@@S>6h zt@LAWcOJQxRBI6mBG}_E)bQY!1EnANL#tDgLWdFu5`YcXj{Cw^y;QihHyThEV~u7x zd)z;b6{71oW1O9U!|IL_81%`>=TqHdYm8U>FWGN_Cs`0+UL)7RUST$>hQujZ`z2a? z^Dt-CsW*Y1O2v~sP~$ny+5pU!TNPSVD&TqHwI3=sQ5*=61K}RWN>w@|U0L)53fq$e zB8&?u&(H_7QWbTTY0}BW=P)m9WqT-fE(m%GMS73c7BQx;V!Y+&;#t~}%1uECg%$?x zB$3*OGd+-_*0Vzn+kyuQjaKIzcULYqCm3PfljCXY^-+0sG11KGa>+ooAufgCL!pe;H}Rc6{!Ex> zhU>Rs;37PK+)Hz9<2jMS%I(J-JI(rt5L|)5Fh{HgNr#Fg6XWVaBWXBsP8hwn-|#W~ zA=#hne3~r)j!-rh*qn5Mo6F&t^*5F>0C4zeENpO8?6sk|5@89h4}CBTzVKlIZ%SD6 z{DbjoEGpU~D()9vj1+)d9%pnhfF{#1?J>!fCGvwJVF&i`3T0W^fuoccHu>cJ8_LM! zdmmKm47;+?Cf)p_H;k|sk%)I3NQ`Iy=9TX06m!KNhkcTx63X zsIgURkz8_rFx?}$SDZ%O5_CBVnPI7u0E49O&-aEj^IquRoVC0_mF9^+1gs`J0|{tH ztbx9XD1uIyTpWiiW!a*|(Q_S4>B0$ZN0_YMuS1yhV0GP~cTCGg9=A$X1tw@8gXUrX zT#QKg0x?+KZy`(c0Ih=woUI(y%&=FjMn8f zHupDY-)tW)j-+t;D5yPiLAyy|)(in%XRXT&`^Jo1x4*`eNFwj@OLp8f=60ZaZR31L z3s<*p+Ca+d2*4^6L9)w6j?g~SR-B>@)m!9fc|x?<{6b6nPG@&p{o24*BQ2m3uens7 zxuvUkr~b@qsP7d;)7~ZPOPljS_%-z+B&XwYit(}RH_`4Rj3m`Kc2+gUh?efdA4B3l za~n@FOG+gY$g-$YnewmLj%7JaouU3}qV)+%z!MzdRMupB>T9qMSyYn`%7Jn$eG-w`BD9NWDcK@sL>$lZKmRxr?%bsQ zw9$QOwvSScogn&D9ZVFghvVq2es7p`x}$-Vzi>cNBVW*3W8G#x_DM(bAK&i5VOC$;6?|X zyJE=R+AjwgODwb#Nn68DX28TjS*8XEZ5@xspRz1xAKRqEy!v{h<{^wRR^wBjs%B|Y zl8ooX$_-8D#PNA2QP_%dmdkf1#5GA=On;_MuL^(&cq0iz<(E8@M>m;~?$EhFqE0&TEatZ_UN~_A2E^~i!;&aa|t(5qJ_9Hvr*v-I=iUlZ~HUYkP zEjJ<<;++C;nhAI-WR8stDrKhVIi3Yd=&vSkl|1ipBi=@kd{#~F zJcZ8QSPgzRf`FEq6CcnBk00whgED4Q-q_8a(+w2V;Bt0KiX`; z)B_e2C(G8E{E9*7tB(>SI=F)8-u|?L6o9M!l@tDpx&4tlbwAoXjJg-~`q49OpF`oF zPiF@~3jw~x=nHvWO=yI5qtmv9wrR;%M~RF_e>}w;;it?{X&Yfq550~$KgC{FgDHH^f0rc7i^AcXSqLj zWeh&xueRO(#T3eys&>{PwAsga7ywb-o(w^3lv5zTi&S=PQ-{rLlwdD5n1>)c;j37O z%JTvSSs9|E@DL>%k-dbFVhlO+LiIu~~kloH= z6+yK(i>_he>uKK>!H@S!kdqWK@BoH7k2qplWJZ{5#6j0f=f&p838RhOBGA0SlaIci z0yQou5d@sB2kc2tA(egGtsmtSBUQKcEtj;nh}NxLPA|0s#QLTSe@@QBP<_2Th-e}j zGf!>uSB>_k3)e`zXpz;mH3 z?8lnGAake;XYnTH!#`*-fbXCo{O>cqt#z;YS6gSfOaBCScmHi_WFk zvBd}645~>`fQo+BIj70)*3@Wqgu(*!Lq`;l$0f@8Za zvmTde%VTS(3^WK1DZ@tBbZ3+oPUd2uBk0YhT-?(bJR{A1BUhjlnZgK{iZ_!SUWLU$ zpF~IXd;E{y=l_QSJ&*OyJ4An zyGT%9>=etXO8KcI5#A3ELFq-2sCG|co!Ul;CZEWz`%P9=(x*2}wIVZpwXys-YToNd zxqVN+7Hi3Fr*KN63$a8B{2Ub8wU&5Zl8#MCw{n;UaO$eg!*A4Rbk_Itgvn{;C3hOL2>Lza^@uAROxcM{pFa=Nr7Y6dzfd7kzZOO>&k>> zZ=KWJd;nDinG{cI3S#?(ni@t2UZ%N?sZLr$2f8d;_9(njQ0pvt49c2`dr$-q25+6| zR<%8bl~%o*4poB5n@DQE5%NQ!iU%SH%tQ-tp3;ZqPM7o!hzd`=6{xkEy7<4+Pfvc< zP@tkIt*rEbpT8E|>89;iWMXi}%*oegcoQx9z+SpFlc`arr^i_|=g{!}Uw`Td$>YOJ z*{w=q5nP4AJ?^9i$n`z~jU6h3v>aJKuDHJ6u%Q-RH7wkq{ifrVuNJgXRyd5LiCt{b zI#cxOM4MF(n{3?wJucwnB>rWRO%Bh5+s3-Af-Zjn=wGQk38*h}>;1Ws)Wcv6d)pX%eB# zXlV+Nj6@Uvr9f|bhA9k&2z=jH9CsHgS?-5<{^p;~1Kt4F;?I-` z4J6796S@bQ;3Vug2Ptkkol^}kzunCnGmW%d8pU<%-)6&u#*LOZ@>;q#K?m?j09Z22 zXHltp`Aw&VQ!^r3bV;b`w~UGBrYk@>BWsrxMl=RKLENt%Cx3r?@&nZZ9W!fQY1_iG zC%4c{ep@mWZjt7O3|ZKLn~@Doauh=t3t|~w(p3>F6s1LGGDo(&&(V}T;8M~Q$vWdY z$?vYy1$s)$3HyvDt3%6k`N?aeu1-^9FCM4QaeZ;#q>0*}AxmZ%_vHbd-IH$9Smx@( z`*?0jzg%Ae*djSZrsEyzPN|iy6g`A=p-d3Rgly^WD`S0myZ@<`i@`<7F`#cCh%dAG z?Nv$1bsg6P>*Q0VtFM4bfMvhfvSkZG&_F!&yG#>P0~;3Y4*&Qj4Vfp`!yEUFQ!pC< zDF(Wi_3a~Kuup-APraIS-u`WqWS+#uZu!c%&yTX*+<`D=d$V483sDQo<4K(@>WP~H zc%xbDG!Uu!4qumi{Z~+e(*+oP zWYddxK`I$pL3Woe1h8%N#GAr)WV|~mTTBp5@fUcs9fOx@o|GG2I0H&>Yt32ma!~fo zrjX5$;R2P?-Rf8V4i8s--u&F_}FeUEDQ(w)Djh#;hTI98}$` z9zw5zE|-|eQX7bHvGgBPIbSLU$(}OS?Q5o(JSOc)%AgnQ&$xT_Ew}r|ty9I1Dj?PD z6MXi|>KaVRaMOf-ZQAp_0E>=X2BsP%aK5%wN;^rb8y$vP`_UFZIxex13j)2*ock#D zjhlK&D={dU)cfSNndS?@Sn(5n=87fG_U+c$N42@1_UcCxb#ebXv1n>Pi5ac|!jyeo zS30qgPbvo=p&yD>4P#?jZlHG&6onm{~2``_@6e)^<$0EF}aQVd?uIC7KZ=oA*)_*9UODsYJp;iM4T-{|g?)|b2Q(quR$I$aPm)A_ z1`y70qgP&^tIo;KxOKkMaWR}Jsr4pT&@(AUmI?mO7Op>8M_}-O!ynO zQ&q_PbW3Mx>DK3X9~mT@%Y{{hE+Jz;q^#Rso*J&2QM(LpdPQ)hVrU`-lG#)A!W_u} zV3vpEmvi$X!(n+%^MZXJUoAbUGg`0f#|3%IjN0j8gs;czDT}`N=&z3%|D|5c%|Q;G zxoD5>Fy@RszN{!$DKh-EBKJb&7Y&@7nKXeF$K0nte7 z;m#cK8fkurE&gBdJV>bevdWK-dxZvss5o`H%wuh&xL3m)JD-Px!#yRFhb3$W_Zqdc zI!YN6OfHGBHo?v#lb0kobChvpJuIz!!&eL!5`c4%1S?ph`FPGeuvC zxXn}LaZ(pb2~Kt@&W^zMRwssu55?yfJZtEN!4G{B7lltxabrD&vg%lGH(GK@2|YNf zv)Z7GDgl-=-gZUl%+Aziw6br0jM0ckPJ*UC+45cQ*LYgg&fF0Fbac}t3@1nf9=Vpp zIij3rN&*VIc`c!&?@`|w zEHo+RTH~;Cnv0m_0^=NrtIu?GAT$VS?4$@aQT#%PxC;`$+Av-#5S!q9EnY2Rhr03H zk8!r*?2K`*j|_Soo7Pb#<}jaf;u;ipyI?8Mptl`kX}v_d%4${=@*kPNuIlweTUQM} zwz1XAlKh~c;eM}Db)!#1YyR%>kb6a5jtI^8;^ID~cQB4fJ(qnm4rXGOCf{dw{qp%G zVmLtT7V#?r+f{na*91Cc8O}$d#%;BbF8O$-a!z2iMp<3lj-*v0rZmXt%Nhr(y@v#< zN6ED%kQXiY@h1B8G}T@C+;)}o7G+2+L=f4nvV+|eU)Ac0hd3HFA9})MAsW2{z-o~2 z@G0vPR$;t9HkH2qDb#~{uo%nCP_NP1*GS49ut?1=sd1;vCs#i728v5u2jBUQ7AIMvHIBXwD^ zR&z)nUk?bl7>K9Owv1dL2xQ`gb`Xu}3`vM?&O9`uWzvkGi1}AV{W6w#gNz|d1!4gq zsSBkaa)m}68Wl?SY>mU!MH22F7p*9AuaP$|HWjJ7h*HwyEOB@%usH0O#7f&ke_0J4 z3M=Dg#>yM-YM=gi2v}L2(FD;z|KAtCQ-IdIoagadj-h3ci_`I#)>fe4Q`z8;njj%T zVJ`N5zl8zMz0UB3H76{}@`iw;QUrNlTgWo5zc7mKjs-{R^@`mphAIcUeaB9V|2CxF zaQeJI6S-#LSnRBl<>Cq?9mUlhT$n+>JNI=I> zzND35sUv&V^drX2JTw8-;QK{I^KUV)sh_;Q=-=B{V4eodURn%Se?iU1cNpXu8y>KC zM_j1Z<*V)Pb(ycx5&gn>!ir{_O#i*WP5^B(!F(}iJor!-s_8Gi?otHdfI!!WiR<87 z;bHzG_e(f$5&;6ePP)H>6Dy7h5H>3k);=|}^^xt6p}XmtuyhY~DL;^BC@RuK`=hVh z$bGc;TJ;Ra4w9DG!3iTRn+`Jg&SIV7(gT@l6JwGs-+XHj&TJM%T)dM{)coud))OjGDU zVjDp*DlJ_jc_WT@Y9A5&UMh?p3~77V5v*7HpqIE&6&Ba7N4s)FK;poc^txTRyyuuq z8W?(%W5z5ts8_hI4j(=61a0sLUhF2W$fkI_14*SNY+AB6ATipUGlBV{3;M~>Ax2)N7{A-#C_a6?{NEI~qr$V) zV)&L*6_lN^CS1WUoH(HA6l*TWr~|CFg{3~|uT?C<)l|Z?xPy!*IBnR!ixlg!oj!{C z!u3J3eogxI@TY%D8xPqL8vlc2Y)@_|#^At>sm%P+(uH4y))e8xhbbt;gDZR|n@m?h2%ezW?AZ z(0OLU>VPDZ26IT9_p<^k@}##V?U1CW*pdQBSiMZ+-w+B0fTKT{#qi@D_H z3y~<0zxLYEF5;Rt2D!3(1sX-L@LyqXO8Y|khozU7S}?6?K-{0|ox}zK*GtJ_JX^vR z@q3jj-Qp92tOI;}A@%*}&ncmc1?wx2zttQc`NdEVd+#Zlq62ozpGT2Vj9u zAJZfq?WY!0yM0MieKQ1My}mY{Sb2Hns(zIsKClSd>qZLpLS$&TtklDn4K4N%&k8Qe zs)suL{KU7uDh_VS$(A>eXqp-eVFy&Gc87I-?GqKy_hfyFuzUThrJp|AxMZ4{Ox6WaNdV?gZ(o+GvY?IF{P|NT`(q0O68gd~q{Rr1c1r>8xCJKG2Fgp;L_ zI!#90@Zd2-7_-FT>SXvSm=COR0`#z8}mP0b*2{%VMj5P=Q`8jU)L-6O6)D!Kh^^)RH)3#6bY$_w;F z1dkaySSa>YG$jk*Wkz+o zs8me~92QVnxTQ9_qNQD<@cK3#U+=7K(P7@0&~LB!ae|@~aD=1ulwTf0U7T)f5-E#G zBjKSVjss5(PfnF$X>Cdw*(OZJRW1oliRx71^$h#Ow36QcHcP6FxtU+PA;8y6s`y?G zQXcC)=sk;9GmYy|RXOgc|l#H;i}hKq2HKcf&S{Gf5LOg#z= z64Y2NtjQvV*%V`?dn70o^ho7>Za$aZLCE!YkVaM?0R7A76N;=O;-HpKYJsw~ z!rSBtbK5Sb=OM*#@FJ7p9g7*8j9#XW@<+XA$xtV`xn?aEH8AcX@wv9NCrg#WODLHr z4XQv#y9p~!)n67THZl?P>=;J$uAO}%zp}Siue#`>r?gM^&fl`AGnEuE#8$^T7L^15NxO56fem;0*$%Pr?tlqe$jl|-=*;~>joJlsxAt@N0 zNinTMzT!ZP5+(Jh;87>_n(kmuidrhMGN?0Ms_M)`XIAU?)p}E3u}U%}9|kCH-=vte zqy1)cuWdVuVk#|!v>W+}TX9H3T_H8~zyZ)zFsAMl+t%T?;U21dzt5+0Pv#hg-=`_M z?#S|!59?0^f&Ty?x~fp3Fi}<2DE<30K%KfuK6F8NTZ zTz{{d&QuV4Jh_H#)I}a9yCSFq3;r9|eSGw>gr}^W2R%8joBtcy;VWuj1@gn6wUo$- zxx$@^@6qQ8a7UznRED9qKSrOo-olpI$uYW30J6>g&Y#cQ4GoJSOYR&|7H4@~(%GRz z9{(26p1QNFHvhc_NJ1>=FOvZ9+m7@vJ3F>|zSicdENt54^3=VMpGz2X@8=^_oE?so z>)G;+d;9{^ojaV-sdQ_gQ7hQ{Y{H{aRkRc z!+@3UlUFJBnQDWR>0@7!B1|sR(Ung zxI;svS%URLez6QpZEc+NX*gtSjl>$LrV==oe@`=9=t|2g^Te)yfN6U?+D#Z@#sAra z%QPMxr%x!K*=|AHR7m8T;7SJNV;aMX)@8A(DqJWBlrZxByos3z@2JPF{=?Zey+#GF zuG;EnaLqEw#KfzQ#DnlTKk<;%XR1C^eGE5Mp5I!S{0YQ)^l$mkb1ImU)23%ze{u&0D-9TEeKt8XG^+^Ru%++~0bjBTH zlMp}^+fa9FR38;8@BG(dVs#U22yAsOGOVtv%D9lzMO7p-C7xGo}=%>4+rWHHN5*#${94ReTYEmI&*R0><|g(*$H z(ASCr$RI1ufLb9dGc5TQUpFI3uJGhSa)HhTc1Hc$72@9H7;D^3W~YDX2=fv#5 z*ndfcr{#Tj1&LY0^#!>tvGEXBE@AzvZM#{VX3j^Fle2&E|3o}*y!W;j|GV=3NI*aY z|NqF6i@lYjqnWGAf0uqtL+8IskLJJ8aEMZv%&g117GjN~Str>mGx;68Xn0d-YIN(Bxh^Ul6X*2W(HY|Q;VxZ_UxLAh9D;C6C zf;6Absy4CM)JiMjBKR+BI;)@+o?;Lhln3hZ$bfHI5Wg}pb|s;Y-Kk|zi0|d#Hz?9N zub51;IFkld8X8fiC~*u`@jJg9nlaPUU*;&RD8FcRS->niS0p472NzfYHOMm9DJoW& z8kcD5pPGR%WvPla?K*V=CS5-IKXp_oDRnVI4Fb6@IfEKDzLBIf z?EG246Opw@n31#KVQgb;J86c|W6u!DysES$RE1!&G(+Z9)m_zx5EvTZgIZ+bkbBTL zvIvVicczS1K;y55pY|_C(e*tV8hb~siv@*C=vQ&!6(N^~tf5QTR|pP^UqcVAK~$VD z?M3fVi~oYiR^&^A-Zn#*ae@*pLQRGJFqjE%qR*+bR9MeFR7VXFq$@R_$cH&))o7^3vw<*SQi<2IveOi(y&Ken$<93UE&x%YD|i&d*2qm- zK}_LB{m1AoBHdR9w41nz3|@)iiN0IELU>QQnn{g=kBGKD`m5!s5^h+s*(GXjLG1Yb$r$n-ex-5 z4q9_5;k4OV_x2G)bL`Ba2is72ny$l5=8ZPoN&nkEdmp=R5cKl0~sO z4vJh{$|`%)=x?OzJ`x=KG zQ+uaFPYcHidu7f8tq2@x5mG<<1N#Dy#`N3gu4MF%Pj)8OKG6q;RSgJ>3iqzQE~3%} zaM%rb>LcN}Ol_L9BTYJupyUbD!9TKGX)ITd1VwQJX(y09-im4;*Q>0vB0VH=JtskZ z*DuwU>Mk~r!Va!n1iG%T__hL0qiR4Nr#A?@Q)rAn3d7g2d*f_gzB;d#YIxakpH}G= zlv1Q&#LB@?aam&?^5}p5=(^uXFt_W7RI+Rj^9XVERJRMI%@bnkjbV}44k$6Tq)C(zGNV19a} z#87nRMQ;;CL=ioc2i?t7yn^nu@A1vo@-#7CoZH0+18s4KAZTG-yBzJf^Yhxm<`6Yy z@~h;I13TK`-=axK)B)nMvly7bX9eZQ0gex^h95IcG5rA&XJ~hOxg)IO^)dQ=!UE{9 zJ(+7M)yAx;_n>zHI0^OTjslRY39c? z0IPeV$j84AB8c8s9F!Lu=eKgIKZAk(V_UmI^FsPHkYi%+%*@IBCSMsRS2t}06pI&#jq6{t7E3DO04Vpi1K`L_nTR69xq)&J#JZlS<|3v1M(ZM(l z9+J%B0x6WUU~yDqzRDXa2yjrZt6iO{!6poBo&)m|$=|4k%^lFD9!@1kckZKmeqtMO zQq>yl&!fW8;e+nIGNUvFRJy3PQtWx|2}($aX&6(;f+{<#w4kzBJXVHy)CK%M@l^%a zuV!`_ARqyHARxm3t8OiDGKu%`!&B}CElL|FJ1?<3JDkpF%DG-)>k zw`f>UQIE9EYVsD|S9f)q(I1FHlxUcg(yF_@`J=9S^oa;s~-Scd$Wo-&*_ewdldN-P;Q3o1`iG955L4QiOaCzpX z1*@sa9y;JUo27#l2lE&ETXovne}t^--E7TIaw&F%^hJ-8?-3=zy!uq$^a>YY! z3bmKR2P+?be1_YMO{O6eE3TP5YkWn3KaZSpAV1HSbHGy|2~S$FY&;Y@t&NqK`qHW$ z2<-M)eN)P2`o!fY~ad|DO^uIp^QnxZsbuc>TX)dpva%m|c83Rrw*ar`f znP_OoFQyY?_PAd?APE+FpaL7l$Eq$Z1A~snEoNl55${9s*2f;W*|vTZHYhq}bL;_& zLbgQV=+g)M4z1-}fgS$-#{EBkBYMs=*3`CEVIkJt`>UM`!mFn@awG%y4yQtAXP61& z#Ha2D^7Y6F{R=d&3vR^@*tpsYrw1k`|7do(F3bhvIZBXihO@z;Gt$qcU!PDv)a94j zO6BO{Ez~b;y#2>~T?$l7CVi*0en zM($8WQa9`jy^c-6Neq60mL?Pw&rX~+-X+6pnW=jAm-wgKJW6QNv~l|*&2I`#l)K1k zR@Exn^PQO@rd66X%O1KuO9?@uCYM5J;q?wkLN&5glcoU>O9=)S87S(`f*@ZmD?4`B z@R~evad5>^yrD3z&OZ?*EvbxVN?6I>?USBwwNZF%N!U@f^{W~>a%jyNzJ7Pb^}G5lw})i z2D1Yx(nHr=H;*4jt>DTsDbK?o>o4*`!nb~jDWaAuXS)*PWYda;5VO?As6v4fHqR5~*XEKnTrX!YB1UG{cR3rBp|2+3ai4Mva83H9TdPq zJ=cfsBif!ta}9b9gm&RhcGKXl1rCAZy8FS0at?d%j;mKNIEiDJatb6R5$ibX4pfh{ zZvzl{Z<3O=gs8%fcZl#`<8@(j=S&qjD z)VNA)!DvWXW}_)sy!l*DwyKR`c8%1Vj)7t#8N^v0TQ^6KXg#pwo>6c&B>fnw?Y2mR5@XndV3zVtw+=^SF*;Arl~ir?yw>%F7U*8##8vev=sYKUIo?u zuvTt%I#SR7RnB>7J^lD~A?|#b*ihhmamp7^+)-IGKIQwwy@ zb_R)aDoo_oW#`1aQSmK;9&3LtrVUEz7WK$`0NS-7*!C#cyGk*K+&AHhEnTDDmPu2) z)r1H!6#`}Oij3t(T{EMAtc(Xp;gVThMHa(r5a5^kS{2cH@vivF?L%waMU%2heGE~A zy!hc$d7iQd;y!E57W_A`+*Z%tbuS*8uK6)BXLT@w;KYBT2!2f4QEqTjHxw4oo9dK4 zNH#Z_Aa<+7CnX;jRQz}jfUY>(MKP28*_v)umfv38N%2R`K5bUEbSf#}cK+4UEYk~x z&Cl-W@Kq!s_5=bHN36SKS+fXpRBM@ef-3nU&o@^KDIZlTg2>T!+C99u2$2SX*X`X} zt|JwMrUFuL5?ls6Av4?5NJglmxU4b(4^dI`-|WgwcB7D5XC4(HAK%oIk^~z84QvTM zsJ$vtXcSE-yLRihJPH{vG-r_Ip|7kv&IeuNLE${6819}6hA9{&lJOa7Xb*OGh$s_V z`o+{TIUWWIJ&`0!alKKX+j#QZUPdU=zBO0pX5}=zau+uZIP7qy3$P)r^R-v$Bm_$4Z>R23#VKEU}@uHp_F*K{^wT!jhFg0Nj7iFZ?V9q#Qm5CVJx}kYpJnk*^o-$Q`R3wHlPBg7Q)k zk7FBD5HH7DlN5$@aliAv6hmzs!X;3d(=UuB5`wdI?V+TvAK^!_t@{pP3~Ifl#`Khc!-{YIn7hz}>W#9&-pPURsHpE$)yK7=X6TTnN_; z$+%6h0Xa9N*?@Y`WdL5IS!V3V06%yY^y~}Yyd%{j%Ih@r&S}CPJN^4pb89i4_qN5%h%ftCia+2zK5FbVh?Y)w%9P-&hopls_?ZYkIT76u5ca#E9S8H zS8~HQ-NXO!4ux*bKmK}^t$Um|ne7jS#NQ+ZX1q+tfcL@S&37bUX3O)P9ZcANtT^sh z)O`0>RkOcv;?0N9CZVoHsmzj~0n7kugT{UOX!SM)55zjJFjBm4!v85Ux1YCyFhT+W z9i#uR4O1RQUbaT||5s;D)BI0o7DxH1H)yisPaIVe#d$%1JW?%nJ07nzfwUmEGJ+b7 z)|Jvp(M@M)cMJdhn!CaE5ZiY8JA~nJ?w6mHcSh^{dbxN1?2_M9ZT8%ftA>BzyiPZ{ zz&7`0`$OTy=OZRB>Sy_3e~`q{@SkZ-Xyqc}k380Y4*078?cl(11(@2pRcP62M<$nA zu{(H$mr)s>(PqUjQX}Wyc2a6%=_9*oxKn(#mavpj*A_JX*gxuYE-M-PZfbv{xD!0e_Cnv}wGjwzV5w|FdS!_(Z z842C6obGlB0C>vtEXhW0E~Y09VWwBKS*j>*j(>jtk?;Es|6N+n%w>)y?l$xgH=fc~ zLiaTh&2zqFtnVLK(2QHknfpkuOjW3Jj!^U-n88u9f<5?7RJ|N9f7_K6-~sG{l8&*H&SZ$B7_Zs_kmKtbPZnZy(mSr6|Q#d-7wiHci_9+P;lm9 z1HNa7z?U>b1As6y1Y1w=je#635PP^Ue=hY;!;7LIkQ&TLNjDQju3oNwa+wN~kz>V& z;`Q~Zf#S;pY}#}1Z^GHkVZ`Y{BL?+Pu3b^5*H{lLypFnU6ThuLrhPLh^RHC;lCfi7 zgBGfIRNCQ#xO}J}{jmr{lN_*L{tD>R`XP)p=W*|rP|$h`8^422Pb;G5vr3@9XL%g51na5D5H$+%4V~n^;NHlnxCVCB2xUA9aT{arB^`tD zBIi`8jO$dJ{R0i579JomRw+)|20R*+2ta-kAn8r3oebXftQV?}S-(tR8p zG+BRi=`vguzZda^%#cns>`5 zO|Ux6OdKY&W6ibUXiKNdwS_T>?&FGd?L@xzbNdyr9@=|J%Q_IqNa)4Ft?J! z0z#s~@rNY2#F~of-wZf}xKtoG ze0Uy@2ImK=iqfaieL59QuB(iQ~$Xz)|<|vF1mTq6cMX#c3?_pXC~JMgeHa~Euh~3nds&`n!-jca*E);Io1G~!Bj0y4Y7f9_+?G!`UG*jI~v5y6q2o zzQfW(bfl2(rl8b#mCjK-d>SiNpFqndK4YrIJHLbsw)TJc`lskz!nFw$jcsejwryv| zwr$(CZQHhO+qRv|Bq!^PaW4LK_SzSH{f+T;zg^W;&r`M87%7{pYI{68IZO5K$wM$H zY+_-1WSby8zBYFSrZJ_EUbE}P*t=+kPuw)Jf>JOZp9?p|cksuN&)?IFktL4ySI7}y z{_~ry$G*#yQ3=O_nH>*RS|1f#{k%pzN`0tFpKH0o(J(`D8Q=IuzStAakBOa#dcDk~ zH+1UG?|~v4;E?BmmKO7~m^qs-eZzOG*^mo_%S#7<$2)I!3=u>LC}V=<{v8|YFUK?@ zI?#H;>l-$tUhKZ^YLI-y@VKCHI%j!4o?Oi%|ls~dHa7|~Z za6arL{pWxKwia+u?L=qw$SUM~Msuv50exNx5o(rK6DpWrXL{?YDt- z?88PvY7gRQ>~9(l5Lv9LUmNPH_!SG(-HYn1{#u@j$#N<-yY9Bj{(6Jg23i*S$O}v^ zGZIFvE2yOY17sjw4)3}{u@X}-5_p&0_P^5hfDh?F6v9NjI424d??wJpajM?VOvsH+ zKABM4fSdOG6$LQGi>u;C4sGCh2SLwniX$7nX zv>w^h)s;fq8q^2)ymU=M)fu+=y@@rj$4&6*dyFV+5f(@t=4@LQdOeQD)!YEpeR-6_ z{&Y7x))s>=?)+p?tj^HIF4%k5r-BTPYs~n;1K^JrN3;| z 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 xh$?aACnZ`WO(~&zTWV;9{+lbV14mRw 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