From 51c253f3a890b8628e04010b87bf348be60701c1 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Fri, 25 Jul 2025 17:15:39 +0800 Subject: [PATCH 01/14] QEMU update to version 8.2.0-38: Signed-off-by: zhangpengrui --- ...ke-s-mem_region_alignment-be-64-bits.patch | 48 ++++++++++ ...accept-NULL-qiov-in-bdrv_pad_request.patch | 80 +++++++++++++++++ ...-fix-assertion-error-in-isa_bus_get_.patch | 37 ++++++++ qemu.spec | 20 ++++- ...m-Adjust-and-validate-mtedesc-sizem1.patch | 66 ++++++++++++++ ...-arm-fix-qemu-arm-target-build-error.patch | 41 +++++++++ ...i386-Add-new-Hygon-Chengdu-CPU-model.patch | 89 +++++++++++++++++++ 7 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 block-blkio-Make-s-mem_region_alignment-be-64-bits.patch create mode 100644 block-io-accept-NULL-qiov-in-bdrv_pad_request.patch create mode 100644 hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch create mode 100644 target-arm-Adjust-and-validate-mtedesc-sizem1.patch create mode 100644 target-arm-fix-qemu-arm-target-build-error.patch create mode 100644 target-i386-Add-new-Hygon-Chengdu-CPU-model.patch diff --git a/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch b/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch new file mode 100644 index 00000000..3b95eea9 --- /dev/null +++ b/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch @@ -0,0 +1,48 @@ +From ede25e9b7c5cc8ce1c668f306bfbe5c90564570b Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:13:10 +0800 +Subject: [PATCH] block/blkio: Make s->mem_region_alignment be 64 bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 615eaeab3d318ba239d54141a4251746782f65c1 + +With GCC 14 the code failed to compile on i686 (and was wrong for any +version of GCC): + +../block/blkio.c: In function ‘blkio_file_open’: +../block/blkio.c:857:28: error: passing argument 3 of ‘blkio_get_uint64’ from incompatible pointer type [-Wincompatible-pointer-types] + 857 | &s->mem_region_alignment); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | size_t * {aka unsigned int *} +In file included from ../block/blkio.c:12: +/usr/include/blkio.h:49:67: note: expected ‘uint64_t *’ {aka ‘long long unsigned int *’} but argument is of type ‘size_t *’ {aka ‘unsigned int *’} + 49 | int blkio_get_uint64(struct blkio *b, const char *name, uint64_t *value); + | ~~~~~~~~~~^~~~~ + +Signed-off-by: Richard W.M. Jones +Message-id: 20240130122006.2977938-1-rjones@redhat.com +Signed-off-by: Stefan Hajnoczi +Signed-off-by: gubin +--- + block/blkio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/blkio.c b/block/blkio.c +index 027c16ceb6..52ac94527f 100644 +--- a/block/blkio.c ++++ b/block/blkio.c +@@ -68,7 +68,7 @@ typedef struct { + CoQueue bounce_available; + + /* The value of the "mem-region-alignment" property */ +- size_t mem_region_alignment; ++ uint64_t mem_region_alignment; + + /* Can we skip adding/deleting blkio_mem_regions? */ + bool needs_mem_regions; +-- +2.33.0 + diff --git a/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch b/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch new file mode 100644 index 00000000..0235d649 --- /dev/null +++ b/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch @@ -0,0 +1,80 @@ +From a01e9f722d8e187493cda6acf645012793bc95fe Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:18:04 +0800 +Subject: [PATCH] block/io: accept NULL qiov in bdrv_pad_request + +cherry-pick from 3f934817c82c2f1bf1c238f8d1065a3be10a3c9e + +Some operations, e.g. block-stream, perform reads while discarding the +results (only copy-on-read matters). In this case, they will pass NULL +as the target QEMUIOVector, which will however trip bdrv_pad_request, +since it wants to extend its passed vector. In particular, this is the +case for the blk_co_preadv() call in stream_populate(). + +If there is no qiov, no operation can be done with it, but the bytes +and offset still need to be updated, so the subsequent aligned read +will actually be aligned and not run into an assertion failure. + +Originally-by: Stefan Reiter +Signed-off-by: Thomas Lamprecht +Signed-off-by: Fiona Ebner +Message-ID: <20240322095009.346989-2-f.ebner@proxmox.com> +Reviewed-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Kevin Wolf +Signed-off-by: gubin +Signed-off-by: gubin +--- + block/io.c | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/block/io.c b/block/io.c +index a280a5a4c9..27d6a1a04b 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1756,22 +1756,29 @@ static int bdrv_pad_request(BlockDriverState *bs, + return 0; + } + +- sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes, +- &sliced_head, &sliced_tail, +- &sliced_niov); +- +- /* Guaranteed by bdrv_check_request32() */ +- assert(*bytes <= SIZE_MAX); +- ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov, +- sliced_head, *bytes); +- if (ret < 0) { +- bdrv_padding_finalize(pad); +- return ret; ++ /* ++ * For prefetching in stream_populate(), no qiov is passed along, because ++ * only copy-on-read matters. ++ */ ++ if (qiov && *qiov) { ++ sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes, ++ &sliced_head, &sliced_tail, ++ &sliced_niov); ++ ++ /* Guaranteed by bdrv_check_request32() */ ++ assert(*bytes <= SIZE_MAX); ++ ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov, ++ sliced_head, *bytes); ++ if (ret < 0) { ++ bdrv_padding_finalize(pad); ++ return ret; ++ } ++ *qiov = &pad->local_qiov; ++ *qiov_offset = 0; + } ++ + *bytes += pad->head + pad->tail; + *offset -= pad->head; +- *qiov = &pad->local_qiov; +- *qiov_offset = 0; + if (padded) { + *padded = true; + } +-- +2.33.0 + diff --git a/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch b/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch new file mode 100644 index 00000000..3bb243fa --- /dev/null +++ b/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch @@ -0,0 +1,37 @@ +From 3e4513fcbbb00aff1d8147cee3b93c2bbf3a68fb Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Sat, 14 Jun 2025 17:09:25 +0800 +Subject: [PATCH] hw/audio/cs4231a: fix assertion error in isa_bus_get_irq + + This patch fixes an assertion error in isa_bus_get_irq() in + /hw/isa/isa-bus.c by adding a constraint to the irq property. + Patch v1 misused ISA_NUM_IRQS, pls ignore that. + + Signed-off-by: Zheng Huang + Link: https://lore.kernel.org/r/6d228069-e38f-4c46-813f-edcccc5c47e4@gmail.com + Signed-off-by: Paolo Bonzini + +Signed-off-by: dinglimin +--- + hw/audio/cs4231a.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c +index 3aa105748d..88dfd0bb7f 100644 +--- a/hw/audio/cs4231a.c ++++ b/hw/audio/cs4231a.c +@@ -682,6 +682,11 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) + return; + } + ++ if (s->irq >= ISA_NUM_IRQS) { ++ error_setg(errp, "Invalid IRQ %d (max %d)", s->irq, ISA_NUM_IRQS - 1); ++ return; ++ } ++ + s->pic = isa_bus_get_irq(bus, s->irq); + k = ISADMA_GET_CLASS(s->isa_dma); + k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 28d63341..43f87215 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 37 +Release: 38 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -947,8 +947,12 @@ Patch0930: qemu-options-enable-smbios-option-on-RISC-V.patch Patch0931: qemu-options.hx-correct-formatting-smbios-type-4.patch Patch0932: tests-unit-test-char-Avoid-using-g_alloca.patch Patch0933: virtio-processes-indirect-descriptors-even-if-the-re.patch - - +Patch0934: hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch +Patch0935: block-blkio-Make-s-mem_region_alignment-be-64-bits.patch +Patch0936: target-arm-Adjust-and-validate-mtedesc-sizem1.patch +Patch0937: block-io-accept-NULL-qiov-in-bdrv_pad_request.patch +Patch0938: target-arm-fix-qemu-arm-target-build-error.patch +Patch0939: target-i386-Add-new-Hygon-Chengdu-CPU-model.patch BuildRequires: flex BuildRequires: gcc @@ -1547,7 +1551,15 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Thu Oct 23 2025 AlexChen - 11:8.2.0-37 +* Fri Jul 25 2025 Pengrui Zhang - 11:8.2.0-38 +- hw/audio/cs4231a: fix assertion error in isa_bus_get_irq +- block/blkio: Make s->mem_region_alignment be 64 bits +- target/arm: Adjust and validate mtedesc sizem1 +- block/io: accept NULL qiov in bdrv_pad_request +- target-arm: fix qemu-arm target build error +- target/i386: Add new Hygon 'Chengdu' CPU model + +Thu Oct 23 2025 AlexChen - 11:8.2.0-37 - sync header file from upstream - backends/tpm: Avoid using g_alloca() - hw/virtio/virtio-pci:Support shadow device for virtio-net/blk/scsi devices diff --git a/target-arm-Adjust-and-validate-mtedesc-sizem1.patch b/target-arm-Adjust-and-validate-mtedesc-sizem1.patch new file mode 100644 index 00000000..c2248de0 --- /dev/null +++ b/target-arm-Adjust-and-validate-mtedesc-sizem1.patch @@ -0,0 +1,66 @@ +From 19ef3764888b212a63603ac46e88b4cfd99dd7b2 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:24:49 +0800 +Subject: [PATCH] target/arm: Adjust and validate mtedesc sizem1 + +cherry-pick from b12a7671b6099a26ce5d5ab09701f151e21c112c + +When we added SVE_MTEDESC_SHIFT, we effectively limited the +maximum size of MTEDESC. Adjust SIZEM1 to consume the remaining +bits (32 - 10 - 5 - 12 == 5). Assert that the data to be stored +fits within the field (expecting 8 * 4 - 1 == 31, exact fit). + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-4-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +Signed-off-by: gubin +--- + target/arm/internals.h | 2 +- + target/arm/tcg/translate-sve.c | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 20b9c1da38..ed9bfb29c8 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -1265,7 +1265,7 @@ FIELD(MTEDESC, TBI, 4, 2) + FIELD(MTEDESC, TCMA, 6, 2) + FIELD(MTEDESC, WRITE, 8, 1) + FIELD(MTEDESC, ALIGN, 9, 3) +-FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - 12) /* size - 1 */ ++FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - SVE_MTEDESC_SHIFT - 12) /* size - 1 */ + + bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr); + uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index 1d8e0d29bf..1b722ae75d 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4457,17 +4457,18 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr t_pg; ++ uint32_t sizem1; + int desc = 0; + + assert(mte_n >= 1 && mte_n <= 4); ++ sizem1 = (mte_n << dtype_msz(dtype)) - 1; ++ assert(sizem1 <= R_MTEDESC_SIZEM1_MASK >> R_MTEDESC_SIZEM1_SHIFT); + if (s->mte_active[0]) { +- int msz = dtype_msz(dtype); +- + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); +- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (mte_n << msz) - 1); ++ desc = FIELD_DP32(desc, MTEDESC, SIZEM1, sizem1); + desc <<= SVE_MTEDESC_SHIFT; + } else { + addr = clean_data_tbi(s, addr); +-- +2.33.0 + diff --git a/target-arm-fix-qemu-arm-target-build-error.patch b/target-arm-fix-qemu-arm-target-build-error.patch new file mode 100644 index 00000000..fc848b70 --- /dev/null +++ b/target-arm-fix-qemu-arm-target-build-error.patch @@ -0,0 +1,41 @@ +From d9940c5d6b3b7ad1173a16c58246196a03b3d317 Mon Sep 17 00:00:00 2001 +From: huangyan +Date: Fri, 4 Jul 2025 00:31:45 +0800 +Subject: [PATCH] target-arm: fix qemu-arm target build error * handle PSCI + calls in qemu-arm + +this change the same as upstream: +98128601ac8ff23df8a4c48acff00f9614613463: +* target-arm: add emulation of PSCI calls for system emulation + +Ported-by: huangyan huangyan@cdjrlc.com +Original-author: wangziliang wangziliang@kylinos.cn +--- + target/arm/internals.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 20b9c1da38..a02a98d72a 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -314,10 +314,17 @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len); + /* Callback function for when a watchpoint or breakpoint triggers. */ + void arm_debug_excp_handler(CPUState *cs); + ++#ifdef CONFIG_USER_ONLY ++static inline bool arm_is_psci_call(ARMCPU *cpu, int excp_type) ++{ ++ return false; ++} ++#else + /* Return true if the r0/x0 value indicates that this SMC/HVC is a PSCI call. */ + bool arm_is_psci_call(ARMCPU *cpu, int excp_type); + /* Actually handle a PSCI call */ + void arm_handle_psci_call(ARMCPU *cpu); ++#endif + + /** + * arm_clear_exclusive: clear the exclusive monitor +-- +2.33.0 + diff --git a/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch b/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch new file mode 100644 index 00000000..829b46d4 --- /dev/null +++ b/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch @@ -0,0 +1,89 @@ +From 198d98579a2ccb26423b644b29f53323c9bcb1e8 Mon Sep 17 00:00:00 2001 +From: Yanjing Zhou +Date: Mon, 19 May 2025 08:14:54 +0000 +Subject: [PATCH] target/i386: Add new Hygon 'Chengdu' CPU model + +Add the following feature bits compare to Dhyana CPU model: +avx512f, avx512dq, avx512ifma, clwb, avx512cd, avx512bw, gfni, +avx512vl, avx512_bf16, wbnoinvd, avx512vbmi, avx512_vbmi2, +vaes, vpclmulqdq, avx512_vnni, avx512_bitalg,avx512_vpopcntdq + +Signed-off-by: Yanjing Zhou +--- + target/i386/cpu.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f79d0c9abf..8360ea3d61 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5324,6 +5324,66 @@ static const X86CPUDefinition builtin_x86_defs[] = { + .model_id = "Hygon Dharma Processor", + .cache_info = &dharma_cache_info, + }, ++ { ++ .name = "Chengdu", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_HYGON, ++ .family = 24, ++ .model = 7, ++ .stepping = 0, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | ++ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | ++ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | ++ CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB | ++ CPUID_8000_0008_EBX_IBRS | CPUID_8000_0008_EBX_STIBP | ++ CPUID_8000_0008_EBX_AMD_SSBD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | ++ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_AVX512F | ++ CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_RDSEED | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA | ++ CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | ++ CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | ++ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | ++ CPUID_7_0_ECX_AVX512_VPOPCNTDQ, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX512_BF16, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_SVM] = ++ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, ++ .xlevel = 0x80000020, ++ .model_id = "Hygon Chengdu Processor", ++ .cache_info = &dharma_cache_info, ++ }, + }; + + /* +-- +2.33.0 + -- Gitee From 9000268e490d3ca68cf0f7f9c89a69b7c78f518e Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Fri, 25 Jul 2025 17:15:39 +0800 Subject: [PATCH 02/14] QEMU update to version 8.2.0-38: Signed-off-by: zhangpengrui --- ...ke-s-mem_region_alignment-be-64-bits.patch | 48 ++++++++++ ...accept-NULL-qiov-in-bdrv_pad_request.patch | 80 +++++++++++++++++ ...-fix-assertion-error-in-isa_bus_get_.patch | 37 ++++++++ qemu.spec | 20 ++++- ...m-Adjust-and-validate-mtedesc-sizem1.patch | 66 ++++++++++++++ ...-arm-fix-qemu-arm-target-build-error.patch | 41 +++++++++ ...i386-Add-new-Hygon-Chengdu-CPU-model.patch | 89 +++++++++++++++++++ 7 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 block-blkio-Make-s-mem_region_alignment-be-64-bits.patch create mode 100644 block-io-accept-NULL-qiov-in-bdrv_pad_request.patch create mode 100644 hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch create mode 100644 target-arm-Adjust-and-validate-mtedesc-sizem1.patch create mode 100644 target-arm-fix-qemu-arm-target-build-error.patch create mode 100644 target-i386-Add-new-Hygon-Chengdu-CPU-model.patch diff --git a/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch b/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch new file mode 100644 index 00000000..3b95eea9 --- /dev/null +++ b/block-blkio-Make-s-mem_region_alignment-be-64-bits.patch @@ -0,0 +1,48 @@ +From ede25e9b7c5cc8ce1c668f306bfbe5c90564570b Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:13:10 +0800 +Subject: [PATCH] block/blkio: Make s->mem_region_alignment be 64 bits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 615eaeab3d318ba239d54141a4251746782f65c1 + +With GCC 14 the code failed to compile on i686 (and was wrong for any +version of GCC): + +../block/blkio.c: In function ‘blkio_file_open’: +../block/blkio.c:857:28: error: passing argument 3 of ‘blkio_get_uint64’ from incompatible pointer type [-Wincompatible-pointer-types] + 857 | &s->mem_region_alignment); + | ^~~~~~~~~~~~~~~~~~~~~~~~ + | | + | size_t * {aka unsigned int *} +In file included from ../block/blkio.c:12: +/usr/include/blkio.h:49:67: note: expected ‘uint64_t *’ {aka ‘long long unsigned int *’} but argument is of type ‘size_t *’ {aka ‘unsigned int *’} + 49 | int blkio_get_uint64(struct blkio *b, const char *name, uint64_t *value); + | ~~~~~~~~~~^~~~~ + +Signed-off-by: Richard W.M. Jones +Message-id: 20240130122006.2977938-1-rjones@redhat.com +Signed-off-by: Stefan Hajnoczi +Signed-off-by: gubin +--- + block/blkio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/blkio.c b/block/blkio.c +index 027c16ceb6..52ac94527f 100644 +--- a/block/blkio.c ++++ b/block/blkio.c +@@ -68,7 +68,7 @@ typedef struct { + CoQueue bounce_available; + + /* The value of the "mem-region-alignment" property */ +- size_t mem_region_alignment; ++ uint64_t mem_region_alignment; + + /* Can we skip adding/deleting blkio_mem_regions? */ + bool needs_mem_regions; +-- +2.33.0 + diff --git a/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch b/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch new file mode 100644 index 00000000..0235d649 --- /dev/null +++ b/block-io-accept-NULL-qiov-in-bdrv_pad_request.patch @@ -0,0 +1,80 @@ +From a01e9f722d8e187493cda6acf645012793bc95fe Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:18:04 +0800 +Subject: [PATCH] block/io: accept NULL qiov in bdrv_pad_request + +cherry-pick from 3f934817c82c2f1bf1c238f8d1065a3be10a3c9e + +Some operations, e.g. block-stream, perform reads while discarding the +results (only copy-on-read matters). In this case, they will pass NULL +as the target QEMUIOVector, which will however trip bdrv_pad_request, +since it wants to extend its passed vector. In particular, this is the +case for the blk_co_preadv() call in stream_populate(). + +If there is no qiov, no operation can be done with it, but the bytes +and offset still need to be updated, so the subsequent aligned read +will actually be aligned and not run into an assertion failure. + +Originally-by: Stefan Reiter +Signed-off-by: Thomas Lamprecht +Signed-off-by: Fiona Ebner +Message-ID: <20240322095009.346989-2-f.ebner@proxmox.com> +Reviewed-by: Kevin Wolf +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Kevin Wolf +Signed-off-by: gubin +Signed-off-by: gubin +--- + block/io.c | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/block/io.c b/block/io.c +index a280a5a4c9..27d6a1a04b 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -1756,22 +1756,29 @@ static int bdrv_pad_request(BlockDriverState *bs, + return 0; + } + +- sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes, +- &sliced_head, &sliced_tail, +- &sliced_niov); +- +- /* Guaranteed by bdrv_check_request32() */ +- assert(*bytes <= SIZE_MAX); +- ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov, +- sliced_head, *bytes); +- if (ret < 0) { +- bdrv_padding_finalize(pad); +- return ret; ++ /* ++ * For prefetching in stream_populate(), no qiov is passed along, because ++ * only copy-on-read matters. ++ */ ++ if (qiov && *qiov) { ++ sliced_iov = qemu_iovec_slice(*qiov, *qiov_offset, *bytes, ++ &sliced_head, &sliced_tail, ++ &sliced_niov); ++ ++ /* Guaranteed by bdrv_check_request32() */ ++ assert(*bytes <= SIZE_MAX); ++ ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov, ++ sliced_head, *bytes); ++ if (ret < 0) { ++ bdrv_padding_finalize(pad); ++ return ret; ++ } ++ *qiov = &pad->local_qiov; ++ *qiov_offset = 0; + } ++ + *bytes += pad->head + pad->tail; + *offset -= pad->head; +- *qiov = &pad->local_qiov; +- *qiov_offset = 0; + if (padded) { + *padded = true; + } +-- +2.33.0 + diff --git a/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch b/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch new file mode 100644 index 00000000..3bb243fa --- /dev/null +++ b/hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch @@ -0,0 +1,37 @@ +From 3e4513fcbbb00aff1d8147cee3b93c2bbf3a68fb Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Sat, 14 Jun 2025 17:09:25 +0800 +Subject: [PATCH] hw/audio/cs4231a: fix assertion error in isa_bus_get_irq + + This patch fixes an assertion error in isa_bus_get_irq() in + /hw/isa/isa-bus.c by adding a constraint to the irq property. + Patch v1 misused ISA_NUM_IRQS, pls ignore that. + + Signed-off-by: Zheng Huang + Link: https://lore.kernel.org/r/6d228069-e38f-4c46-813f-edcccc5c47e4@gmail.com + Signed-off-by: Paolo Bonzini + +Signed-off-by: dinglimin +--- + hw/audio/cs4231a.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c +index 3aa105748d..88dfd0bb7f 100644 +--- a/hw/audio/cs4231a.c ++++ b/hw/audio/cs4231a.c +@@ -682,6 +682,11 @@ static void cs4231a_realizefn (DeviceState *dev, Error **errp) + return; + } + ++ if (s->irq >= ISA_NUM_IRQS) { ++ error_setg(errp, "Invalid IRQ %d (max %d)", s->irq, ISA_NUM_IRQS - 1); ++ return; ++ } ++ + s->pic = isa_bus_get_irq(bus, s->irq); + k = ISADMA_GET_CLASS(s->isa_dma); + k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 28d63341..43f87215 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 37 +Release: 38 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -947,8 +947,12 @@ Patch0930: qemu-options-enable-smbios-option-on-RISC-V.patch Patch0931: qemu-options.hx-correct-formatting-smbios-type-4.patch Patch0932: tests-unit-test-char-Avoid-using-g_alloca.patch Patch0933: virtio-processes-indirect-descriptors-even-if-the-re.patch - - +Patch0934: hw-audio-cs4231a-fix-assertion-error-in-isa_bus_get_.patch +Patch0935: block-blkio-Make-s-mem_region_alignment-be-64-bits.patch +Patch0936: target-arm-Adjust-and-validate-mtedesc-sizem1.patch +Patch0937: block-io-accept-NULL-qiov-in-bdrv_pad_request.patch +Patch0938: target-arm-fix-qemu-arm-target-build-error.patch +Patch0939: target-i386-Add-new-Hygon-Chengdu-CPU-model.patch BuildRequires: flex BuildRequires: gcc @@ -1547,7 +1551,15 @@ getent passwd qemu >/dev/null || \ %endif %changelog -* Thu Oct 23 2025 AlexChen - 11:8.2.0-37 +* Fri Jul 25 2025 Pengrui Zhang - 11:8.2.0-38 +- hw/audio/cs4231a: fix assertion error in isa_bus_get_irq +- block/blkio: Make s->mem_region_alignment be 64 bits +- target/arm: Adjust and validate mtedesc sizem1 +- block/io: accept NULL qiov in bdrv_pad_request +- target-arm: fix qemu-arm target build error +- target/i386: Add new Hygon 'Chengdu' CPU model + +Thu Oct 23 2025 AlexChen - 11:8.2.0-37 - sync header file from upstream - backends/tpm: Avoid using g_alloca() - hw/virtio/virtio-pci:Support shadow device for virtio-net/blk/scsi devices diff --git a/target-arm-Adjust-and-validate-mtedesc-sizem1.patch b/target-arm-Adjust-and-validate-mtedesc-sizem1.patch new file mode 100644 index 00000000..c2248de0 --- /dev/null +++ b/target-arm-Adjust-and-validate-mtedesc-sizem1.patch @@ -0,0 +1,66 @@ +From 19ef3764888b212a63603ac46e88b4cfd99dd7b2 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 25 Jun 2025 17:24:49 +0800 +Subject: [PATCH] target/arm: Adjust and validate mtedesc sizem1 + +cherry-pick from b12a7671b6099a26ce5d5ab09701f151e21c112c + +When we added SVE_MTEDESC_SHIFT, we effectively limited the +maximum size of MTEDESC. Adjust SIZEM1 to consume the remaining +bits (32 - 10 - 5 - 12 == 5). Assert that the data to be stored +fits within the field (expecting 8 * 4 - 1 == 31, exact fit). + +Cc: qemu-stable@nongnu.org +Reviewed-by: Peter Maydell +Signed-off-by: Richard Henderson +Tested-by: Gustavo Romero +Message-id: 20240207025210.8837-4-richard.henderson@linaro.org +Signed-off-by: Peter Maydell +Signed-off-by: gubin +--- + target/arm/internals.h | 2 +- + target/arm/tcg/translate-sve.c | 7 ++++--- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 20b9c1da38..ed9bfb29c8 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -1265,7 +1265,7 @@ FIELD(MTEDESC, TBI, 4, 2) + FIELD(MTEDESC, TCMA, 6, 2) + FIELD(MTEDESC, WRITE, 8, 1) + FIELD(MTEDESC, ALIGN, 9, 3) +-FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - 12) /* size - 1 */ ++FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - SVE_MTEDESC_SHIFT - 12) /* size - 1 */ + + bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr); + uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); +diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c +index 1d8e0d29bf..1b722ae75d 100644 +--- a/target/arm/tcg/translate-sve.c ++++ b/target/arm/tcg/translate-sve.c +@@ -4457,17 +4457,18 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, + { + unsigned vsz = vec_full_reg_size(s); + TCGv_ptr t_pg; ++ uint32_t sizem1; + int desc = 0; + + assert(mte_n >= 1 && mte_n <= 4); ++ sizem1 = (mte_n << dtype_msz(dtype)) - 1; ++ assert(sizem1 <= R_MTEDESC_SIZEM1_MASK >> R_MTEDESC_SIZEM1_SHIFT); + if (s->mte_active[0]) { +- int msz = dtype_msz(dtype); +- + desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); + desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); + desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); +- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (mte_n << msz) - 1); ++ desc = FIELD_DP32(desc, MTEDESC, SIZEM1, sizem1); + desc <<= SVE_MTEDESC_SHIFT; + } else { + addr = clean_data_tbi(s, addr); +-- +2.33.0 + diff --git a/target-arm-fix-qemu-arm-target-build-error.patch b/target-arm-fix-qemu-arm-target-build-error.patch new file mode 100644 index 00000000..fc848b70 --- /dev/null +++ b/target-arm-fix-qemu-arm-target-build-error.patch @@ -0,0 +1,41 @@ +From d9940c5d6b3b7ad1173a16c58246196a03b3d317 Mon Sep 17 00:00:00 2001 +From: huangyan +Date: Fri, 4 Jul 2025 00:31:45 +0800 +Subject: [PATCH] target-arm: fix qemu-arm target build error * handle PSCI + calls in qemu-arm + +this change the same as upstream: +98128601ac8ff23df8a4c48acff00f9614613463: +* target-arm: add emulation of PSCI calls for system emulation + +Ported-by: huangyan huangyan@cdjrlc.com +Original-author: wangziliang wangziliang@kylinos.cn +--- + target/arm/internals.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/target/arm/internals.h b/target/arm/internals.h +index 20b9c1da38..a02a98d72a 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -314,10 +314,17 @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len); + /* Callback function for when a watchpoint or breakpoint triggers. */ + void arm_debug_excp_handler(CPUState *cs); + ++#ifdef CONFIG_USER_ONLY ++static inline bool arm_is_psci_call(ARMCPU *cpu, int excp_type) ++{ ++ return false; ++} ++#else + /* Return true if the r0/x0 value indicates that this SMC/HVC is a PSCI call. */ + bool arm_is_psci_call(ARMCPU *cpu, int excp_type); + /* Actually handle a PSCI call */ + void arm_handle_psci_call(ARMCPU *cpu); ++#endif + + /** + * arm_clear_exclusive: clear the exclusive monitor +-- +2.33.0 + diff --git a/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch b/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch new file mode 100644 index 00000000..829b46d4 --- /dev/null +++ b/target-i386-Add-new-Hygon-Chengdu-CPU-model.patch @@ -0,0 +1,89 @@ +From 198d98579a2ccb26423b644b29f53323c9bcb1e8 Mon Sep 17 00:00:00 2001 +From: Yanjing Zhou +Date: Mon, 19 May 2025 08:14:54 +0000 +Subject: [PATCH] target/i386: Add new Hygon 'Chengdu' CPU model + +Add the following feature bits compare to Dhyana CPU model: +avx512f, avx512dq, avx512ifma, clwb, avx512cd, avx512bw, gfni, +avx512vl, avx512_bf16, wbnoinvd, avx512vbmi, avx512_vbmi2, +vaes, vpclmulqdq, avx512_vnni, avx512_bitalg,avx512_vpopcntdq + +Signed-off-by: Yanjing Zhou +--- + target/i386/cpu.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f79d0c9abf..8360ea3d61 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5324,6 +5324,66 @@ static const X86CPUDefinition builtin_x86_defs[] = { + .model_id = "Hygon Dharma Processor", + .cache_info = &dharma_cache_info, + }, ++ { ++ .name = "Chengdu", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_HYGON, ++ .family = 24, ++ .model = 7, ++ .stepping = 0, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | ++ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | ++ CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | ++ CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB | ++ CPUID_8000_0008_EBX_IBRS | CPUID_8000_0008_EBX_STIBP | ++ CPUID_8000_0008_EBX_AMD_SSBD, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | ++ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_AVX512F | ++ CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_RDSEED | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA | ++ CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | ++ CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | ++ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, ++ .features[FEAT_7_0_ECX] = ++ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | ++ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | ++ CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | ++ CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | ++ CPUID_7_0_ECX_AVX512_VPOPCNTDQ, ++ .features[FEAT_7_1_EAX] = ++ CPUID_7_1_EAX_AVX512_BF16, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .features[FEAT_SVM] = ++ CPUID_SVM_NPT | CPUID_SVM_NRIPSAVE, ++ .xlevel = 0x80000020, ++ .model_id = "Hygon Chengdu Processor", ++ .cache_info = &dharma_cache_info, ++ }, + }; + + /* +-- +2.33.0 + -- Gitee From f647a4256ae0289caaf138ad1af1eb394d2cb41a Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Tue, 26 Aug 2025 16:08:03 +0800 Subject: [PATCH 03/14] QEMU update to version 8.2.0-39: Signed-off-by: zhangpengrui --- Bugfix-Fix-compile-error-in-aarch32.patch | 28 + ...ack-whether-guest-state-is-encrypted.patch | 122 ++ On-the-Adaptation-of-CCA-and-virtCCA.patch | 134 ++ ...mware.json-Add-arm-rme-firmware-feat.patch | 53 + hw-acpi-Fix-the-memory-leak-issue.patch | 50 + ...-Load-DTB-as-is-for-confidential-VMs.patch | 41 + ...t-Mark-all-guest-memory-as-RIPAS_RAM.patch | 39 + ...p-bootloader-for-confidential-guests.patch | 117 ++ ...measurement-log-for-confidential-boo.patch | 186 +++ hw-arm-virt-Add-support-for-Arm-RME.patch | 78 ++ ...ble-DTB-randomness-for-confidential-.patch | 175 +++ ...e-virt_flash_create-to-machvirt_init.patch | 46 + ...rve-one-bit-of-guest-physical-addres.patch | 66 + ...RAM-instead-of-flash-for-confidentia.patch | 110 ++ hw-core-loader-Add-ROM-loader-notifier.patch | 96 ++ ...loader-Add-fields-to-RomLoaderNotify.patch | 48 + ...gem-fix-register-mask-initialization.patch | 49 + hw-tpm-Add-TPM-event-log.patch | 507 ++++++++ ...ct.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch | 249 ++++ ...m_vm_check_extension-where-necessary.patch | 86 ++ ...d-KVM-Arm-RME-definitions-to-Linux-h.patch | 178 +++ ...tifyStateClear-definition-to-return-.patch | 84 ++ ...mory_region_set_ram_discard_manager-.patch | 140 ++ ...helper-to-get-intersection-of-a-Memo.patch | 142 ++ ...-PrivateSharedManager-Interface-as-c.patch | 152 +++ ...-generic-state-change-parent-class-f.patch | 1145 +++++++++++++++++ ...-definiton-of-ReplayRamPopulate-and-.patch | 222 ++++ qemu.spec | 151 ++- ...ute-Add-priority-listener-support-fo.patch | 99 ++ ...t-arm-Add-confidential-guest-support.patch | 124 ++ ...nform-about-reading-confidential-CPU.patch | 37 + ...pu-Set-number-of-PMU-counters-in-KVM.patch | 193 +++ ...et-number-of-breakpoints-and-watchpo.patch | 253 ++++ ...reate-scratch-VM-as-Realm-if-necessa.patch | 47 + ...eturn-immediately-on-error-in-kvm_ar.patch | 77 ++ ...kvm-Split-kvm_arch_get-put_registers.patch | 85 ++ ...me-Add-DMA-remapping-for-the-shared-.patch | 363 ++++++ ...me-Add-Realm-Personalization-Value-p.patch | 190 +++ ...me-Add-measurement-algorithm-propert.patch | 158 +++ target-arm-kvm-rme-Add-measurement-log.patch | 636 +++++++++ ...-arm-kvm-rme-Initialize-Realm-memory.patch | 236 ++++ target-arm-kvm-rme-Initialize-realm.patch | 272 ++++ target-arm-kvm-rme-Initialize-vCPU.patch | 191 +++ ...port-for-PrivateSharedManager-Interf.patch | 254 ++++ ...io-net-Fix-num_buffers-for-version-1.patch | 41 + 45 files changed, 7749 insertions(+), 1 deletion(-) create mode 100644 Bugfix-Fix-compile-error-in-aarch32.patch create mode 100644 KVM-track-whether-guest-state-is-encrypted.patch create mode 100644 On-the-Adaptation-of-CCA-and-virtCCA.patch create mode 100644 docs-interop-firmware.json-Add-arm-rme-firmware-feat.patch create mode 100644 hw-acpi-Fix-the-memory-leak-issue.patch create mode 100644 hw-arm-boot-Load-DTB-as-is-for-confidential-VMs.patch create mode 100644 hw-arm-boot-Mark-all-guest-memory-as-RIPAS_RAM.patch create mode 100644 hw-arm-boot-Skip-bootloader-for-confidential-guests.patch create mode 100644 hw-arm-virt-Add-measurement-log-for-confidential-boo.patch create mode 100644 hw-arm-virt-Add-support-for-Arm-RME.patch create mode 100644 hw-arm-virt-Disable-DTB-randomness-for-confidential-.patch create mode 100644 hw-arm-virt-Move-virt_flash_create-to-machvirt_init.patch create mode 100644 hw-arm-virt-Reserve-one-bit-of-guest-physical-addres.patch create mode 100644 hw-arm-virt-Use-RAM-instead-of-flash-for-confidentia.patch create mode 100644 hw-core-loader-Add-ROM-loader-notifier.patch create mode 100644 hw-core-loader-Add-fields-to-RomLoaderNotify.patch create mode 100644 hw-net-cadence_gem-fix-register-mask-initialization.patch create mode 100644 hw-tpm-Add-TPM-event-log.patch create mode 100644 include-qom-object.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch create mode 100644 kvm-Use-kvm_vm_check_extension-where-necessary.patch create mode 100644 linux-headers-Add-KVM-Arm-RME-definitions-to-Linux-h.patch create mode 100644 memory-Change-NotifyStateClear-definition-to-return-.patch create mode 100644 memory-Change-memory_region_set_ram_discard_manager-.patch create mode 100644 memory-Export-a-helper-to-get-intersection-of-a-Memo.patch create mode 100644 memory-Introduce-PrivateSharedManager-Interface-as-c.patch create mode 100644 memory-Introduce-generic-state-change-parent-class-f.patch create mode 100644 memory-Unify-the-definiton-of-ReplayRamPopulate-and-.patch create mode 100644 ram-block-attribute-Add-priority-listener-support-fo.patch create mode 100644 target-arm-Add-confidential-guest-support.patch create mode 100644 target-arm-cpu-Inform-about-reading-confidential-CPU.patch create mode 100644 target-arm-cpu-Set-number-of-PMU-counters-in-KVM.patch create mode 100644 target-arm-cpu-Set-number-of-breakpoints-and-watchpo.patch create mode 100644 target-arm-kvm-Create-scratch-VM-as-Realm-if-necessa.patch create mode 100644 target-arm-kvm-Return-immediately-on-error-in-kvm_ar.patch create mode 100644 target-arm-kvm-Split-kvm_arch_get-put_registers.patch create mode 100644 target-arm-kvm-rme-Add-DMA-remapping-for-the-shared-.patch create mode 100644 target-arm-kvm-rme-Add-Realm-Personalization-Value-p.patch create mode 100644 target-arm-kvm-rme-Add-measurement-algorithm-propert.patch create mode 100644 target-arm-kvm-rme-Add-measurement-log.patch create mode 100644 target-arm-kvm-rme-Initialize-Realm-memory.patch create mode 100644 target-arm-kvm-rme-Initialize-realm.patch create mode 100644 target-arm-kvm-rme-Initialize-vCPU.patch create mode 100644 vfio-Add-the-support-for-PrivateSharedManager-Interf.patch create mode 100644 virtio-net-Fix-num_buffers-for-version-1.patch diff --git a/Bugfix-Fix-compile-error-in-aarch32.patch b/Bugfix-Fix-compile-error-in-aarch32.patch new file mode 100644 index 00000000..0d49dfd1 --- /dev/null +++ b/Bugfix-Fix-compile-error-in-aarch32.patch @@ -0,0 +1,28 @@ +From 15bdaa95d03419ba00c34fe3249c8ab50faee9de Mon Sep 17 00:00:00 2001 +From: yxk +Date: Fri, 22 Aug 2025 02:34:27 +0800 +Subject: [PATCH] Bugfix: Fix compile error in aarch32. + +Add definition of virtcca_cvm_allowed in include/sysemu/kvm.h when +CONFIG_KVM_IS_POSSIBLE in disable. + +Signed-off-by: yxk +--- + include/sysemu/kvm.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 5f3f779de4..7602cd4429 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -180,6 +180,7 @@ extern bool kvm_csv3_allowed; + #define kvm_msi_devid_required() (false) + #define kvm_csv3_enabled() (false) + #define kvm_csv3_should_set_priv_mem() (false) ++extern bool virtcca_cvm_allowed; + + #endif /* CONFIG_KVM_IS_POSSIBLE */ + +-- +2.33.0 + diff --git a/KVM-track-whether-guest-state-is-encrypted.patch b/KVM-track-whether-guest-state-is-encrypted.patch new file mode 100644 index 00000000..32a63355 --- /dev/null +++ b/KVM-track-whether-guest-state-is-encrypted.patch @@ -0,0 +1,122 @@ +From 98c7d031289a52028656a64bd393a5b959209e19 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Mon, 18 Mar 2024 14:41:10 -0400 +Subject: [PATCH] KVM: track whether guest state is encrypted +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://gitlab.com/qemu-project/qemu/-/commit/5c3131c392f84c660033d511ec39872d8beb4b1e + +So far, KVM has allowed KVM_GET/SET_* ioctls to execute even if the +guest state is encrypted, in which case they do nothing. For the new +API using VM types, instead, the ioctls will fail which is a safer and +more robust approach. + +The new API will be the only one available for SEV-SNP and TDX, but it +is also usable for SEV and SEV-ES. In preparation for that, require +architecture-specific KVM code to communicate the point at which guest +state is protected (which must be after kvm_cpu_synchronize_post_init(), +though that might change in the future in order to suppor migration). +From that point, skip reading registers so that cpu->vcpu_dirty is +never true: if it ever becomes true, kvm_arch_put_registers() will +fail miserably. + +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Paolo Bonzini +Conflicts: + include/sysemu/kvm.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + accel/kvm/kvm-all.c | 17 ++++++++++++++--- + include/sysemu/kvm.h | 3 +++ + include/sysemu/kvm_int.h | 1 + + target/i386/sev.c | 1 + + 4 files changed, 19 insertions(+), 3 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 2cdd615025..50047b9b71 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2782,7 +2782,7 @@ bool kvm_cpu_check_are_resettable(void) + + static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) + { +- if (!cpu->vcpu_dirty) { ++ if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) { + int ret = kvm_arch_get_registers(cpu); + if (ret) { + error_report("Failed to get registers: %s", strerror(-ret)); +@@ -2796,7 +2796,7 @@ static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) + + void kvm_cpu_synchronize_state(CPUState *cpu) + { +- if (!cpu->vcpu_dirty) { ++ if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) { + run_on_cpu(cpu, do_kvm_cpu_synchronize_state, RUN_ON_CPU_NULL); + } + } +@@ -2831,7 +2831,13 @@ static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) + + void kvm_cpu_synchronize_post_init(CPUState *cpu) + { +- run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL); ++ if (!kvm_state->guest_state_protected) { ++ /* ++ * This runs before the machine_init_done notifiers, and is the last ++ * opportunity to synchronize the state of confidential guests. ++ */ ++ run_on_cpu(cpu, do_kvm_cpu_synchronize_post_init, RUN_ON_CPU_NULL); ++ } + } + + static void do_kvm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg) +@@ -4223,3 +4229,8 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp) + query_stats_schema_vcpu(first_cpu, &stats_args); + } + } ++ ++void kvm_mark_guest_state_protected(void) ++{ ++ kvm_state->guest_state_protected = true; ++} +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index 098257e72f..5f3f779de4 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -604,4 +604,7 @@ int kvm_load_user_data(hwaddr loader_start, hwaddr image_end, hwaddr initrd_star + int kvm_create_shadow_device(PCIDevice *dev); + int kvm_delete_shadow_device(PCIDevice *dev); + #endif ++ ++void kvm_mark_guest_state_protected(void); ++ + #endif +diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h +index b2d2c59477..9a7bc1a4b8 100644 +--- a/include/sysemu/kvm_int.h ++++ b/include/sysemu/kvm_int.h +@@ -87,6 +87,7 @@ struct KVMState + bool kernel_irqchip_required; + OnOffAuto kernel_irqchip_split; + bool sync_mmu; ++ bool guest_state_protected; + uint64_t manual_dirty_log_protect; + /* The man page (and posix) say ioctl numbers are signed int, but + * they're not. Linux, glibc and *BSD all treat ioctl numbers as +diff --git a/target/i386/sev.c b/target/i386/sev.c +index b4b42fd716..8c1f4d653e 100644 +--- a/target/i386/sev.c ++++ b/target/i386/sev.c +@@ -936,6 +936,7 @@ sev_launch_get_measure(Notifier *notifier, void *unused) + if (ret) { + exit(1); + } ++ kvm_mark_guest_state_protected(); + } + + /* query the measurement blob length */ +-- +2.33.0 + diff --git a/On-the-Adaptation-of-CCA-and-virtCCA.patch b/On-the-Adaptation-of-CCA-and-virtCCA.patch new file mode 100644 index 00000000..e7102a97 --- /dev/null +++ b/On-the-Adaptation-of-CCA-and-virtCCA.patch @@ -0,0 +1,134 @@ +From 7916c32580dd8e887466fe597ba64dc6e212685f Mon Sep 17 00:00:00 2001 +From: yxk +Date: Wed, 16 Jul 2025 18:47:39 +0800 +Subject: [PATCH] On the Adaptation of CCA and virtCCA. + +We modified virtCCA to use the same Macros as CCA, but did not +change the values of these Macros to keep it compact. + +Signed-off-by: yxk +--- + accel/kvm/kvm-all.c | 4 ---- + hw/arm/virt.c | 1 + + linux-headers/asm-arm64/kvm.h | 3 +-- + linux-headers/linux/kvm.h | 4 +--- + target/arm/kvm-tmm.c | 12 ++++++------ + 5 files changed, 9 insertions(+), 15 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 50047b9b71..f472fc4f69 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2491,10 +2491,6 @@ static int kvm_init(MachineState *ms) + goto err; + } + +- if (kvm_is_virtcca_cvm_type(type)) { +- virtcca_cvm_allowed = true; +- } +- + do { + ret = kvm_ioctl(s, KVM_CREATE_VM, type); + } while (ret == -EINTR); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 52789a3782..f12bc645d2 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -3876,6 +3876,7 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + + if (!strcmp(kvm_type, "cvm")) { + virtcca_cvm_type = VIRTCCA_CVM_TYPE; ++ virtcca_cvm_allowed = true; + } + } + int rme_vm_type = kvm_arm_rme_vm_type(ms), type; +diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h +index aed56ef371..777b668851 100644 +--- a/linux-headers/asm-arm64/kvm.h ++++ b/linux-headers/asm-arm64/kvm.h +@@ -110,9 +110,8 @@ struct kvm_regs { + #define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */ + #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ + #define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */ +-#define KVM_ARM_VCPU_TEC 8 /* VCPU TEC state as part of cvm */ ++#define KVM_ARM_VCPU_REC 8 /* VCPU REC state as part of Realm */ + #define KVM_ARM_VCPU_HAS_EL2_E2H0 9 /* Limit NV support to E2H RES0 */ +-#define KVM_ARM_VCPU_REC 10 /* VCPU REC state as part of Realm */ + + struct kvm_vcpu_init { + __u32 target; +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index beb41f7433..96bc60475e 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -1218,9 +1218,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 + #define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230 + #define KVM_CAP_ARM_WRITABLE_IMP_ID_REGS 239 +-#define KVM_CAP_ARM_RME 240 +- +-#define KVM_CAP_ARM_TMM 300 ++#define KVM_CAP_ARM_RME 300 + + #define KVM_CAP_SEV_ES_GHCB 500 + #define KVM_CAP_HYGON_COCO_EXT 501 +diff --git a/target/arm/kvm-tmm.c b/target/arm/kvm-tmm.c +index d18ac10896..d6dc8342c4 100644 +--- a/target/arm/kvm-tmm.c ++++ b/target/arm/kvm-tmm.c +@@ -118,7 +118,7 @@ static int tmm_configure_one(TmmGuest *guest, uint32_t cfg, Error **errp) + g_assert_not_reached(); + } + +- ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_TMM, 0, ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_TMM_CONFIG_CVM, (intptr_t)&args); + if (ret) { + error_setg_errno(errp, -ret, "TMM: failed to configure %s", cfg_str); +@@ -167,7 +167,7 @@ static void tmm_populate_region(gpointer data, gpointer unused) + return; + } + +- ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_TMM, 0, ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_TMM_POPULATE_CVM, + (intptr_t)&populate_args); + if (ret) { +@@ -179,7 +179,7 @@ static void tmm_populate_region(gpointer data, gpointer unused) + + static int tmm_create_rd(Error **errp) + { +- int ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_TMM, 0, ++ int ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_TMM_CREATE_RD); + if (ret) { + error_setg_errno(errp, -ret, "TMM: failed to create tmm Descriptor"); +@@ -200,14 +200,14 @@ static void tmm_vm_state_change(void *opaque, bool running, RunState state) + g_slist_free_full(g_steal_pointer(&tmm_guest->ram_regions), g_free); + + CPU_FOREACH(cs) { +- ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_TEC); ++ ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_REC); + if (ret) { + error_report("TMM: failed to finalize vCPU: %s", strerror(-ret)); + exit(1); + } + } + +- ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_TMM, 0, ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_TMM_ACTIVATE_CVM); + if (ret) { + error_report("TMM: failed to activate cvm: %s", strerror(-ret)); +@@ -224,7 +224,7 @@ int kvm_arm_tmm_init(ConfidentialGuestSupport *cgs, Error **errp) + return -ENODEV; + } + +- if (!kvm_check_extension(kvm_state, KVM_CAP_ARM_TMM)) { ++ if (!kvm_check_extension(kvm_state, KVM_CAP_ARM_RME)) { + error_setg(errp, "KVM does not support TMM"); + return -ENODEV; + } +-- +2.33.0 + diff --git a/docs-interop-firmware.json-Add-arm-rme-firmware-feat.patch b/docs-interop-firmware.json-Add-arm-rme-firmware-feat.patch new file mode 100644 index 00000000..abfcc38c --- /dev/null +++ b/docs-interop-firmware.json-Add-arm-rme-firmware-feat.patch @@ -0,0 +1,53 @@ +From e8055696aa1d0ee3fab298fb3605473f285c9cc6 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 16 Apr 2025 13:40:08 +0100 +Subject: [PATCH] docs/interop/firmware.json: Add arm-rme firmware feature + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/b547ad23843a33030968a51e547d0e2ff875086b + +Some distributions provide packages continaing firmware to be run under +QEMU, such as "qemu-efi-aarch64" or "edk2-aarch64". Those packages also +contain descriptors in /usr/share/qemu/firmware/*.json listing the +firmware features, so that environments like libvirt can figure out +which firmware they can load. + +Define an optional feature for arm64 firmware to indicate that a +firmware supports running in a Realm. Firmware implementations need +extra support for running in a Realm, in particular to distinguish +shared from private guest memory. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + docs/interop/firmware.json +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + docs/interop/firmware.json | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json +index cc8f869186..08c2fbabe7 100644 +--- a/docs/interop/firmware.json ++++ b/docs/interop/firmware.json +@@ -127,6 +127,9 @@ + # options related to this feature are documented in + # "docs/system/i386/amd-memory-encryption.rst". + # ++# @arm-rme: The firmware supports running in a Realm, under the Arm Realm ++# Management Extension (RME). ++# + # @intel-tdx: The firmware supports running under Intel Trust Domain + # Extensions (TDX). + # +@@ -196,7 +199,7 @@ + { 'enum' : 'FirmwareFeature', + 'data' : [ 'acpi-s3', 'acpi-s4', + 'amd-sev', 'amd-sev-es', 'amd-sev-snp', +- 'intel-tdx', ++ 'arm-rme', 'intel-tdx', + 'enrolled-keys', 'requires-smm', 'secure-boot', + 'verbose-dynamic', 'verbose-static' ] } + +-- +2.33.0 + diff --git a/hw-acpi-Fix-the-memory-leak-issue.patch b/hw-acpi-Fix-the-memory-leak-issue.patch new file mode 100644 index 00000000..614f0300 --- /dev/null +++ b/hw-acpi-Fix-the-memory-leak-issue.patch @@ -0,0 +1,50 @@ +From 569786d7c883154effcb215bd74f30f680f9e540 Mon Sep 17 00:00:00 2001 +From: Xianglai Li +Date: Wed, 30 Jul 2025 16:03:57 +0800 +Subject: [PATCH] hw/acpi: Fix the memory leak issue + +During the creation process of the acpi ged device, +the function cpu_hotplug_hw_init was wrongly called multiple times, +resulting in a memory leak. + +Now, delete the redundant calls of the function cpu_hotplug_hw_init +to solve the memory leak problem. + +Fixes: ac96f2161550 ("hw/acpi: Update ACPI GED framework to support vCPU Hotplug") +Fixes: 6e17d32d6df2 ("acpi/ged: Init cpu hotplug only when machine support it") +Signed-off-by: Xianglai Li +--- + hw/acpi/generic_event_device.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c +index 755653dc26..61a4c9e643 100644 +--- a/hw/acpi/generic_event_device.c ++++ b/hw/acpi/generic_event_device.c +@@ -439,7 +439,6 @@ static void acpi_ged_initfn(Object *obj) + AcpiGedState *s = ACPI_GED(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + GEDState *ged_st = &s->ged_state; +- MachineClass *mc; + + memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st, + TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN); +@@ -463,15 +462,6 @@ static void acpi_ged_initfn(Object *obj) + memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st, + TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT); + sysbus_init_mmio(sbd, &ged_st->regs); +- +- mc = MACHINE_GET_CLASS(qdev_get_machine()); +- if (mc->possible_cpu_arch_ids) { +- memory_region_init(&s->container_cpuhp, OBJECT(dev), "cpuhp container", +- ACPI_CPU_HOTPLUG_REG_LEN); +- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container_cpuhp); +- cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev), +- &s->cpuhp_state, 0); +- } + } + + static void acpi_ged_class_init(ObjectClass *class, void *data) +-- +2.33.0 + diff --git a/hw-arm-boot-Load-DTB-as-is-for-confidential-VMs.patch b/hw-arm-boot-Load-DTB-as-is-for-confidential-VMs.patch new file mode 100644 index 00000000..4798f129 --- /dev/null +++ b/hw-arm-boot-Load-DTB-as-is-for-confidential-VMs.patch @@ -0,0 +1,41 @@ +From ac5a8a0a35b5f41a2b86f5b0681519123dc7da57 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 21 Feb 2024 13:58:14 +0000 +Subject: [PATCH] hw/arm/boot: Load DTB as is for confidential VMs + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/2c85282f4b10b301880b5067834ef83ad368d50a + +For confidential VMs it may be necessary to measure the DTB, to ensure a +malicious host does not insert harmful information in there. In case an +external tool can generated and measured the DTB, load it as is without +patching it. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/arm/boot.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 1e931d91d3..e2fbde1699 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -527,7 +527,14 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, + char **node_path; + Error *err = NULL; + +- if (binfo->dtb_filename) { ++ if (binfo->dtb_filename && binfo->confidential) { ++ /* ++ * If the user is providing a DTB for a confidential VM, it is already ++ * tailored to this configuration and measured. Load it as is, without ++ * any modification. ++ */ ++ return rom_add_file_fixed_as(binfo->dtb_filename, addr, -1, as); ++ } else if (binfo->dtb_filename) { + char *filename; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename); + if (!filename) { +-- +2.33.0 + diff --git a/hw-arm-boot-Mark-all-guest-memory-as-RIPAS_RAM.patch b/hw-arm-boot-Mark-all-guest-memory-as-RIPAS_RAM.patch new file mode 100644 index 00000000..06774e77 --- /dev/null +++ b/hw-arm-boot-Mark-all-guest-memory-as-RIPAS_RAM.patch @@ -0,0 +1,39 @@ +From 080ba1535c68e2d819dc8e7597aa941f478d0296 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 14 Jun 2023 16:36:52 +0100 +Subject: [PATCH] hw/arm/boot: Mark all guest memory as RIPAS_RAM. + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/7dd79c57dd097f2de2cb4c3ce428dad78ca452f3 + +All Realm IPA states are by default RIPAS_EMPTY, and accessing them in +that state causes injection of synchronous exception. Either the loader +or the guest needs to set IPA state to RIPAS_RAM before accessing it. +Since a Linux guest needs all memory ready at boot [1], initialize it +here. + +[1] https://docs.kernel.org/arch/arm64/booting.html + https://lore.kernel.org/all/20241004144307.66199-12-steven.price@arm.com/ + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/arm/boot.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 9a33601d35..1e931d91d3 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -1330,6 +1330,9 @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info) + } + } + ++ /* Mark all Realm memory as RAM */ ++ kvm_arm_rme_init_guest_ram(info->loader_start, info->ram_size); ++ + /* Load the kernel. */ + if (!info->kernel_filename || info->firmware_loaded) { + arm_setup_firmware_boot(cpu, info, ms->firmware); +-- +2.33.0 + diff --git a/hw-arm-boot-Skip-bootloader-for-confidential-guests.patch b/hw-arm-boot-Skip-bootloader-for-confidential-guests.patch new file mode 100644 index 00000000..40ec5b59 --- /dev/null +++ b/hw-arm-boot-Skip-bootloader-for-confidential-guests.patch @@ -0,0 +1,117 @@ +From 215b18636f45a1ecdad8abba5db383075efa722b Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Fri, 26 Apr 2024 16:11:59 +0100 +Subject: [PATCH] hw/arm/boot: Skip bootloader for confidential guests + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/79359e41a418cffbb2f2ae0314599a29d9f183a7 + +An independent verifier needs to reconstruct the content of guest memory +in order to attest that it is running trusted code. To avoid having to +reconstruct the bootloader generated by QEMU, skip this step and jump +directly to the kernel, with the DTB address in x0 as specified by the +Linux boot protocol [1]. + +[1] https://docs.kernel.org/arch/arm64/booting.html + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/arm/boot.c | 23 +++++++++++++++++------ + hw/arm/virt.c | 1 + + include/hw/arm/boot.h | 6 ++++++ + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index e2fbde1699..6980aebe1e 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -766,7 +766,13 @@ void do_cpu_reset(void *opaque) + if (cs == first_cpu) { + AddressSpace *as = arm_boot_address_space(cpu, info); + +- cpu_set_pc(cs, info->loader_start); ++ if (info->skip_bootloader) { ++ assert(is_a64(env)); ++ env->xregs[0] = info->dtb_start; ++ cpu_set_pc(cs, info->entry); ++ } else { ++ cpu_set_pc(cs, info->loader_start); ++ } + + if (!have_dtb(info)) { + if (old_param) { +@@ -858,7 +864,8 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry, + } + + static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, +- hwaddr *entry, AddressSpace *as) ++ hwaddr *entry, AddressSpace *as, ++ bool skip_bootloader) + { + hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR; + uint64_t kernel_size = 0; +@@ -910,7 +917,8 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, + * bootloader, we can just load it starting at 2MB+offset rather + * than 0MB + offset. + */ +- if (kernel_load_offset < BOOTLOADER_MAX_SIZE) { ++ if (kernel_load_offset < BOOTLOADER_MAX_SIZE && ++ !skip_bootloader) { + kernel_load_offset += 2 * MiB; + } + } +@@ -994,7 +1002,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, + } + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) { + kernel_size = load_aarch64_image(info->kernel_filename, +- info->loader_start, &entry, as); ++ info->loader_start, &entry, as, ++ info->skip_bootloader); + is_linux = 1; + if (kernel_size >= 0) { + image_low_addr = entry; +@@ -1134,8 +1143,10 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, + fixupcontext[FIXUP_ENTRYPOINT_LO] = entry; + fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32; + +- arm_write_bootloader("bootloader", as, info->loader_start, +- primary_loader, fixupcontext); ++ if (!info->skip_bootloader) { ++ arm_write_bootloader("bootloader", as, info->loader_start, ++ primary_loader, fixupcontext); ++ } + + if (info->write_board_setup) { + info->write_board_setup(cpu, info); +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 8423912c89..e6053acec6 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2911,6 +2911,7 @@ static void machvirt_init(MachineState *machine) + vms->bootinfo.confidential = virtcca_cvm_enabled(); + vms->bootinfo.psci_conduit = vms->psci_conduit; + vms->bootinfo.confidential = virt_machine_is_confidential(vms); ++ vms->bootinfo.skip_bootloader = vms->bootinfo.confidential; + arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo); + + vms->machine_done.notify = virt_machine_done; +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index 0cbae4685b..326c92782e 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -137,6 +137,12 @@ struct arm_boot_info { + /* Used when loading firmware into RAM */ + hwaddr firmware_base; + hwaddr firmware_max_size; ++ /* ++ * Instead of starting in a small bootloader that jumps to the kernel, ++ * immediately start in the kernel. ++ */ ++ bool skip_bootloader; ++ + /* + * Confidential guest boot loads everything into RAM so it can be measured. + */ +-- +2.33.0 + diff --git a/hw-arm-virt-Add-measurement-log-for-confidential-boo.patch b/hw-arm-virt-Add-measurement-log-for-confidential-boo.patch new file mode 100644 index 00000000..916d124b --- /dev/null +++ b/hw-arm-virt-Add-measurement-log-for-confidential-boo.patch @@ -0,0 +1,186 @@ +From f22ae2af5af021521084e40c848e5a0505ab7955 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 7 Nov 2024 17:42:02 +0000 +Subject: [PATCH] hw/arm/virt: Add measurement log for confidential boot + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/7905fe583633f1246a50324c77c39026136fac29 + +Create a measurement log describing operations performed by QEMU to +initialize the guest, and load it into guest memory above the DTB. + +Cc: Stefan Berger +Signed-off-by: Jean-Philippe Brucker +Conflicts: + hw/arm/virt.c + include/hw/arm/virt.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/arm/boot.c | 47 +++++++++++++++++++++++++++++++++++++++++++ + hw/arm/virt.c | 22 ++++++++++++++++++++ + include/hw/arm/boot.h | 3 +++ + include/hw/arm/virt.h | 1 + + 4 files changed, 73 insertions(+) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 6980aebe1e..4f5bf6e77c 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -669,6 +669,24 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, + + fdt_add_psci_node(fdt); + ++ /* Add a reserved-memory node for the event log */ ++ if (binfo->log_size) { ++ char *nodename; ++ ++ qemu_fdt_add_subnode(fdt, "/reserved-memory"); ++ qemu_fdt_setprop_cell(fdt, "/reserved-memory", "#address-cells", 0x2); ++ qemu_fdt_setprop_cell(fdt, "/reserved-memory", "#size-cells", 0x2); ++ qemu_fdt_setprop(fdt, "/reserved-memory", "ranges", NULL, 0); ++ ++ nodename = g_strdup_printf("/reserved-memory/event-log@%" PRIx64, ++ binfo->log_paddr); ++ qemu_fdt_add_subnode(fdt, nodename); ++ qemu_fdt_setprop_string(fdt, nodename, "compatible", "cc-event-log"); ++ qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", 2, binfo->log_paddr, ++ 2, binfo->log_size); ++ g_free(nodename); ++ } ++ + if (binfo->modify_dtb) { + binfo->modify_dtb(binfo, fdt); + } +@@ -941,6 +959,30 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, + return kernel_size; + } + ++static void add_event_log(struct arm_boot_info *info) ++{ ++ if (!info->log_size) { ++ return; ++ } ++ ++ if (!info->dtb_limit) { ++ int dtb_size = 0; ++ ++ if (!info->get_dtb(info, &dtb_size) || dtb_size == 0) { ++ error_report("Board does not have a DTB"); ++ exit(1); ++ } ++ info->dtb_limit = info->dtb_start + dtb_size; ++ } ++ ++ info->log_paddr = info->dtb_limit; ++ if (info->log_paddr + info->log_size > ++ info->loader_start + info->ram_size) { ++ error_report("Not enough space for measurement log and DTB"); ++ exit(1); ++ } ++} ++ + static void arm_setup_direct_kernel_boot(ARMCPU *cpu, + struct arm_boot_info *info) + { +@@ -988,6 +1030,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, + } + info->dtb_start = info->loader_start; + info->dtb_limit = image_low_addr; ++ add_event_log(info); + } + } + entry = elf_entry; +@@ -1126,6 +1169,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, + error_report("Not enough space for DTB after kernel/initrd"); + exit(1); + } ++ add_event_log(info); ++ + fixupcontext[FIXUP_ARGPTR_LO] = info->dtb_start; + fixupcontext[FIXUP_ARGPTR_HI] = info->dtb_start >> 32; + } else { +@@ -1212,6 +1257,8 @@ static void arm_setup_confidential_firmware_boot(ARMCPU *cpu, + error_report("could not load firmware '%s'", firmware_filename); + exit(EXIT_FAILURE); + } ++ ++ add_event_log(info); + } + + static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info, const char *firmware_filename) +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index e6053acec6..52789a3782 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1989,6 +1989,11 @@ void virt_machine_done(Notifier *notifier, void *data) + exit(1); + } + ++ if (vms->event_log) { ++ object_property_set_uint(vms->event_log, "load-addr", ++ vms->bootinfo.log_paddr, &error_fatal); ++ } ++ + fw_cfg_add_extra_pci_roots(vms->bus, vms->fw_cfg); + + virt_acpi_setup(vms); +@@ -2398,6 +2403,21 @@ static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem) + } + } + ++static void create_measurement_log(VirtMachineState *vms) ++{ ++ Error *err = NULL; ++ ++ vms->event_log = kvm_arm_rme_get_measurement_log(); ++ if (vms->event_log == NULL) { ++ return; ++ } ++ vms->bootinfo.log_size = object_property_get_uint(vms->event_log, ++ "max-size", &err); ++ if (err != NULL) { ++ error_report_err(err); ++ } ++} ++ + static void virt_cpu_set_properties(Object *cpuobj, const CPUArchId *cpu_slot, + Error **errp) + { +@@ -2900,6 +2920,8 @@ static void machvirt_init(MachineState *machine) + + kvm_arm_rme_init_gpa_space(vms->highest_gpa, vms->bus); + ++ create_measurement_log(vms); ++ + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index 326c92782e..8fed25706b 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -147,6 +147,9 @@ struct arm_boot_info { + * Confidential guest boot loads everything into RAM so it can be measured. + */ + bool confidential; ++ /* measurement log location in guest memory */ ++ hwaddr log_paddr; ++ size_t log_size; + }; + + /** +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 9b43e72aac..fee7c27e0c 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -254,6 +254,7 @@ struct VirtMachineState { + char *oem_table_id; + char *kvm_type; + NotifierList cpuhp_notifiers; ++ Object *event_log; + }; + + #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) +-- +2.33.0 + diff --git a/hw-arm-virt-Add-support-for-Arm-RME.patch b/hw-arm-virt-Add-support-for-Arm-RME.patch new file mode 100644 index 00000000..bbc4c3d6 --- /dev/null +++ b/hw-arm-virt-Add-support-for-Arm-RME.patch @@ -0,0 +1,78 @@ +From 8f73dd3647c1ea8255c3fbd809ded08d30cbe746 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 6 Feb 2023 16:49:25 +0000 +Subject: [PATCH] hw/arm/virt: Add support for Arm RME + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/6e0e9f49e9bdf22e4bd06d3506b9abc63c927b85 + +When confidential-guest-support is enabled for the virt machine, add the +RME flag to the VM type. + +The HVC conduit for PSCI is not supported for Realms. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + hw/arm/virt.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/arm/virt.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index a43f18020c..ec4faab9dc 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -260,6 +260,11 @@ static bool cpu_type_valid(const char *cpu) + return false; + } + ++static bool virt_machine_is_confidential(VirtMachineState *vms) ++{ ++ return MACHINE(vms)->cgs; ++} ++ + static void create_randomness(MachineState *ms, const char *node) + { + struct { +@@ -2610,10 +2615,12 @@ static void machvirt_init(MachineState *machine) + * if the guest has EL2 then we will use SMC as the conduit, + * and otherwise we will use HVC (for backwards compatibility and + * because if we're using KVM then we must use HVC). ++ * Realm guests must also use SMC. + */ + if (vms->secure && firmware_loaded) { + vms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED; +- } else if (vms->virt || virtcca_cvm_enabled()) { ++ } else if (vms->virt || virtcca_cvm_enabled() || ++ virt_machine_is_confidential(vms)) { + vms->psci_conduit = QEMU_PSCI_CONDUIT_SMC; + } else { + vms->psci_conduit = QEMU_PSCI_CONDUIT_HVC; +@@ -3813,6 +3820,7 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + virtcca_cvm_type = VIRTCCA_CVM_TYPE; + } + } ++ int rme_vm_type = kvm_arm_rme_vm_type(ms), type; + int max_vm_pa_size, requested_pa_size; + bool fixed_ipa; + +@@ -3842,9 +3850,12 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + * the implicit legacy 40b IPA setting, in which case the kvm_type + * must be 0. + */ +- return strcmp(type_str, "cvm") == 0 ? +- ((fixed_ipa ? 0 : requested_pa_size) | virtcca_cvm_type) : +- (fixed_ipa ? 0 : requested_pa_size); ++ type = strcmp(type_str, "cvm") == 0 ? virtcca_cvm_type : 0; ++ if (fixed_ipa) { ++ return type; ++ } ++ ++ return requested_pa_size | rme_vm_type | type; + } + + static void virt_machine_class_init(ObjectClass *oc, void *data) +-- +2.33.0 + diff --git a/hw-arm-virt-Disable-DTB-randomness-for-confidential-.patch b/hw-arm-virt-Disable-DTB-randomness-for-confidential-.patch new file mode 100644 index 00000000..061fdf5c --- /dev/null +++ b/hw-arm-virt-Disable-DTB-randomness-for-confidential-.patch @@ -0,0 +1,175 @@ +From 8796ed125a4e424df483e2059eab2b4fa7f88f8d Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 6 Feb 2023 16:52:37 +0000 +Subject: [PATCH] hw/arm/virt: Disable DTB randomness for confidential VMs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/68a0501d8fbf67b2828c262e8aa296820a1b32a1 + +The dtb-randomness feature, which adds random seeds to the DTB, isn't +really compatible with confidential VMs since it randomizes the Realm +Initial Measurement. Enabling it is not an error, but it prevents +attestation. It also isn't useful to a Realm, which doesn't trust host +input. + +Currently the feature is automatically enabled, unless the user disables +it on the command-line. Change it to OnOffAuto, and automatically +disable it for confidential VMs, unless the user explicitly enables it. + +Signed-off-by: Jean-Philippe Brucker +Reviewed-by: Philippe Mathieu-Daudé +Conflicts: + hw/arm/virt.c + include/hw/arm/virt.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + docs/system/arm/virt.rst | 9 +++++---- + hw/arm/virt.c | 41 +++++++++++++++++++++++++--------------- + include/hw/arm/virt.h | 2 +- + 3 files changed, 32 insertions(+), 20 deletions(-) + +diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst +index 7c4c80180c..0ba6d8610f 100644 +--- a/docs/system/arm/virt.rst ++++ b/docs/system/arm/virt.rst +@@ -153,10 +153,11 @@ dtb-randomness + rng-seed and kaslr-seed nodes (in both "/chosen" and + "/secure-chosen") to use for features like the random number + generator and address space randomisation. The default is +- ``on``. You will want to disable it if your trusted boot chain +- will verify the DTB it is passed, since this option causes the +- DTB to be non-deterministic. It would be the responsibility of +- the firmware to come up with a seed and pass it on if it wants to. ++ ``off`` for confidential VMs, and ``on`` otherwise. You will want ++ to disable it if your trusted boot chain will verify the DTB it is ++ passed, since this option causes the DTB to be non-deterministic. ++ It would be the responsibility of the firmware to come up with a ++ seed and pass it on if it wants to. + + dtb-kaslr-seed + A deprecated synonym for dtb-randomness. +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index ec4faab9dc..66d2d68944 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -281,6 +281,7 @@ static void create_randomness(MachineState *ms, const char *node) + + static void create_fdt(VirtMachineState *vms) + { ++ bool dtb_randomness = true; + MachineState *ms = MACHINE(vms); + int nb_numa_nodes = ms->numa_state->num_nodes; + void *fdt = create_device_tree(&vms->fdt_size); +@@ -290,6 +291,16 @@ static void create_fdt(VirtMachineState *vms) + exit(1); + } + ++ /* ++ * Including random data in the DTB causes random intial measurement on CCA, ++ * so disable it for confidential VMs. ++ */ ++ if (vms->dtb_randomness == ON_OFF_AUTO_OFF || ++ (vms->dtb_randomness == ON_OFF_AUTO_AUTO && ++ virt_machine_is_confidential(vms))) { ++ dtb_randomness = false; ++ } ++ + ms->fdt = fdt; + + /* Header */ +@@ -306,7 +317,7 @@ static void create_fdt(VirtMachineState *vms) + kvm_type = object_property_get_str(OBJECT(current_machine), + "kvm-type", &error_abort); + } +- if (vms->dtb_randomness) { ++ if (dtb_randomness) { + if (!(kvm_type && !strcmp(kvm_type, "cvm"))) { + create_randomness(ms, "/chosen"); + } +@@ -314,7 +325,7 @@ static void create_fdt(VirtMachineState *vms) + + if (vms->secure) { + qemu_fdt_add_subnode(fdt, "/secure-chosen"); +- if (vms->dtb_randomness) { ++ if (dtb_randomness) { + create_randomness(ms, "/secure-chosen"); + } + } +@@ -2998,18 +3009,21 @@ static void virt_set_its(Object *obj, bool value, Error **errp) + vms->its = value; + } + +-static bool virt_get_dtb_randomness(Object *obj, Error **errp) ++static void virt_get_dtb_randomness(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) + { + VirtMachineState *vms = VIRT_MACHINE(obj); ++ OnOffAuto dtb_randomness = vms->dtb_randomness; + +- return vms->dtb_randomness; ++ visit_type_OnOffAuto(v, name, &dtb_randomness, errp); + } + +-static void virt_set_dtb_randomness(Object *obj, bool value, Error **errp) ++static void virt_set_dtb_randomness(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) + { + VirtMachineState *vms = VIRT_MACHINE(obj); + +- vms->dtb_randomness = value; ++ visit_type_OnOffAuto(v, name, &vms->dtb_randomness, errp); + } + + static char *virt_get_oem_id(Object *obj, Error **errp) +@@ -3996,16 +4010,16 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + "Set on/off to enable/disable " + "ITS instantiation"); + +- object_class_property_add_bool(oc, "dtb-randomness", +- virt_get_dtb_randomness, +- virt_set_dtb_randomness); ++ object_class_property_add(oc, "dtb-randomness", "OnOffAuto", ++ virt_get_dtb_randomness, virt_set_dtb_randomness, ++ NULL, NULL); + object_class_property_set_description(oc, "dtb-randomness", + "Set off to disable passing random or " + "non-deterministic dtb nodes to guest"); + +- object_class_property_add_bool(oc, "dtb-kaslr-seed", +- virt_get_dtb_randomness, +- virt_set_dtb_randomness); ++ object_class_property_add(oc, "dtb-kaslr-seed", "OnOffAuto", ++ virt_get_dtb_randomness, virt_set_dtb_randomness, ++ NULL, NULL); + object_class_property_set_description(oc, "dtb-kaslr-seed", + "Deprecated synonym of dtb-randomness"); + +@@ -4092,9 +4106,6 @@ static void virt_instance_init(Object *obj) + /* MTE is disabled by default. */ + vms->mte = false; + +- /* Supply kaslr-seed and rng-seed by default */ +- vms->dtb_randomness = true; +- + vms->irqmap = a15irqmap; + + virt_flash_create(vms); +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index 3e2759d225..9b43e72aac 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -225,7 +225,7 @@ struct VirtMachineState { + bool cpu_hotplug_enabled; + bool ras; + bool mte; +- bool dtb_randomness; ++ OnOffAuto dtb_randomness; + bool pmu; + int smmu_accel_count; + OnOffAuto acpi; +-- +2.33.0 + diff --git a/hw-arm-virt-Move-virt_flash_create-to-machvirt_init.patch b/hw-arm-virt-Move-virt_flash_create-to-machvirt_init.patch new file mode 100644 index 00000000..13dab3c8 --- /dev/null +++ b/hw-arm-virt-Move-virt_flash_create-to-machvirt_init.patch @@ -0,0 +1,46 @@ +From ddf23b6f58d3c605a083ad3f09388dcb6edf729e Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Fri, 12 Aug 2022 11:53:11 +0100 +Subject: [PATCH] hw/arm/virt: Move virt_flash_create() to machvirt_init() + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/b7d6407b658327eb0be8a3014a63f84f58406043 + +For confidential VMs we'll want to skip flash device creation. +Unfortunately, in virt_instance_init() the machine->cgs member has not +yet been initialized, so we cannot check whether confidential guest is +enabled. Move virt_flash_create() to machvirt_init(), where we can +access the machine->cgs member. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + hw/arm/virt.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/arm/virt.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 95f6acf655..116c3ddbf0 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2572,6 +2572,7 @@ static void machvirt_init(MachineState *machine) + } + + finalize_gic_version(vms); ++ virt_flash_create(vms); + + possible_cpus = mc->possible_cpu_arch_ids(machine); + +@@ -4120,8 +4121,6 @@ static void virt_instance_init(Object *obj) + + vms->irqmap = a15irqmap; + +- virt_flash_create(vms); +- + vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); + vms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); + +-- +2.33.0 + diff --git a/hw-arm-virt-Reserve-one-bit-of-guest-physical-addres.patch b/hw-arm-virt-Reserve-one-bit-of-guest-physical-addres.patch new file mode 100644 index 00000000..342e226d --- /dev/null +++ b/hw-arm-virt-Reserve-one-bit-of-guest-physical-addres.patch @@ -0,0 +1,66 @@ +From 726dbebf1dc71cf4ede0f0bf6ea049639d93c00d Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 6 Feb 2023 16:56:39 +0000 +Subject: [PATCH] hw/arm/virt: Reserve one bit of guest-physical address for + RME + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/ebffee632eb86b3423ac08a264ea0edc5cf97ead + +When RME is enabled, the upper GPA bit is used to distinguish protected +from unprotected addresses. Reserve it when setting up the guest memory +map. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/arm/virt.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 66d2d68944..51f7c940f4 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -3836,14 +3836,24 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + } + int rme_vm_type = kvm_arm_rme_vm_type(ms), type; + int max_vm_pa_size, requested_pa_size; ++ int rme_reserve_bit = 0; + bool fixed_ipa; + +- max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa); ++ if (rme_vm_type) { ++ /* ++ * With RME, the upper GPA bit differentiates Realm from NS memory. ++ * Reserve the upper bit to ensure that highmem devices will fit. ++ */ ++ rme_reserve_bit = 1; ++ } ++ ++ max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms, &fixed_ipa) - ++ rme_reserve_bit; + + /* we freeze the memory map to compute the highest gpa */ + virt_set_memmap(vms, max_vm_pa_size); + +- requested_pa_size = 64 - clz64(vms->highest_gpa); ++ requested_pa_size = 64 - clz64(vms->highest_gpa) + rme_reserve_bit; + + /* + * KVM requires the IPA size to be at least 32 bits. +@@ -3852,11 +3862,11 @@ static int virt_kvm_type(MachineState *ms, const char *type_str) + requested_pa_size = 32; + } + +- if (requested_pa_size > max_vm_pa_size) { ++ if (requested_pa_size > max_vm_pa_size + rme_reserve_bit) { + error_report("-m and ,maxmem option values " + "require an IPA range (%d bits) larger than " + "the one supported by the host (%d bits)", +- requested_pa_size, max_vm_pa_size); ++ requested_pa_size, max_vm_pa_size + rme_reserve_bit); + return -1; + } + /* +-- +2.33.0 + diff --git a/hw-arm-virt-Use-RAM-instead-of-flash-for-confidentia.patch b/hw-arm-virt-Use-RAM-instead-of-flash-for-confidentia.patch new file mode 100644 index 00000000..6c6aea8e --- /dev/null +++ b/hw-arm-virt-Use-RAM-instead-of-flash-for-confidentia.patch @@ -0,0 +1,110 @@ +From 2e0ea64c8643318f8824040b010f0b2421efbd33 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Fri, 12 Aug 2022 12:08:58 +0100 +Subject: [PATCH] hw/arm/virt: Use RAM instead of flash for confidential guest + firmware + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/a8d4685f97e63dac012647cc3f9b1d830b784f8c + +The flash device that holds firmware code relies on read-only stage-2 +mappings. Read accesses behave as RAM and write accesses as MMIO. Since +the RMM does not support read-only mappings we cannot use the flash +device as-is. + +That isn't a problem because the firmware does not want to disclose any +information to the host, hence will not store its variables in clear +persistent memory. We can therefore replace the flash device with RAM, +and load the firmware there. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + hw/arm/boot.c + hw/arm/virt.c + include/hw/arm/boot.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/arm/virt.c | 20 +++++++++++++++++++- + include/hw/arm/boot.h | 5 +++++ + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 116c3ddbf0..8423912c89 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1407,6 +1407,10 @@ static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms, + + static void virt_flash_create(VirtMachineState *vms) + { ++ if (virt_machine_is_confidential(vms)) { ++ return; ++ } ++ + vms->flash[0] = virt_flash_create1(vms, "virt.flash0", "pflash0"); + vms->flash[1] = virt_flash_create1(vms, "virt.flash1", "pflash1"); + } +@@ -1445,6 +1449,10 @@ static void virt_flash_map(VirtMachineState *vms, + hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vms->memmap[VIRT_FLASH].base; + ++ if (virt_machine_is_confidential(vms)) { ++ return; ++ } ++ + virt_flash_map1(vms->flash[0], flashbase, flashsize, + secure_sysmem); + virt_flash_map1(vms->flash[1], flashbase + flashsize, flashsize, +@@ -1460,7 +1468,7 @@ static void virt_flash_fdt(VirtMachineState *vms, + MachineState *ms = MACHINE(vms); + char *nodename; + +- if (virtcca_cvm_enabled()) { ++ if (virtcca_cvm_enabled() || virt_machine_is_confidential(vms)) { + return; + } + +@@ -1524,6 +1532,15 @@ static bool virt_firmware_init(VirtMachineState *vms, + const char *bios_name; + BlockBackend *pflash_blk0; + ++ /* ++ * For a confidential VM, the firmware image and any boot information, ++ * including EFI variables, are stored in RAM in order to be measurable and ++ * private. Create a RAM region and load the firmware image there. ++ */ ++ if (virt_machine_is_confidential(vms)) { ++ return virt_confidential_firmware_init(vms, sysmem); ++ } ++ + /* Map legacy -drive if=pflash to machine properties */ + for (i = 0; i < ARRAY_SIZE(vms->flash); i++) { + pflash_cfi01_legacy_drive(vms->flash[i], +@@ -2893,6 +2910,7 @@ static void machvirt_init(MachineState *machine) + vms->bootinfo.firmware_max_size = vms->memmap[VIRT_FLASH].size; + vms->bootinfo.confidential = virtcca_cvm_enabled(); + vms->bootinfo.psci_conduit = vms->psci_conduit; ++ vms->bootinfo.confidential = virt_machine_is_confidential(vms); + arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo); + + vms->machine_done.notify = virt_machine_done; +diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h +index 06ca1d90b2..0cbae4685b 100644 +--- a/include/hw/arm/boot.h ++++ b/include/hw/arm/boot.h +@@ -133,8 +133,13 @@ struct arm_boot_info { + bool secure_board_setup; + + arm_endianness endianness; ++ ++ /* Used when loading firmware into RAM */ + hwaddr firmware_base; + hwaddr firmware_max_size; ++ /* ++ * Confidential guest boot loads everything into RAM so it can be measured. ++ */ + bool confidential; + }; + +-- +2.33.0 + diff --git a/hw-core-loader-Add-ROM-loader-notifier.patch b/hw-core-loader-Add-ROM-loader-notifier.patch new file mode 100644 index 00000000..b4ce70d0 --- /dev/null +++ b/hw-core-loader-Add-ROM-loader-notifier.patch @@ -0,0 +1,96 @@ +From 9964f1260d5e67c2bc54031136629b10a4d81a2c Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Tue, 13 Jun 2023 18:01:50 +0100 +Subject: [PATCH] hw/core/loader: Add ROM loader notifier + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/4575987ee573474185f8ad8c715dffa9a40494ed + +Add a function to register a notifier, that is invoked after a ROM gets +loaded into guest memory. + +It will be used by Arm confidential guest support, in order to register +all blobs loaded into memory with KVM, so that their content is moved +into Realm state and measured into the initial VM state. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/core/loader.c | 14 ++++++++++++++ + include/hw/loader.h | 15 +++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index e7a9b3775b..1627ef1976 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -67,6 +67,8 @@ + #include + + static int roms_loaded; ++static NotifierList rom_loader_notifier = ++ NOTIFIER_LIST_INITIALIZER(rom_loader_notifier); + + /* return the size or -1 if error */ + int64_t get_image_size(const char *filename) +@@ -1209,6 +1211,11 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, + return mr; + } + ++void rom_add_load_notifier(Notifier *notifier) ++{ ++ notifier_list_add(&rom_loader_notifier, notifier); ++} ++ + /* This function is specific for elf program because we don't need to allocate + * all the rom. We just allocate the first part and the rest is just zeros. This + * is why romsize and datasize are different. Also, this function takes its own +@@ -1250,6 +1257,7 @@ ssize_t rom_add_option(const char *file, int32_t bootindex) + static void rom_reset(void *unused) + { + Rom *rom; ++ RomLoaderNotifyData notify; + + QTAILQ_FOREACH(rom, &roms, next) { + if (rom->fw_file) { +@@ -1298,6 +1306,12 @@ static void rom_reset(void *unused) + cpu_flush_icache_range(rom->addr, rom->datasize); + + trace_loader_write_rom(rom->name, rom->addr, rom->datasize, rom->isrom); ++ ++ notify = (RomLoaderNotifyData) { ++ .addr = rom->addr, ++ .len = rom->datasize, ++ }; ++ notifier_list_notify(&rom_loader_notifier, ¬ify); + } + } + +diff --git a/include/hw/loader.h b/include/hw/loader.h +index 8685e27334..5df632c5bd 100644 +--- a/include/hw/loader.h ++++ b/include/hw/loader.h +@@ -356,6 +356,21 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict); + ssize_t rom_add_vga(const char *file); + ssize_t rom_add_option(const char *file, int32_t bootindex); + ++typedef struct RomLoaderNotifyData { ++ /* Address of the blob in guest memory */ ++ hwaddr addr; ++ /* Length of the blob */ ++ size_t len; ++} RomLoaderNotifyData; ++ ++/** ++ * rom_add_load_notifier - Add a notifier for loaded images ++ * ++ * Add a notifier that will be invoked with a RomLoaderNotifyData structure for ++ * each blob loaded into guest memory, after the blob is loaded. ++ */ ++void rom_add_load_notifier(Notifier *notifier); ++ + /* This is the usual maximum in uboot, so if a uImage overflows this, it would + * overflow on real hardware too. */ + #define UBOOT_MAX_GUNZIP_BYTES (64 << 20) +-- +2.33.0 + diff --git a/hw-core-loader-Add-fields-to-RomLoaderNotify.patch b/hw-core-loader-Add-fields-to-RomLoaderNotify.patch new file mode 100644 index 00000000..437ecce2 --- /dev/null +++ b/hw-core-loader-Add-fields-to-RomLoaderNotify.patch @@ -0,0 +1,48 @@ +From b398484a5425336c57256dde48b1ee6630be1552 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 7 Nov 2024 14:03:34 +0000 +Subject: [PATCH] hw/core/loader: Add fields to RomLoaderNotify + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/3bf3a64142d22868078d191d5ff0e6a3ddf0644c + +In order to write an event log, the ROM load notification handler needs +two more fields. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/core/loader.c | 2 ++ + include/hw/loader.h | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/hw/core/loader.c b/hw/core/loader.c +index 1627ef1976..7990147ade 100644 +--- a/hw/core/loader.c ++++ b/hw/core/loader.c +@@ -1308,6 +1308,8 @@ static void rom_reset(void *unused) + trace_loader_write_rom(rom->name, rom->addr, rom->datasize, rom->isrom); + + notify = (RomLoaderNotifyData) { ++ .name = rom->name, ++ .blob_ptr = rom->data, + .addr = rom->addr, + .len = rom->datasize, + }; +diff --git a/include/hw/loader.h b/include/hw/loader.h +index 5df632c5bd..3a5212b897 100644 +--- a/include/hw/loader.h ++++ b/include/hw/loader.h +@@ -357,6 +357,10 @@ ssize_t rom_add_vga(const char *file); + ssize_t rom_add_option(const char *file, int32_t bootindex); + + typedef struct RomLoaderNotifyData { ++ /* Description of the loaded ROM */ ++ const char *name; ++ /* Blob */ ++ void *blob_ptr; + /* Address of the blob in guest memory */ + hwaddr addr; + /* Length of the blob */ +-- +2.33.0 + diff --git a/hw-net-cadence_gem-fix-register-mask-initialization.patch b/hw-net-cadence_gem-fix-register-mask-initialization.patch new file mode 100644 index 00000000..b77da2b0 --- /dev/null +++ b/hw-net-cadence_gem-fix-register-mask-initialization.patch @@ -0,0 +1,49 @@ +From 7fe1c9d57bf60feadaadabe6ada9ddee378ab244 Mon Sep 17 00:00:00 2001 +From: guping +Date: Fri, 1 Aug 2025 02:38:52 +0000 +Subject: [PATCH] hw/net/cadence_gem: fix register mask initialization + cherry-pick from 2bfcd27e00a49da2efa5d703121b94cd9cd4948b +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The gem_init_register_masks function was called at init time but it +relies on the num-priority-queues property. Call it at realize time +instead. + +Cc: qemu-stable@nongnu.org +Fixes: 4c70e32f05f ("net: cadence_gem: Define access permission for interrupt registers") +Signed-off-by: Luc Michel +Reviewed-by: Francisco Iglesias +Reviewed-by: Sai Pavan Boddu +Message-ID: <20250716095432.81923-2-luc.michel@amd.com> +Signed-off-by: Philippe Mathieu-Daudé + +Signed-off-by: guping +--- + hw/net/cadence_gem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index 296bba238e..c7f793c560 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -1740,6 +1740,7 @@ static void gem_realize(DeviceState *dev, Error **errp) + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + ++ gem_init_register_masks(s); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + + s->nic = qemu_new_nic(&net_gem_info, &s->conf, +@@ -1760,7 +1761,6 @@ static void gem_init(Object *obj) + + DB_PRINT("\n"); + +- gem_init_register_masks(s); + memory_region_init_io(&s->iomem, OBJECT(s), &gem_ops, s, + "enet", sizeof(s->regs)); + +-- +2.33.0 + diff --git a/hw-tpm-Add-TPM-event-log.patch b/hw-tpm-Add-TPM-event-log.patch new file mode 100644 index 00000000..35f669ce --- /dev/null +++ b/hw-tpm-Add-TPM-event-log.patch @@ -0,0 +1,507 @@ +From ace3d13d5db0b33fdda4c31549aed8e3f87ce47d Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 7 Nov 2024 13:11:56 +0000 +Subject: [PATCH] hw/tpm: Add TPM event log + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/b8e00505df37d35bcbcb05abdca5819d616099f4 + +Provide a library allowing the VMM to create an event log that describes +what is loaded into memory. During remote attestation in confidential +computing this helps an independent verifier reconstruct the initial +measurements of a VM, which contain the initial state of memory and +CPUs. + +We provide some definitions and structures described by the Trusted +Computing Group (TCG) in "TCG PC Client Platform Firmware Profile +Specification" Level 00 Version 1.06 Revision 52 [1]. This is the same +format as used by UEFI, and UEFI could reuse this log after finding it +in DT or ACPI tables, but can also copy its content into a new one. + +[1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ + +Cc: Stefan Berger +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/tpm/Kconfig | 4 + + hw/tpm/meson.build | 1 + + hw/tpm/tpm_log.c | 325 +++++++++++++++++++++++++++++++++++++++ + include/hw/tpm/tpm_log.h | 89 +++++++++++ + qapi/tpm.json | 14 ++ + 5 files changed, 433 insertions(+) + create mode 100644 hw/tpm/tpm_log.c + create mode 100644 include/hw/tpm/tpm_log.h + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index a46663288c..70694b14a3 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -30,3 +30,7 @@ config TPM_SPAPR + default y + depends on TPM && PSERIES + select TPM_BACKEND ++ ++config TPM_LOG ++ bool ++ default y +diff --git a/hw/tpm/meson.build b/hw/tpm/meson.build +index 6968e60b3f..81efb557f3 100644 +--- a/hw/tpm/meson.build ++++ b/hw/tpm/meson.build +@@ -6,4 +6,5 @@ system_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb.c')) + system_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_ppi.c')) + system_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_ppi.c')) + ++system_ss.add(when: 'CONFIG_TPM_LOG', if_true: files('tpm_log.c')) + specific_ss.add(when: 'CONFIG_TPM_SPAPR', if_true: files('tpm_spapr.c')) +diff --git a/hw/tpm/tpm_log.c b/hw/tpm/tpm_log.c +new file mode 100644 +index 0000000000..ab29d8569b +--- /dev/null ++++ b/hw/tpm/tpm_log.c +@@ -0,0 +1,325 @@ ++/* ++ * tpm_log.c - Event log as described by the Trusted Computing Group (TCG) ++ * ++ * Copyright (c) 2024 Linaro Ltd. ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Create an event log in the format specified by: ++ * ++ * TCG PC Client Platform Firmware Profile Specification ++ * Level 00 Version 1.06 Revision 52 ++ * Family “2.0” ++ */ ++ ++#include "qemu/osdep.h" ++ ++#include "crypto/hash.h" ++#include "exec/address-spaces.h" ++#include "exec/memory.h" ++#include "hw/tpm/tpm_log.h" ++#include "qapi/error.h" ++#include "qemu/bswap.h" ++#include "qom/object_interfaces.h" ++ ++/* ++ * Legacy structure used only in the first event in the log, for compatibility ++ */ ++struct TcgPcClientPcrEvent { ++ uint32_t pcr_index; ++ uint32_t event_type; ++ uint8_t digest[20]; ++ uint32_t event_data_size; ++ uint8_t event[]; ++} QEMU_PACKED; ++ ++struct TcgEfiSpecIdEvent { ++ uint8_t signature[16]; ++ uint32_t platform_class; ++ uint8_t family_version_minor; ++ uint8_t family_version_major; ++ uint8_t spec_revision; ++ uint8_t uintn_size; ++ uint32_t number_of_algorithms; /* 1 */ ++ /* ++ * For now we declare a single algo, but if we want UEFI to reuse this ++ * header then we'd need to add entries here for all algos supported by ++ * UEFI (and expand the digest field for EV_NO_ACTION). ++ */ ++ uint16_t algorithm_id; ++ uint16_t digest_size; ++ uint8_t vendor_info_size; ++ uint8_t vendor_info[]; ++} QEMU_PACKED; ++ ++struct TcgPcrEvent2Head { ++ uint32_t pcr_index; ++ uint32_t event_type; ++ /* variable-sized digests */ ++ uint8_t digests[]; ++} QEMU_PACKED; ++ ++struct TcgPcrEvent2Tail { ++ uint32_t event_size; ++ uint8_t event[]; ++} QEMU_PACKED; ++ ++struct TpmlDigestValues { ++ uint32_t count; /* 1 */ ++ uint16_t hash_alg; ++ uint8_t digest[]; ++} QEMU_PACKED; ++ ++struct TpmLog { ++ Object parent_obj; ++ ++ TpmLogDigestAlgo digest_algo; ++ size_t max_size; ++ uint64_t load_addr; ++ ++ uint16_t tcg_algo; ++ GByteArray *content; ++ uint8_t *digest; ++ size_t digest_size; ++}; ++ ++OBJECT_DEFINE_SIMPLE_TYPE(TpmLog, tpm_log, TPM_LOG, OBJECT) ++ ++static void tpm_log_init(Object *obj) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ ++ log->digest_algo = TPM_LOG_DIGEST_ALGO_SHA256; ++} ++ ++static void tpm_log_destroy(TpmLog *log) ++{ ++ if (!log->content) { ++ return; ++ } ++ g_free(log->digest); ++ log->digest = NULL; ++ g_byte_array_free(log->content, /* free_segment */ true); ++ log->content = NULL; ++} ++ ++static void tpm_log_finalize(Object *obj) ++{ ++ tpm_log_destroy(TPM_LOG(obj)); ++} ++ ++static int tpm_log_get_digest_algo(Object *obj, Error **errp) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ ++ return log->digest_algo; ++} ++ ++static void tpm_log_set_digest_algo(Object *obj, int algo, Error **errp) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ ++ if (log->content != NULL) { ++ error_setg(errp, "cannot set digest algo after log creation"); ++ return; ++ } ++ ++ log->digest_algo = algo; ++} ++ ++static void tpm_log_get_max_size(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ uint64_t value = log->max_size; ++ ++ visit_type_uint64(v, name, &value, errp); ++} ++ ++static void tpm_log_get_load_addr(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ uint64_t value = log->load_addr; ++ ++ visit_type_uint64(v, name, &value, errp); ++} ++ ++static void tpm_log_set_load_addr(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ TpmLog *log = TPM_LOG(obj); ++ uint64_t value; ++ ++ if (!visit_type_uint64(v, name, &value, errp)) { ++ return; ++ } ++ ++ log->load_addr = value; ++} ++ ++ ++static void tpm_log_class_init(ObjectClass *oc, void *data) ++{ ++ object_class_property_add_enum(oc, "digest-algo", ++ "TpmLogDigestAlgo", ++ &TpmLogDigestAlgo_lookup, ++ tpm_log_get_digest_algo, ++ tpm_log_set_digest_algo); ++ object_class_property_set_description(oc, "digest-algo", ++ "Algorithm used to hash blobs added as events ('sha256', 'sha512')"); ++ ++ /* max_size is set while allocating the log in tpm_log_create */ ++ object_class_property_add(oc, "max-size", "uint64", tpm_log_get_max_size, ++ NULL, NULL, NULL); ++ object_class_property_set_description(oc, "max-size", ++ "Maximum size of the log, reserved in guest memory"); ++ ++ object_class_property_add(oc, "load-addr", "uint64", tpm_log_get_load_addr, ++ tpm_log_set_load_addr, NULL, NULL); ++ object_class_property_set_description(oc, "load-addr", ++ "Base address of the log in guest memory"); ++} ++ ++int tpm_log_create(TpmLog *log, size_t max_size, Error **errp) ++{ ++ struct TcgEfiSpecIdEvent event; ++ struct TcgPcClientPcrEvent header = { ++ .pcr_index = 0, ++ .event_type = cpu_to_le32(TCG_EV_NO_ACTION), ++ .digest = {0}, ++ .event_data_size = cpu_to_le32(sizeof(event)), ++ }; ++ ++ log->content = g_byte_array_sized_new(max_size); ++ log->max_size = max_size; ++ ++ switch (log->digest_algo) { ++ case TPM_LOG_DIGEST_ALGO_SHA256: ++ log->tcg_algo = TCG_ALG_SHA256; ++ log->digest_size = TCG_ALG_SHA256_DIGEST_SIZE; ++ break; ++ case TPM_LOG_DIGEST_ALGO_SHA512: ++ log->tcg_algo = TCG_ALG_SHA512; ++ log->digest_size = TCG_ALG_SHA512_DIGEST_SIZE; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ log->digest = g_malloc0(log->digest_size); ++ ++ event = (struct TcgEfiSpecIdEvent) { ++ .signature = "Spec ID Event03", ++ .platform_class = 0, ++ .family_version_minor = 0, ++ .family_version_major = 2, ++ .spec_revision = 106, ++ .uintn_size = 2, /* UINT64 */ ++ .number_of_algorithms = cpu_to_le32(1), ++ .algorithm_id = cpu_to_le16(log->tcg_algo), ++ .digest_size = cpu_to_le16(log->digest_size), ++ .vendor_info_size = 0, ++ }; ++ ++ g_byte_array_append(log->content, (guint8 *)&header, sizeof(header)); ++ g_byte_array_append(log->content, (guint8 *)&event, sizeof(event)); ++ return 0; ++} ++ ++int tpm_log_add_event(TpmLog *log, uint32_t event_type, const uint8_t *event, ++ size_t event_size, const uint8_t *data, size_t data_size, ++ Error **errp) ++{ ++ int digests = 0; ++ size_t rollback_len; ++ struct TcgPcrEvent2Head header = { ++ .pcr_index = 0, ++ .event_type = cpu_to_le32(event_type), ++ }; ++ struct TpmlDigestValues digest_header = {0}; ++ struct TcgPcrEvent2Tail tail = { ++ .event_size = cpu_to_le32(event_size), ++ }; ++ ++ if (log->content == NULL) { ++ error_setg(errp, "event log is not initialized"); ++ return -EINVAL; ++ } ++ rollback_len = log->content->len; ++ ++ g_byte_array_append(log->content, (guint8 *)&header, sizeof(header)); ++ ++ if (data) { ++ QCryptoHashAlgorithm qc_algo; ++ ++ digest_header.hash_alg = cpu_to_le16(log->tcg_algo); ++ switch (log->digest_algo) { ++ case TPM_LOG_DIGEST_ALGO_SHA256: ++ qc_algo = QCRYPTO_HASH_ALG_SHA256; ++ break; ++ case TPM_LOG_DIGEST_ALGO_SHA512: ++ qc_algo = QCRYPTO_HASH_ALG_SHA512; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ if (qcrypto_hash_bytes(qc_algo, (const char *)data, data_size, ++ &log->digest, &log->digest_size, errp)) { ++ goto err_rollback; ++ } ++ digests = 1; ++ } else if (event_type == TCG_EV_NO_ACTION) { ++ /* EV_NO_ACTION contains empty digests for each supported algo */ ++ memset(log->digest, 0, log->digest_size); ++ digest_header.hash_alg = 0; ++ digests = 1; ++ } ++ ++ if (digests) { ++ digest_header.count = cpu_to_le32(digests); ++ g_byte_array_append(log->content, (guint8 *)&digest_header, ++ sizeof(digest_header)); ++ g_byte_array_append(log->content, log->digest, log->digest_size); ++ } else { ++ /* Add an empty digests list */ ++ g_byte_array_append(log->content, (guint8 *)&digest_header.count, ++ sizeof(digest_header.count)); ++ } ++ ++ g_byte_array_append(log->content, (guint8 *)&tail, sizeof(tail)); ++ g_byte_array_append(log->content, event, event_size); ++ ++ if (log->content->len > log->max_size) { ++ error_setg(errp, "event log exceeds max size"); ++ goto err_rollback; ++ } ++ ++ return 0; ++ ++err_rollback: ++ g_byte_array_set_size(log->content, rollback_len); ++ return -1; ++} ++ ++int tpm_log_write_and_close(TpmLog *log, Error **errp) ++{ ++ int ret; ++ ++ if (!log->content) { ++ error_setg(errp, "event log is not initialized"); ++ return -1; ++ } ++ ++ ret = address_space_write_rom(&address_space_memory, log->load_addr, ++ MEMTXATTRS_UNSPECIFIED, log->content->data, ++ log->content->len); ++ if (ret) { ++ error_setg(errp, "cannot load log into memory"); ++ return -1; ++ } ++ ++ tpm_log_destroy(log); ++ return ret; ++} +diff --git a/include/hw/tpm/tpm_log.h b/include/hw/tpm/tpm_log.h +new file mode 100644 +index 0000000000..b3cd2e7563 +--- /dev/null ++++ b/include/hw/tpm/tpm_log.h +@@ -0,0 +1,89 @@ ++#ifndef QEMU_TPM_LOG_H ++#define QEMU_TPM_LOG_H ++ ++#include "qom/object.h" ++#include "sysemu/tpm.h" ++ ++/* ++ * Defined in: TCG Algorithm Registry ++ * Family 2.0 Level 00 Revision 01.34 ++ * ++ * (Here TCG stands for Trusted Computing Group) ++ */ ++#define TCG_ALG_SHA256 0xB ++#define TCG_ALG_SHA512 0xD ++ ++/* Size of a digest in bytes */ ++#define TCG_ALG_SHA256_DIGEST_SIZE 32 ++#define TCG_ALG_SHA512_DIGEST_SIZE 64 ++ ++/* ++ * Defined in: TCG PC Client Platform Firmware Profile Specification ++ * Version 1.06 revision 52 ++ */ ++#define TCG_EV_NO_ACTION 0x00000003 ++#define TCG_EV_EVENT_TAG 0x00000006 ++#define TCG_EV_POST_CODE2 0x00000013 ++#define TCG_EV_EFI_PLATFORM_FIRMWARE_BLOB2 0x8000000A ++ ++struct UefiPlatformFirmwareBlob2Head { ++ uint8_t blob_description_size; ++ uint8_t blob_description[]; ++} __attribute__((packed)); ++ ++struct UefiPlatformFirmwareBlob2Tail { ++ uint64_t blob_base; ++ uint64_t blob_size; ++} __attribute__((packed)); ++ ++#define TYPE_TPM_LOG "tpm-log" ++ ++OBJECT_DECLARE_SIMPLE_TYPE(TpmLog, TPM_LOG) ++ ++/** ++ * tpm_log_create - Create the event log ++ * @log: the log object ++ * @max_size: maximum size of the log. Adding an event past that size will ++ * return an error ++ * @errp: pointer to a NULL-initialized error object ++ * ++ * Allocate the event log and create the initial entry (Spec ID Event03) ++ * describing the log format. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++int tpm_log_create(TpmLog *log, size_t max_size, Error **errp); ++ ++/** ++ * tpm_log_add_event - Append an event to the log ++ * @log: the log object ++ * @event_type: the `eventType` field in TCG_PCR_EVENT2 ++ * @event: the `event` field in TCG_PCR_EVENT2 ++ * @event_size: the `eventSize` field in TCG_PCR_EVENT2 ++ * @data: content to be hashed into the event digest. May be NULL. ++ * @data_size: size of @data. Should be zero when @data is NULL. ++ * @errp: pointer to a NULL-initialized error object ++ * ++ * Add a TCG_PCR_EVENT2 event to the event log. Depending on the event type, a ++ * data buffer may be hashed into the event digest (for example ++ * TCG_EV_EFI_PLATFORM_FIRMWARE_BLOB2 contains a digest of the blob.) ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++int tpm_log_add_event(TpmLog *log, uint32_t event_type, const uint8_t *event, ++ size_t event_size, const uint8_t *data, size_t data_size, ++ Error **errp); ++ ++/** ++ * tpm_log_write_and_close - Move the log to guest memory ++ * @log: the log object ++ * @errp: pointer to a NULL-initialized error object ++ * ++ * Write the log into memory, at the address set in the load-addr property. ++ * After this operation, the log is not writable anymore. ++ * ++ * Return: 0 on success, -1 on error ++ */ ++int tpm_log_write_and_close(TpmLog *log, Error **errp); ++ ++#endif +diff --git a/qapi/tpm.json b/qapi/tpm.json +index a754455ca5..a051d7bf5c 100644 +--- a/qapi/tpm.json ++++ b/qapi/tpm.json +@@ -186,3 +186,17 @@ + ## + { 'command': 'query-tpm', 'returns': ['TPMInfo'], + 'if': 'CONFIG_TPM' } ++ ++## ++# @TpmLogDigestAlgo: ++# ++# @sha256: Use the SHA256 algorithm ++# ++# @sha512: Use the SHA512 algorithm ++# ++# Algorithm to use for event log digests ++# ++# Since: 9.3 ++## ++{ 'enum': 'TpmLogDigestAlgo', ++ 'data': ['sha256', 'sha512'] } +-- +2.33.0 + diff --git a/include-qom-object.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch b/include-qom-object.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch new file mode 100644 index 00000000..5ca38f59 --- /dev/null +++ b/include-qom-object.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch @@ -0,0 +1,249 @@ +From b1304358281cd973a8c7ef057e350e5e2028e005 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Tue, 20 Feb 2024 16:06:16 +0000 +Subject: [PATCH] include/qom/object.h: New OBJECT_DEFINE_SIMPLE_TYPE{, + _WITH_INTERFACES} macros +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://gitlab.com/qemu-project/qemu/-/commit/e54c24339f3e6533af0b0c4364c5c9c9f74e9273 + +We have an OBJECT_DEFINE_TYPE_EXTENDED macro, plus several variations +on it, which emits the boilerplate for the TypeInfo and ensures it is +registered with the type system. However, all the existing macros +insist that the type being defined has its own FooClass struct, so +they aren't useful for the common case of a simple leaf class which +doesn't have any new methods or any other need for its own class +struct (that is, for the kind of type that OBJECT_DECLARE_SIMPLE_TYPE +declares). + +Pull the actual implementation of OBJECT_DEFINE_TYPE_EXTENDED out +into a new DO_OBJECT_DEFINE_TYPE_EXTENDED which parameterizes the +value we use for the class_size field. This lets us add a new +OBJECT_DEFINE_SIMPLE_TYPE which does the same job as the various +existing OBJECT_DEFINE_*_TYPE_* family macros for this kind of simple +type, and the variant OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES for +when the type will implement some interfaces. + +Reviewed-by: Daniel P. Berrangé +Signed-off-by: Peter Maydell +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Richard Henderson +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20240220160622.114437-5-peter.maydell@linaro.org +Reviewed-by: Zhao Liu +Signed-off-by: houmingyong +--- + docs/devel/qom.rst | 34 +++++++++++++--- + include/qom/object.h | 96 ++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 108 insertions(+), 22 deletions(-) + +diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst +index 9918fac7f2..0889ca949c 100644 +--- a/docs/devel/qom.rst ++++ b/docs/devel/qom.rst +@@ -348,12 +348,14 @@ used. This does the same as OBJECT_DECLARE_SIMPLE_TYPE(), but without + the 'struct MyDeviceClass' definition. + + To implement the type, the OBJECT_DEFINE macro family is available. +-In the simple case the OBJECT_DEFINE_TYPE macro is suitable: ++For the simplest case of a leaf class which doesn't need any of its ++own virtual functions (i.e. which was declared with OBJECT_DECLARE_SIMPLE_TYPE) ++the OBJECT_DEFINE_SIMPLE_TYPE macro is suitable: + + .. code-block:: c + :caption: Defining a simple type + +- OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) ++ OBJECT_DEFINE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) + + This is equivalent to the following: + +@@ -370,7 +372,6 @@ This is equivalent to the following: + .instance_size = sizeof(MyDevice), + .instance_init = my_device_init, + .instance_finalize = my_device_finalize, +- .class_size = sizeof(MyDeviceClass), + .class_init = my_device_class_init, + }; + +@@ -385,13 +386,36 @@ This is sufficient to get the type registered with the type + system, and the three standard methods now need to be implemented + along with any other logic required for the type. + ++If the class needs its own virtual methods, or has some other ++per-class state it needs to store in its own class struct, ++then you can use the OBJECT_DEFINE_TYPE macro. This does the ++same thing as OBJECT_DEFINE_SIMPLE_TYPE, but it also sets the ++class_size of the type to the size of the class struct. ++ ++.. code-block:: c ++ :caption: Defining a type which needs a class struct ++ ++ OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE) ++ + If the type needs to implement one or more interfaces, then the +-OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead. +-This accepts an array of interface type names. ++OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES() and ++OBJECT_DEFINE_TYPE_WITH_INTERFACES() macros can be used instead. ++These accept an array of interface type names. The difference between ++them is that the former is for simple leaf classes that don't need ++a class struct, and the latter is for when you will be defining ++a class struct. + + .. code-block:: c + :caption: Defining a simple type implementing interfaces + ++ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(MyDevice, my_device, ++ MY_DEVICE, DEVICE, ++ { TYPE_USER_CREATABLE }, ++ { NULL }) ++ ++.. code-block:: c ++ :caption: Defining a type implementing interfaces ++ + OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device, + MY_DEVICE, DEVICE, + { TYPE_USER_CREATABLE }, +diff --git a/include/qom/object.h b/include/qom/object.h +index afccd24ca7..f52ab216cd 100644 +--- a/include/qom/object.h ++++ b/include/qom/object.h +@@ -259,31 +259,23 @@ struct Object + + + /** +- * OBJECT_DEFINE_TYPE_EXTENDED: ++ * DO_OBJECT_DEFINE_TYPE_EXTENDED: + * @ModuleObjName: the object name with initial caps + * @module_obj_name: the object name in lowercase with underscore separators + * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators + * @PARENT_MODULE_OBJ_NAME: the parent object name in uppercase with underscore + * separators + * @ABSTRACT: boolean flag to indicate whether the object can be instantiated ++ * @CLASS_SIZE: size of the type's class + * @...: list of initializers for "InterfaceInfo" to declare implemented interfaces + * +- * This macro is typically used in a source file, and will: +- * +- * - declare prototypes for _finalize, _class_init and _init methods +- * - declare the TypeInfo struct instance +- * - provide the constructor to register the type +- * +- * After using this macro, implementations of the _finalize, _class_init, +- * and _init methods need to be written. Any of these can be zero-line +- * no-op impls if no special logic is required for a given type. +- * +- * This macro should rarely be used, instead one of the more specialized +- * macros is usually a better choice. ++ * This is the base macro used to implement all the OBJECT_DEFINE_* ++ * macros. It should never be used directly in a source file. + */ +-#define OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ +- MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ +- ABSTRACT, ...) \ ++#define DO_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, \ ++ PARENT_MODULE_OBJ_NAME, \ ++ ABSTRACT, CLASS_SIZE, ...) \ + static void \ + module_obj_name##_finalize(Object *obj); \ + static void \ +@@ -298,7 +290,7 @@ struct Object + .instance_align = __alignof__(ModuleObjName), \ + .instance_init = module_obj_name##_init, \ + .instance_finalize = module_obj_name##_finalize, \ +- .class_size = sizeof(ModuleObjName##Class), \ ++ .class_size = CLASS_SIZE, \ + .class_init = module_obj_name##_class_init, \ + .abstract = ABSTRACT, \ + .interfaces = (InterfaceInfo[]) { __VA_ARGS__ } , \ +@@ -311,6 +303,37 @@ struct Object + } \ + type_init(module_obj_name##_register_types); + ++/** ++ * OBJECT_DEFINE_TYPE_EXTENDED: ++ * @ModuleObjName: the object name with initial caps ++ * @module_obj_name: the object name in lowercase with underscore separators ++ * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators ++ * @PARENT_MODULE_OBJ_NAME: the parent object name in uppercase with underscore ++ * separators ++ * @ABSTRACT: boolean flag to indicate whether the object can be instantiated ++ * @...: list of initializers for "InterfaceInfo" to declare implemented interfaces ++ * ++ * This macro is typically used in a source file, and will: ++ * ++ * - declare prototypes for _finalize, _class_init and _init methods ++ * - declare the TypeInfo struct instance ++ * - provide the constructor to register the type ++ * ++ * After using this macro, implementations of the _finalize, _class_init, ++ * and _init methods need to be written. Any of these can be zero-line ++ * no-op impls if no special logic is required for a given type. ++ * ++ * This macro should rarely be used, instead one of the more specialized ++ * macros is usually a better choice. ++ */ ++#define OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ ++ ABSTRACT, ...) \ ++ DO_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ ++ ABSTRACT, sizeof(ModuleObjName##Class), \ ++ __VA_ARGS__) ++ + /** + * OBJECT_DEFINE_TYPE: + * @ModuleObjName: the object name with initial caps +@@ -368,6 +391,45 @@ struct Object + MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ + true, { NULL }) + ++/** ++ * OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES: ++ * @ModuleObjName: the object name with initial caps ++ * @module_obj_name: the object name in lowercase with underscore separators ++ * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators ++ * @PARENT_MODULE_OBJ_NAME: the parent object name in uppercase with underscore ++ * separators ++ * ++ * This is a variant of OBJECT_DEFINE_TYPE_EXTENDED, which is suitable for ++ * the case of a non-abstract type, with interfaces, and with no requirement ++ * for a class struct. ++ */ ++#define OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(ModuleObjName, \ ++ module_obj_name, \ ++ MODULE_OBJ_NAME, \ ++ PARENT_MODULE_OBJ_NAME, ...) \ ++ DO_OBJECT_DEFINE_TYPE_EXTENDED(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, \ ++ false, 0, __VA_ARGS__) ++ ++/** ++ * OBJECT_DEFINE_SIMPLE_TYPE: ++ * @ModuleObjName: the object name with initial caps ++ * @module_obj_name: the object name in lowercase with underscore separators ++ * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators ++ * @PARENT_MODULE_OBJ_NAME: the parent object name in uppercase with underscore ++ * separators ++ * ++ * This is a variant of OBJECT_DEFINE_TYPE_EXTENDED, which is suitable for ++ * the common case of a non-abstract type, without any interfaces, and with ++ * no requirement for a class struct. If you declared your type with ++ * OBJECT_DECLARE_SIMPLE_TYPE then this is probably the right choice for ++ * defining it. ++ */ ++#define OBJECT_DEFINE_SIMPLE_TYPE(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME) \ ++ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(ModuleObjName, module_obj_name, \ ++ MODULE_OBJ_NAME, PARENT_MODULE_OBJ_NAME, { NULL }) ++ + /** + * struct TypeInfo: + * @name: The name of the type. +-- +2.33.0 + diff --git a/kvm-Use-kvm_vm_check_extension-where-necessary.patch b/kvm-Use-kvm_vm_check_extension-where-necessary.patch new file mode 100644 index 00000000..bcf22d2a --- /dev/null +++ b/kvm-Use-kvm_vm_check_extension-where-necessary.patch @@ -0,0 +1,86 @@ +From 4242973f80d6779b2e4235bacc18d685bbfcfda8 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 4 Dec 2024 15:34:28 +0000 +Subject: [PATCH] kvm: Use kvm_vm_check_extension() where necessary + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/97b19c96743303418578785a230019b8b26b0131 + +The Arm KVM code can return different values from KVM_CHECK_EXTENSION +depending on the VM type. Use kvm_vm_check_extension() where necessary +to ensure we get the right response from KVM. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/kvm.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + accel/kvm/kvm-all.c | 6 +++--- + target/arm/kvm64.c | 8 ++++---- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 7d175d3262..2cdd615025 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2363,13 +2363,13 @@ static int kvm_recommended_vcpus(KVMState *s) + + static int kvm_max_vcpus(KVMState *s) + { +- int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS); ++ int ret = kvm_vm_check_extension(s, KVM_CAP_MAX_VCPUS); + return (ret) ? ret : kvm_recommended_vcpus(s); + } + + static int kvm_max_vcpu_id(KVMState *s) + { +- int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPU_ID); ++ int ret = kvm_vm_check_extension(s, KVM_CAP_MAX_VCPU_ID); + return (ret) ? ret : kvm_max_vcpus(s); + } + +@@ -2625,7 +2625,7 @@ static int kvm_init(MachineState *ms) + + #ifdef KVM_CAP_SET_GUEST_DEBUG + kvm_has_guest_debug = +- (kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0); ++ (kvm_vm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0); + #endif + + kvm_sstep_flags = 0; +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index b099287ed0..651f603dd8 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -39,11 +39,11 @@ void kvm_arm_init_debug(KVMState *s) + have_guest_debug = kvm_check_extension(s, + KVM_CAP_SET_GUEST_DEBUG); + +- max_hw_wps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS); ++ max_hw_wps = kvm_vm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS); + hw_watchpoints = g_array_sized_new(true, true, + sizeof(HWWatchpoint), max_hw_wps); + +- max_hw_bps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS); ++ max_hw_bps = kvm_vm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS); + hw_breakpoints = g_array_sized_new(true, true, + sizeof(HWBreakpoint), max_hw_bps); + return; +@@ -513,12 +513,12 @@ bool kvm_arm_aarch32_supported(void) + + bool kvm_arm_sve_supported(void) + { +- return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE); ++ return kvm_vm_check_extension(kvm_state, KVM_CAP_ARM_SVE); + } + + bool kvm_arm_steal_time_supported(void) + { +- return kvm_check_extension(kvm_state, KVM_CAP_STEAL_TIME); ++ return kvm_vm_check_extension(kvm_state, KVM_CAP_STEAL_TIME); + } + + QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); +-- +2.33.0 + diff --git a/linux-headers-Add-KVM-Arm-RME-definitions-to-Linux-h.patch b/linux-headers-Add-KVM-Arm-RME-definitions-to-Linux-h.patch new file mode 100644 index 00000000..1d1d025f --- /dev/null +++ b/linux-headers-Add-KVM-Arm-RME-definitions-to-Linux-h.patch @@ -0,0 +1,178 @@ +From d08cc1efcdf47b6cb3edece889cc36904ccf932d Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Fri, 13 May 2022 09:08:54 +0100 +Subject: [PATCH] linux-headers: Add KVM Arm RME definitions to Linux headers + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/b1872e38b35f4e7b820880694ad876c41aabaa85 + +Copy the KVM definitions for Arm RME from the development branch. +Don't merge, they will be added from the periodic Linux header sync. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + linux-headers/asm-arm64/kvm.h + linux-headers/linux/kvm.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + linux-headers/asm-arm64/kvm.h | 60 +++++++++++++++++++++++++++++++++++ + linux-headers/linux/kvm.h | 28 +++++++++++++--- + 2 files changed, 84 insertions(+), 4 deletions(-) + +diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h +index 552fdcb18f..aed56ef371 100644 +--- a/linux-headers/asm-arm64/kvm.h ++++ b/linux-headers/asm-arm64/kvm.h +@@ -111,6 +111,8 @@ struct kvm_regs { + #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ + #define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */ + #define KVM_ARM_VCPU_TEC 8 /* VCPU TEC state as part of cvm */ ++#define KVM_ARM_VCPU_HAS_EL2_E2H0 9 /* Limit NV support to E2H RES0 */ ++#define KVM_ARM_VCPU_REC 10 /* VCPU REC state as part of Realm */ + + struct kvm_vcpu_init { + __u32 target; +@@ -366,6 +368,7 @@ enum { + KVM_REG_ARM_STD_HYP_BIT_PV_TIME = 0, + }; + ++/* Vendor hyper call function numbers 0-63 */ + #define KVM_REG_ARM_VENDOR_HYP_BMAP KVM_REG_ARM_FW_FEAT_BMAP_REG(2) + + enum { +@@ -373,6 +376,14 @@ enum { + KVM_REG_ARM_VENDOR_HYP_BIT_PTP = 1, + }; + ++/* Vendor hyper call function numbers 64-127 */ ++#define KVM_REG_ARM_VENDOR_HYP_BMAP_2 KVM_REG_ARM_FW_FEAT_BMAP_REG(3) ++ ++enum { ++ KVM_REG_ARM_VENDOR_HYP_BIT_DISCOVER_IMPL_VER = 0, ++ KVM_REG_ARM_VENDOR_HYP_BIT_DISCOVER_IMPL_CPUS = 1, ++}; ++ + /* Device Control API on vm fd */ + #define KVM_ARM_VM_SMCCC_CTRL 0 + #define KVM_ARM_VM_SMCCC_FILTER 0 +@@ -395,6 +406,7 @@ enum { + #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6 + #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7 + #define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8 ++#define KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ 9 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10 + #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \ + (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) +@@ -407,6 +419,54 @@ enum { + #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 + #define KVM_DEV_ARM_ITS_CTRL_RESET 4 + ++/* KVM_CAP_ARM_RME on VM fd */ ++#define KVM_CAP_ARM_RME_CONFIG_REALM 0 ++#define KVM_CAP_ARM_RME_CREATE_REALM 1 ++#define KVM_CAP_ARM_RME_INIT_RIPAS_REALM 2 ++#define KVM_CAP_ARM_RME_POPULATE_REALM 3 ++#define KVM_CAP_ARM_RME_ACTIVATE_REALM 4 ++ ++/* List of configuration items accepted for KVM_CAP_ARM_RME_CONFIG_REALM */ ++#define ARM_RME_CONFIG_RPV 0 ++#define ARM_RME_CONFIG_HASH_ALGO 1 ++ ++#define ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA256 0 ++#define ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA512 1 ++ ++#define ARM_RME_CONFIG_RPV_SIZE 64 ++ ++struct arm_rme_config { ++ __u32 cfg; ++ union { ++ /* cfg == ARM_RME_CONFIG_RPV */ ++ struct { ++ __u8 rpv[ARM_RME_CONFIG_RPV_SIZE]; ++ }; ++ ++ /* cfg == ARM_RME_CONFIG_HASH_ALGO */ ++ struct { ++ __u32 hash_algo; ++ }; ++ ++ /* Fix the size of the union */ ++ __u8 reserved[256]; ++ }; ++}; ++ ++#define KVM_ARM_RME_POPULATE_FLAGS_MEASURE (1 << 0) ++struct arm_rme_populate_realm { ++ __u64 base; ++ __u64 size; ++ __u32 flags; ++ __u32 reserved[3]; ++}; ++ ++struct arm_rme_init_ripas { ++ __u64 base; ++ __u64 size; ++ __u64 reserved[2]; ++}; ++ + /* Device Control API on vcpu fd */ + #define KVM_ARM_VCPU_PMU_V3_CTRL 0 + #define KVM_ARM_VCPU_PMU_V3_IRQ 0 +diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h +index d3bf7fac00..beb41f7433 100644 +--- a/linux-headers/linux/kvm.h ++++ b/linux-headers/linux/kvm.h +@@ -924,14 +924,25 @@ struct kvm_ppc_resize_hpt { + #define KVM_S390_SIE_PAGE_OFFSET 1 + + /* +- * On arm64, machine type can be used to request the physical +- * address size for the VM. Bits[7-0] are reserved for the guest +- * PA size shift (i.e, log2(PA_Size)). For backward compatibility, +- * value 0 implies the default IPA size, 40bits. ++ * On arm64, machine type can be used to request both the machine type and ++ * the physical address size for the VM. ++ * ++ * Bits[11-8] are reserved for the ARM specific machine type. ++ * ++ * Bits[7-0] are reserved for the guest PA size shift (i.e, log2(PA_Size)). ++ * For backward compatibility, value 0 implies the default IPA size, 40bits. + */ ++#define KVM_VM_TYPE_ARM_SHIFT 8 ++#define KVM_VM_TYPE_ARM_MASK (0xfULL << KVM_VM_TYPE_ARM_SHIFT) ++#define KVM_VM_TYPE_ARM(_type) \ ++ (((_type) << KVM_VM_TYPE_ARM_SHIFT) & KVM_VM_TYPE_ARM_MASK) ++#define KVM_VM_TYPE_ARM_NORMAL KVM_VM_TYPE_ARM(0) ++#define KVM_VM_TYPE_ARM_REALM KVM_VM_TYPE_ARM(1) ++ + #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL + #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ + ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) ++ + /* + * ioctls for /dev/kvm fds: + */ +@@ -1206,6 +1217,8 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228 + #define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 + #define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230 ++#define KVM_CAP_ARM_WRITABLE_IMP_ID_REGS 239 ++#define KVM_CAP_ARM_RME 240 + + #define KVM_CAP_ARM_TMM 300 + +@@ -2451,4 +2464,11 @@ struct kvm_s390_zpci_op { + #define KVM_GET_TMI_VERSION _IOR(KVMIO, 0xd2, uint64_t) + #define MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM 0x20001 + ++/* Available with KVM_CAP_ARM_RME, only for VMs with KVM_VM_TYPE_ARM_REALM */ ++struct kvm_arm_rmm_psci_complete { ++ __u64 target_mpidr; ++ __u32 psci_status; ++ __u32 padding[3]; ++}; ++ + #endif /* __LINUX_KVM_H */ +-- +2.33.0 + diff --git a/memory-Change-NotifyStateClear-definition-to-return-.patch b/memory-Change-NotifyStateClear-definition-to-return-.patch new file mode 100644 index 00000000..dc8ba1c9 --- /dev/null +++ b/memory-Change-NotifyStateClear-definition-to-return-.patch @@ -0,0 +1,84 @@ +From d99491bfe7983151fa8e2688f0b0aad591e36147 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:30 +0800 +Subject: [PATCH] memory: Change NotifyStateClear() definition to return the + result + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/13fd87aac38509ab07bacafa2e35eb528d4be365 + +So that the caller can check the result of NotifyStateClear() handler if +the operation fails. + +Signed-off-by: Chenyi Qiang +Signed-off-by: houmingyong +--- + hw/vfio/common.c | 18 ++++++++++-------- + include/exec/memory.h | 4 ++-- + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 62a2000acd..182874eccb 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -350,8 +350,8 @@ out: + rcu_read_unlock(); + } + +-static void vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontainer, +- MemoryRegionSection *section) ++static int vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontainer, ++ MemoryRegionSection *section) + { + const hwaddr size = int128_get64(section->size); + const hwaddr iova = section->offset_within_address_space; +@@ -363,24 +363,26 @@ static void vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontaine + error_report("%s: vfio_container_dma_unmap() failed: %s", __func__, + strerror(-ret)); + } ++ ++ return ret; + } + +-static void vfio_ram_discard_notify_discard(StateChangeListener *scl, +- MemoryRegionSection *section) ++static int vfio_ram_discard_notify_discard(StateChangeListener *scl, ++ MemoryRegionSection *section) + { + RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, + listener); +- vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); ++ return vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); + } + +-static void vfio_private_shared_notify_to_private(StateChangeListener *scl, +- MemoryRegionSection *section) ++static int vfio_private_shared_notify_to_private(StateChangeListener *scl, ++ MemoryRegionSection *section) + { + PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); + VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, + listener); +- vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); ++ return vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); + } + + static int vfio_state_change_notify_to_state_set(VFIOContainerBase *bcontainer, +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 964ec53afc..b93ffb533e 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -580,8 +580,8 @@ typedef int (*ReplayStateChange)(MemoryRegionSection *section, void *opaque); + typedef struct StateChangeListener StateChangeListener; + typedef int (*NotifyStateSet)(StateChangeListener *scl, + MemoryRegionSection *section); +-typedef void (*NotifyStateClear)(StateChangeListener *scl, +- MemoryRegionSection *section); ++typedef int (*NotifyStateClear)(StateChangeListener *scl, ++ MemoryRegionSection *section); + + struct StateChangeListener { + /* +-- +2.33.0 + diff --git a/memory-Change-memory_region_set_ram_discard_manager-.patch b/memory-Change-memory_region_set_ram_discard_manager-.patch new file mode 100644 index 00000000..f7bf838f --- /dev/null +++ b/memory-Change-memory_region_set_ram_discard_manager-.patch @@ -0,0 +1,140 @@ +From 9d4e30a832e8de249869c6cbc29b102e4e9b3db9 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:22 +0800 +Subject: [PATCH] memory: Change memory_region_set_ram_discard_manager() to + return the result + +Reference:https://gitlab.com/qemu-project/qemu/-/commit/ff1211154c45c9f7f82116ae9a8c72a848e4a8b5 + +Modify memory_region_set_ram_discard_manager() to return false if a +RamDiscardManager is already set in the MemoryRegion. The caller must +handle this failure, such as having virtio-mem undo its actions and fail +the realize() process. Opportunistically move the call earlier to avoid +complex error handling. + +This change is beneficial when introducing a new RamDiscardManager +instance besides virtio-mem. After +ram_block_coordinated_discard_require(true) unlocks all +RamDiscardManager instances, only one instance is allowed to be set for +a MemoryRegion at present. + +Suggested-by: David Hildenbrand +Signed-off-by: Chenyi Qiang +Conflicts: + hw/virtio/virtio-mem.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/virtio/virtio-mem.c | 28 ++++++++++++++++------------ + include/exec/memory.h | 6 +++--- + system/memory.c | 10 +++++++--- + 3 files changed, 26 insertions(+), 18 deletions(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 90bfc5e596..6f3ecddfc7 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -1049,6 +1049,17 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + return; + } + ++ /* ++ * Set ourselves as RamDiscardManager before the plug handler maps the ++ * memory region and exposes it via an address space. ++ */ ++ if (memory_region_set_ram_discard_manager(&vmem->memdev->mr, ++ RAM_DISCARD_MANAGER(vmem))) { ++ error_setg(errp, "Failed to set RamDiscardManager"); ++ ram_block_coordinated_discard_require(false); ++ return; ++ } ++ + /* + * We don't know at this point whether shared RAM is migrated using + * QEMU or migrated using the file content. "x-ignore-shared" will be +@@ -1103,13 +1114,6 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + &vmstate_virtio_mem_device_early, vmem); + } + qemu_register_reset(virtio_mem_system_reset, vmem); +- +- /* +- * Set ourselves as RamDiscardManager before the plug handler maps the +- * memory region and exposes it via an address space. +- */ +- memory_region_set_ram_discard_manager(&vmem->memdev->mr, +- RAM_DISCARD_MANAGER(vmem)); + } + + static void virtio_mem_device_unrealize(DeviceState *dev) +@@ -1117,11 +1121,6 @@ static void virtio_mem_device_unrealize(DeviceState *dev) + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOMEM *vmem = VIRTIO_MEM(dev); + +- /* +- * The unplug handler unmapped the memory region, it cannot be +- * found via an address space anymore. Unset ourselves. +- */ +- memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); + qemu_unregister_reset(virtio_mem_system_reset, vmem); + if (vmem->early_migration) { + vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early, +@@ -1132,6 +1131,11 @@ static void virtio_mem_device_unrealize(DeviceState *dev) + virtio_del_queue(vdev, 0); + virtio_cleanup(vdev); + g_free(vmem->bitmap); ++ /* ++ * The unplug handler unmapped the memory region, it cannot be ++ * found via an address space anymore. Unset ourselves. ++ */ ++ memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); + ram_block_coordinated_discard_require(false); + } + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 950362d53c..a4e9e084cd 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -2554,13 +2554,13 @@ static inline bool memory_region_has_ram_discard_manager(MemoryRegion *mr) + * + * This function must not be called for a mapped #MemoryRegion, a #MemoryRegion + * that does not cover RAM, or a #MemoryRegion that already has a +- * #RamDiscardManager assigned. ++ * #RamDiscardManager assigned. Return 0 if the rdm is set successfully. + * + * @mr: the #MemoryRegion + * @rdm: #RamDiscardManager to set + */ +-void memory_region_set_ram_discard_manager(MemoryRegion *mr, +- RamDiscardManager *rdm); ++int memory_region_set_ram_discard_manager(MemoryRegion *mr, ++ RamDiscardManager *rdm); + + /** + * memory_region_find: translate an address/size relative to a +diff --git a/system/memory.c b/system/memory.c +index 607ce9cf60..c3985e8eef 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -2121,12 +2121,16 @@ RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr) + return mr->rdm; + } + +-void memory_region_set_ram_discard_manager(MemoryRegion *mr, +- RamDiscardManager *rdm) ++int memory_region_set_ram_discard_manager(MemoryRegion *mr, ++ RamDiscardManager *rdm) + { + g_assert(memory_region_is_ram(mr)); +- g_assert(!rdm || !mr->rdm); ++ if (mr->rdm && rdm) { ++ return -EBUSY; ++ } ++ + mr->rdm = rdm; ++ return 0; + } + + uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm, +-- +2.33.0 + diff --git a/memory-Export-a-helper-to-get-intersection-of-a-Memo.patch b/memory-Export-a-helper-to-get-intersection-of-a-Memo.patch new file mode 100644 index 00000000..8cea98bf --- /dev/null +++ b/memory-Export-a-helper-to-get-intersection-of-a-Memo.patch @@ -0,0 +1,142 @@ +From a7cca9b3931b22d9893ddf938b6ab4b74d4c7533 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:21 +0800 +Subject: [PATCH] memory: Export a helper to get intersection of a + MemoryRegionSection with a given range + +Rename the helper to memory_region_section_intersect_range() to make it +more generic. Meanwhile, define the @end as Int128 and replace the +related operations with Int128_* format since the helper is exported as +a wider API. + +Reference:https://gitlab.com/qemu-project/qemu/-/commit/f47a672a72acd6e2712031f0bc4d4f3ae4b6302c + +Suggested-by: Alexey Kardashevskiy +Reviewed-by: David Hildenbrand +Signed-off-by: Chenyi Qiang +Reviewed-by: Alexey Kardashevskiy +Signed-off-by: houmingyong +--- + hw/virtio/virtio-mem.c | 32 +++++--------------------------- + include/exec/memory.h | 27 +++++++++++++++++++++++++++ + 2 files changed, 32 insertions(+), 27 deletions(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 75ee38aa46..90bfc5e596 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -235,28 +235,6 @@ static int virtio_mem_for_each_plugged_range(VirtIOMEM *vmem, void *arg, + return ret; + } + +-/* +- * Adjust the memory section to cover the intersection with the given range. +- * +- * Returns false if the intersection is empty, otherwise returns true. +- */ +-static bool virtio_mem_intersect_memory_section(MemoryRegionSection *s, +- uint64_t offset, uint64_t size) +-{ +- uint64_t start = MAX(s->offset_within_region, offset); +- uint64_t end = MIN(s->offset_within_region + int128_get64(s->size), +- offset + size); +- +- if (end <= start) { +- return false; +- } +- +- s->offset_within_address_space += start - s->offset_within_region; +- s->offset_within_region = start; +- s->size = int128_make64(end - start); +- return true; +-} +- + typedef int (*virtio_mem_section_cb)(MemoryRegionSection *s, void *arg); + + static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, +@@ -278,7 +256,7 @@ static int virtio_mem_for_each_plugged_section(const VirtIOMEM *vmem, + first_bit + 1) - 1; + size = (last_bit - first_bit + 1) * vmem->block_size; + +- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { ++ if (!memory_region_section_intersect_range(&tmp, offset, size)) { + break; + } + ret = cb(&tmp, arg); +@@ -310,7 +288,7 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, + first_bit + 1) - 1; + size = (last_bit - first_bit + 1) * vmem->block_size; + +- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { ++ if (!memory_region_section_intersect_range(&tmp, offset, size)) { + break; + } + ret = cb(&tmp, arg); +@@ -346,7 +324,7 @@ static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset, + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { + MemoryRegionSection tmp = *rdl->section; + +- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { ++ if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + rdl->notify_discard(rdl, &tmp); +@@ -362,7 +340,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { + MemoryRegionSection tmp = *rdl->section; + +- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { ++ if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + ret = rdl->notify_populate(rdl, &tmp); +@@ -379,7 +357,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, + if (rdl2 == rdl) { + break; + } +- if (!virtio_mem_intersect_memory_section(&tmp, offset, size)) { ++ if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } + rdl2->notify_discard(rdl2, &tmp); +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 0361ec2054..950362d53c 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -1272,6 +1272,33 @@ MemoryRegionSection *memory_region_section_new_copy(MemoryRegionSection *s); + */ + void memory_region_section_free_copy(MemoryRegionSection *s); + ++/** ++ * memory_region_section_intersect_range: Adjust the memory section to cover ++ * the intersection with the given range. ++ * ++ * @s: the #MemoryRegionSection to be adjusted ++ * @offset: the offset of the given range in the memory region ++ * @size: the size of the given range ++ * ++ * Returns false if the intersection is empty, otherwise returns true. ++ */ ++static inline bool memory_region_section_intersect_range(MemoryRegionSection *s, ++ uint64_t offset, uint64_t size) ++{ ++ uint64_t start = MAX(s->offset_within_region, offset); ++ Int128 end = int128_min(int128_add(int128_make64(s->offset_within_region), s->size), ++ int128_add(int128_make64(offset), int128_make64(size))); ++ ++ if (int128_le(end, int128_make64(start))) { ++ return false; ++ } ++ ++ s->offset_within_address_space += start - s->offset_within_region; ++ s->offset_within_region = start; ++ s->size = int128_sub(end, int128_make64(start)); ++ return true; ++} ++ + /** + * memory_region_init: Initialize a memory region + * +-- +2.33.0 + diff --git a/memory-Introduce-PrivateSharedManager-Interface-as-c.patch b/memory-Introduce-PrivateSharedManager-Interface-as-c.patch new file mode 100644 index 00000000..884819dc --- /dev/null +++ b/memory-Introduce-PrivateSharedManager-Interface-as-c.patch @@ -0,0 +1,152 @@ +From 8d2a28564e7642b156d2a8d7351c5a70011c4529 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:25 +0800 +Subject: [PATCH] memory: Introduce PrivateSharedManager Interface as child of + GenericStateManager + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/dd9686d946fcd8ebd5d5e7dec1fb8b1c05f8b980 + +To manage the private and shared RAM states in confidential VMs, +introduce a new class of PrivateShareManager as a child of +GenericStateManager, which inherits the six interface callbacks. With a +different interface type, it can be distinguished from the +RamDiscardManager object and provide the flexibility for addressing +specific requirements of confidential VMs in the future. + +Signed-off-by: Chenyi Qiang +Conflicts: + include/exec/memory.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + include/exec/memory.h | 44 +++++++++++++++++++++++++++++++++++++++++-- + system/memory.c | 17 +++++++++++++++++ + 2 files changed, 59 insertions(+), 2 deletions(-) + +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 652d71ddf0..964ec53afc 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -55,6 +55,12 @@ typedef struct RamDiscardManager RamDiscardManager; + DECLARE_OBJ_CHECKERS(RamDiscardManager, RamDiscardManagerClass, + RAM_DISCARD_MANAGER, TYPE_RAM_DISCARD_MANAGER); + ++#define TYPE_PRIVATE_SHARED_MANAGER "private-shared-manager" ++typedef struct PrivateSharedManagerClass PrivateSharedManagerClass; ++typedef struct PrivateSharedManager PrivateSharedManager; ++DECLARE_OBJ_CHECKERS(PrivateSharedManager, PrivateSharedManagerClass, ++ PRIVATE_SHARED_MANAGER, TYPE_PRIVATE_SHARED_MANAGER) ++ + #ifdef CONFIG_FUZZ + void fuzz_dma_read_cb(size_t addr, + size_t len, +@@ -749,6 +755,14 @@ void generic_state_manager_register_listener(GenericStateManager *gsm, + void generic_state_manager_unregister_listener(GenericStateManager *gsm, + StateChangeListener *scl); + ++static inline void state_change_listener_init(StateChangeListener *scl, ++ NotifyStateSet state_set_fn, ++ NotifyStateClear state_clear_fn) ++{ ++ scl->notify_to_state_set = state_set_fn; ++ scl->notify_to_state_clear = state_clear_fn; ++} ++ + typedef struct RamDiscardListener RamDiscardListener; + + struct RamDiscardListener { +@@ -770,8 +784,7 @@ static inline void ram_discard_listener_init(RamDiscardListener *rdl, + NotifyStateClear discard_fn, + bool double_discard_supported) + { +- rdl->scl.notify_to_state_set = populate_fn; +- rdl->scl.notify_to_state_clear = discard_fn; ++ state_change_listener_init(&rdl->scl, populate_fn, discard_fn); + rdl->double_discard_supported = double_discard_supported; + } + +@@ -814,6 +827,25 @@ struct RamDiscardManagerClass { + GenericStateManagerClass parent_class; + }; + ++typedef struct PrivateSharedListener PrivateSharedListener; ++struct PrivateSharedListener { ++ struct StateChangeListener scl; ++ ++ QLIST_ENTRY(PrivateSharedListener) next; ++}; ++ ++struct PrivateSharedManagerClass { ++ /* private */ ++ GenericStateManagerClass parent_class; ++}; ++ ++static inline void private_shared_listener_init(PrivateSharedListener *psl, ++ NotifyStateSet populate_fn, ++ NotifyStateClear discard_fn) ++{ ++ state_change_listener_init(&psl->scl, populate_fn, discard_fn); ++} ++ + bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, + bool *mr_has_discard_manager); +@@ -2588,6 +2620,14 @@ int memory_region_set_generic_state_manager(MemoryRegion *mr, + */ + bool memory_region_has_ram_discard_manager(MemoryRegion *mr); + ++/** ++ * memory_region_has_private_shared_manager: check whether a #MemoryRegion has a ++ * #PrivateSharedManager assigned ++ * ++ * @mr: the #MemoryRegion ++ */ ++bool memory_region_has_private_shared_manager(MemoryRegion *mr); ++ + /** + * memory_region_find: translate an address/size relative to a + * MemoryRegion into a #MemoryRegionSection. +diff --git a/system/memory.c b/system/memory.c +index 38f73eb48b..fa99009701 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -2143,6 +2143,16 @@ bool memory_region_has_ram_discard_manager(MemoryRegion *mr) + return true; + } + ++bool memory_region_has_private_shared_manager(MemoryRegion *mr) ++{ ++ if (!memory_region_is_ram(mr) || ++ !object_dynamic_cast(OBJECT(mr->gsm), TYPE_PRIVATE_SHARED_MANAGER)) { ++ return false; ++ } ++ ++ return true; ++} ++ + uint64_t generic_state_manager_get_min_granularity(const GenericStateManager *gsm, + const MemoryRegion *mr) + { +@@ -3760,12 +3770,19 @@ static const TypeInfo ram_discard_manager_info = { + .class_size = sizeof(RamDiscardManagerClass), + }; + ++static const TypeInfo private_shared_manager_info = { ++ .parent = TYPE_GENERIC_STATE_MANAGER, ++ .name = TYPE_PRIVATE_SHARED_MANAGER, ++ .class_size = sizeof(PrivateSharedManagerClass), ++}; ++ + static void memory_register_types(void) + { + type_register_static(&memory_region_info); + type_register_static(&iommu_memory_region_info); + type_register_static(&generic_state_manager_info); + type_register_static(&ram_discard_manager_info); ++ type_register_static(&private_shared_manager_info); + } + + type_init(memory_register_types) +-- +2.33.0 + diff --git a/memory-Introduce-generic-state-change-parent-class-f.patch b/memory-Introduce-generic-state-change-parent-class-f.patch new file mode 100644 index 00000000..fb5944ca --- /dev/null +++ b/memory-Introduce-generic-state-change-parent-class-f.patch @@ -0,0 +1,1145 @@ +From c0f15fa6a2c663bba5cf56f98bdcfec20dc2e807 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:24 +0800 +Subject: [PATCH] memory: Introduce generic state change parent class for + RamDiscardManager + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/31df9c4804e4e422e27a18ca9a7e22b4123203d1 + +RamDiscardManager is an interface used by virtio-mem to adjust VFIO +mappings in relation to VM page assignment. It manages the state of +populated and discard for the RAM. To accommodate future scnarios for +managing RAM states, such as private and shared states in confidential +VMs, the existing RamDiscardManager interface needs to be generalized. + +Introduce a parent class, GenericStateManager, to manage a pair of +opposite states with RamDiscardManager as its child. The changes include +- Define a new abstract class GenericStateChange. +- Extract six callbacks into GenericStateChangeClass and allow the child + classes to inherit them. +- Modify RamDiscardManager-related helpers to use GenericStateManager + ones. +- Define a generic StatChangeListener to extract fields from + RamDiscardManager listener which allows future listeners to embed it + and avoid duplication. +- Change the users of RamDiscardManager (virtio-mem, migration, etc.) to + switch to use GenericStateChange helpers. + +It can provide a more flexible and resuable framework for RAM state +management, facilitating future enhancements and use cases. + +Signed-off-by: Chenyi Qiang +Conflicts: + hw/vfio/common.c + include/exec/memory.h + system/memory.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/vfio/common.c | 30 ++-- + hw/virtio/virtio-mem.c | 95 ++++++------ + include/exec/memory.h | 313 ++++++++++++++++++++++------------------ + migration/ram.c | 16 +- + system/memory.c | 106 ++++++++------ + system/memory_mapping.c | 6 +- + 6 files changed, 310 insertions(+), 256 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 0be63c5fbc..ab7450f3bd 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -350,9 +350,10 @@ out: + rcu_read_unlock(); + } + +-static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl, ++static void vfio_ram_discard_notify_discard(StateChangeListener *scl, + MemoryRegionSection *section) + { ++ RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, + listener); + VFIOContainerBase *bcontainer = vrdl->bcontainer; +@@ -368,9 +369,10 @@ static void vfio_ram_discard_notify_discard(RamDiscardListener *rdl, + } + } + +-static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl, ++static int vfio_ram_discard_notify_populate(StateChangeListener *scl, + MemoryRegionSection *section) + { ++ RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, + listener); + VFIOContainerBase *bcontainer = vrdl->bcontainer; +@@ -396,7 +398,7 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl, + vaddr, section->readonly); + if (ret) { + /* Rollback */ +- vfio_ram_discard_notify_discard(rdl, section); ++ vfio_ram_discard_notify_discard(scl, section); + return ret; + } + } +@@ -406,8 +408,9 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl, + static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) + { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); + VFIORamDiscardListener *vrdl; ++ RamDiscardListener *rdl; + + /* Ignore some corner cases not relevant in practice. */ + g_assert(QEMU_IS_ALIGNED(section->offset_within_region, TARGET_PAGE_SIZE)); +@@ -420,17 +423,18 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, + vrdl->mr = section->mr; + vrdl->offset_within_address_space = section->offset_within_address_space; + vrdl->size = int128_get64(section->size); +- vrdl->granularity = ram_discard_manager_get_min_granularity(rdm, +- section->mr); ++ vrdl->granularity = generic_state_manager_get_min_granularity(gsm, ++ section->mr); + + g_assert(vrdl->granularity && is_power_of_2(vrdl->granularity)); + g_assert(bcontainer->pgsizes && + vrdl->granularity >= 1ULL << ctz64(bcontainer->pgsizes)); + +- ram_discard_listener_init(&vrdl->listener, ++ rdl = &vrdl->listener; ++ ram_discard_listener_init(rdl, + vfio_ram_discard_notify_populate, + vfio_ram_discard_notify_discard, true); +- ram_discard_manager_register_listener(rdm, &vrdl->listener, section); ++ generic_state_manager_register_listener(gsm, &rdl->scl, section); + QLIST_INSERT_HEAD(&bcontainer->vrdl_list, vrdl, next); + + /* +@@ -480,8 +484,9 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, + static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) + { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); + VFIORamDiscardListener *vrdl = NULL; ++ RamDiscardListener *rdl; + + QLIST_FOREACH(vrdl, &bcontainer->vrdl_list, next) { + if (vrdl->mr == section->mr && +@@ -495,7 +500,8 @@ static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, + hw_error("vfio: Trying to unregister missing RAM discard listener"); + } + +- ram_discard_manager_unregister_listener(rdm, &vrdl->listener); ++ rdl = &vrdl->listener; ++ generic_state_manager_unregister_listener(gsm, &rdl->scl); + QLIST_REMOVE(vrdl, next); + g_free(vrdl); + } +@@ -1275,7 +1281,7 @@ static int + vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) + { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); + VFIORamDiscardListener *vrdl = NULL; + + QLIST_FOREACH(vrdl, &bcontainer->vrdl_list, next) { +@@ -1294,7 +1300,7 @@ vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainerBase *bcontainer, + * We only want/can synchronize the bitmap for actually mapped parts - + * which correspond to populated parts. Replay all populated parts. + */ +- return ram_discard_manager_replay_populated(rdm, section, ++ return generic_state_manager_replay_on_state_set(gsm, section, + vfio_ram_discard_get_dirty_bitmap, + &vrdl); + } +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index f40a816b7f..d60bc994ad 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -303,16 +303,16 @@ static int virtio_mem_for_each_unplugged_section(const VirtIOMEM *vmem, + + static int virtio_mem_notify_populate_cb(MemoryRegionSection *s, void *arg) + { +- RamDiscardListener *rdl = arg; ++ StateChangeListener *scl = arg; + +- return rdl->notify_populate(rdl, s); ++ return scl->notify_to_state_set(scl, s); + } + + static int virtio_mem_notify_discard_cb(MemoryRegionSection *s, void *arg) + { +- RamDiscardListener *rdl = arg; ++ StateChangeListener *scl = arg; + +- rdl->notify_discard(rdl, s); ++ scl->notify_to_state_clear(scl, s); + return 0; + } + +@@ -322,12 +322,13 @@ static void virtio_mem_notify_unplug(VirtIOMEM *vmem, uint64_t offset, + RamDiscardListener *rdl; + + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { +- MemoryRegionSection tmp = *rdl->section; ++ StateChangeListener *scl = &rdl->scl; ++ MemoryRegionSection tmp = *scl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } +- rdl->notify_discard(rdl, &tmp); ++ scl->notify_to_state_clear(scl, &tmp); + } + } + +@@ -338,12 +339,13 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, + int ret = 0; + + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { +- MemoryRegionSection tmp = *rdl->section; ++ StateChangeListener *scl = &rdl->scl; ++ MemoryRegionSection tmp = *scl->section; + + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } +- ret = rdl->notify_populate(rdl, &tmp); ++ ret = scl->notify_to_state_set(scl, &tmp); + if (ret) { + break; + } +@@ -352,7 +354,8 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, + if (ret) { + /* Notify all already-notified listeners. */ + QLIST_FOREACH(rdl2, &vmem->rdl_list, next) { +- MemoryRegionSection tmp = *rdl2->section; ++ StateChangeListener *scl2 = &rdl2->scl; ++ MemoryRegionSection tmp = *scl2->section; + + if (rdl2 == rdl) { + break; +@@ -360,7 +363,7 @@ static int virtio_mem_notify_plug(VirtIOMEM *vmem, uint64_t offset, + if (!memory_region_section_intersect_range(&tmp, offset, size)) { + continue; + } +- rdl2->notify_discard(rdl2, &tmp); ++ scl2->notify_to_state_clear(scl2, &tmp); + } + } + return ret; +@@ -375,10 +378,11 @@ static void virtio_mem_notify_unplug_all(VirtIOMEM *vmem) + } + + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { ++ StateChangeListener *scl = &rdl->scl; + if (rdl->double_discard_supported) { +- rdl->notify_discard(rdl, rdl->section); ++ scl->notify_to_state_clear(scl, scl->section); + } else { +- virtio_mem_for_each_plugged_section(vmem, rdl->section, rdl, ++ virtio_mem_for_each_plugged_section(vmem, scl->section, scl, + virtio_mem_notify_discard_cb); + } + } +@@ -1053,8 +1057,8 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp) + * Set ourselves as RamDiscardManager before the plug handler maps the + * memory region and exposes it via an address space. + */ +- if (memory_region_set_ram_discard_manager(&vmem->memdev->mr, +- RAM_DISCARD_MANAGER(vmem))) { ++ if (memory_region_set_generic_state_manager(&vmem->memdev->mr, ++ GENERIC_STATE_MANAGER(vmem))) { + error_setg(errp, "Failed to set RamDiscardManager"); + ram_block_coordinated_discard_require(false); + return; +@@ -1135,7 +1139,7 @@ static void virtio_mem_device_unrealize(DeviceState *dev) + * The unplug handler unmapped the memory region, it cannot be + * found via an address space anymore. Unset ourselves. + */ +- memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL); ++ memory_region_set_generic_state_manager(&vmem->memdev->mr, NULL); + ram_block_coordinated_discard_require(false); + } + +@@ -1184,7 +1188,8 @@ static int virtio_mem_post_load_bitmap(VirtIOMEM *vmem) + * into an address space. Replay, now that we updated the bitmap. + */ + QLIST_FOREACH(rdl, &vmem->rdl_list, next) { +- ret = virtio_mem_for_each_plugged_section(vmem, rdl->section, rdl, ++ StateChangeListener *scl = &rdl->scl; ++ ret = virtio_mem_for_each_plugged_section(vmem, scl->section, scl, + virtio_mem_notify_populate_cb); + if (ret) { + return ret; +@@ -1683,19 +1688,19 @@ static Property virtio_mem_properties[] = { + DEFINE_PROP_END_OF_LIST(), + }; + +-static uint64_t virtio_mem_rdm_get_min_granularity(const RamDiscardManager *rdm, ++static uint64_t virtio_mem_rdm_get_min_granularity(const GenericStateManager *gsm, + const MemoryRegion *mr) + { +- const VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ const VirtIOMEM *vmem = VIRTIO_MEM(gsm); + + g_assert(mr == &vmem->memdev->mr); + return vmem->block_size; + } + +-static bool virtio_mem_rdm_is_populated(const RamDiscardManager *rdm, ++static bool virtio_mem_rdm_is_populated(const GenericStateManager *gsm, + const MemoryRegionSection *s) + { +- const VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ const VirtIOMEM *vmem = VIRTIO_MEM(gsm); + uint64_t start_gpa = vmem->addr + s->offset_within_region; + uint64_t end_gpa = start_gpa + int128_get64(s->size); + +@@ -1723,12 +1728,12 @@ static int virtio_mem_rdm_replay_populated_cb(MemoryRegionSection *s, void *arg) + return data->fn(s, data->opaque); + } + +-static int virtio_mem_rdm_replay_populated(const RamDiscardManager *rdm, ++static int virtio_mem_rdm_replay_populated(const GenericStateManager *gsm, + MemoryRegionSection *s, + ReplayStateChange replay_fn, + void *opaque) + { +- const VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ const VirtIOMEM *vmem = VIRTIO_MEM(gsm); + struct VirtIOMEMReplayData data = { + .fn = replay_fn, + .opaque = opaque, +@@ -1748,12 +1753,12 @@ static int virtio_mem_rdm_replay_discarded_cb(MemoryRegionSection *s, + return 0; + } + +-static int virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, ++static int virtio_mem_rdm_replay_discarded(const GenericStateManager *gsm, + MemoryRegionSection *s, + ReplayStateChange replay_fn, + void *opaque) + { +- const VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ const VirtIOMEM *vmem = VIRTIO_MEM(gsm); + struct VirtIOMEMReplayData data = { + .fn = replay_fn, + .opaque = opaque, +@@ -1764,18 +1769,19 @@ static int virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, + virtio_mem_rdm_replay_discarded_cb); + } + +-static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl, ++static void virtio_mem_rdm_register_listener(GenericStateManager *gsm, ++ StateChangeListener *scl, + MemoryRegionSection *s) + { +- VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ VirtIOMEM *vmem = VIRTIO_MEM(gsm); ++ RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + int ret; + + g_assert(s->mr == &vmem->memdev->mr); +- rdl->section = memory_region_section_new_copy(s); ++ scl->section = memory_region_section_new_copy(s); + + QLIST_INSERT_HEAD(&vmem->rdl_list, rdl, next); +- ret = virtio_mem_for_each_plugged_section(vmem, rdl->section, rdl, ++ ret = virtio_mem_for_each_plugged_section(vmem, scl->section, scl, + virtio_mem_notify_populate_cb); + if (ret) { + error_report("%s: Replaying plugged ranges failed: %s", __func__, +@@ -1783,23 +1789,24 @@ static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm, + } + } + +-static void virtio_mem_rdm_unregister_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl) ++static void virtio_mem_rdm_unregister_listener(GenericStateManager *gsm, ++ StateChangeListener *scl) + { +- VirtIOMEM *vmem = VIRTIO_MEM(rdm); ++ VirtIOMEM *vmem = VIRTIO_MEM(gsm); ++ RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + +- g_assert(rdl->section->mr == &vmem->memdev->mr); ++ g_assert(scl->section->mr == &vmem->memdev->mr); + if (vmem->size) { + if (rdl->double_discard_supported) { +- rdl->notify_discard(rdl, rdl->section); ++ scl->notify_to_state_clear(scl, scl->section); + } else { +- virtio_mem_for_each_plugged_section(vmem, rdl->section, rdl, ++ virtio_mem_for_each_plugged_section(vmem, scl->section, scl, + virtio_mem_notify_discard_cb); + } + } + +- memory_region_section_free_copy(rdl->section); +- rdl->section = NULL; ++ memory_region_section_free_copy(scl->section); ++ scl->section = NULL; + QLIST_REMOVE(rdl, next); + } + +@@ -1832,7 +1839,7 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass); +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_CLASS(klass); + + device_class_set_props(dc, virtio_mem_properties); + dc->vmsd = &vmstate_virtio_mem; +@@ -1853,12 +1860,12 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data) + vmc->remove_size_change_notifier = virtio_mem_remove_size_change_notifier; + vmc->unplug_request_check = virtio_mem_unplug_request_check; + +- rdmc->get_min_granularity = virtio_mem_rdm_get_min_granularity; +- rdmc->is_populated = virtio_mem_rdm_is_populated; +- rdmc->replay_populated = virtio_mem_rdm_replay_populated; +- rdmc->replay_discarded = virtio_mem_rdm_replay_discarded; +- rdmc->register_listener = virtio_mem_rdm_register_listener; +- rdmc->unregister_listener = virtio_mem_rdm_unregister_listener; ++ gsmc->get_min_granularity = virtio_mem_rdm_get_min_granularity; ++ gsmc->is_state_set = virtio_mem_rdm_is_populated; ++ gsmc->replay_on_state_set = virtio_mem_rdm_replay_populated; ++ gsmc->replay_on_state_clear = virtio_mem_rdm_replay_discarded; ++ gsmc->register_listener = virtio_mem_rdm_register_listener; ++ gsmc->unregister_listener = virtio_mem_rdm_unregister_listener; + } + + static const TypeInfo virtio_mem_info = { +diff --git a/include/exec/memory.h b/include/exec/memory.h +index a3243ee218..652d71ddf0 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -43,6 +43,12 @@ typedef struct IOMMUMemoryRegionClass IOMMUMemoryRegionClass; + DECLARE_OBJ_CHECKERS(IOMMUMemoryRegion, IOMMUMemoryRegionClass, + IOMMU_MEMORY_REGION, TYPE_IOMMU_MEMORY_REGION) + ++#define TYPE_GENERIC_STATE_MANAGER "generic-state-manager" ++typedef struct GenericStateManagerClass GenericStateManagerClass; ++typedef struct GenericStateManager GenericStateManager; ++DECLARE_OBJ_CHECKERS(GenericStateManager, GenericStateManagerClass, ++ GENERIC_STATE_MANAGER, TYPE_GENERIC_STATE_MANAGER) ++ + #define TYPE_RAM_DISCARD_MANAGER "qemu:ram-discard-manager" + typedef struct RamDiscardManagerClass RamDiscardManagerClass; + typedef struct RamDiscardManager RamDiscardManager; +@@ -563,103 +569,59 @@ struct IOMMUMemoryRegionClass { + Error **errp); + }; + +-typedef struct RamDiscardListener RamDiscardListener; +-typedef int (*NotifyRamPopulate)(RamDiscardListener *rdl, +- MemoryRegionSection *section); +-typedef void (*NotifyRamDiscard)(RamDiscardListener *rdl, ++typedef int (*ReplayStateChange)(MemoryRegionSection *section, void *opaque); ++ ++typedef struct StateChangeListener StateChangeListener; ++typedef int (*NotifyStateSet)(StateChangeListener *scl, ++ MemoryRegionSection *section); ++typedef void (*NotifyStateClear)(StateChangeListener *scl, + MemoryRegionSection *section); + +-struct RamDiscardListener { ++struct StateChangeListener { + /* +- * @notify_populate: ++ * @notify_to_state_set: + * +- * Notification that previously discarded memory is about to get populated. +- * Listeners are able to object. If any listener objects, already +- * successfully notified listeners are notified about a discard again. ++ * Notification that previously state clear part is about to be set. + * +- * @rdl: the #RamDiscardListener getting notified +- * @section: the #MemoryRegionSection to get populated. The section ++ * @scl: the #StateChangeListener getting notified ++ * @section: the #MemoryRegionSection to be state-set. The section + * is aligned within the memory region to the minimum granularity + * unless it would exceed the registered section. + * + * Returns 0 on success. If the notification is rejected by the listener, + * an error is returned. + */ +- NotifyRamPopulate notify_populate; ++ NotifyStateSet notify_to_state_set; + + /* +- * @notify_discard: ++ * @notify_to_state_clear: + * +- * Notification that previously populated memory was discarded successfully +- * and listeners should drop all references to such memory and prevent +- * new population (e.g., unmap). ++ * Notification that previously state set part is about to be cleared + * +- * @rdl: the #RamDiscardListener getting notified +- * @section: the #MemoryRegionSection to get populated. The section ++ * @scl: the #StateChangeListener getting notified ++ * @section: the #MemoryRegionSection to be state-cleared. The section + * is aligned within the memory region to the minimum granularity + * unless it would exceed the registered section. +- */ +- NotifyRamDiscard notify_discard; +- +- /* +- * @double_discard_supported: + * +- * The listener suppors getting @notify_discard notifications that span +- * already discarded parts. ++ * Returns 0 on success. If the notification is rejected by the listener, ++ * an error is returned. + */ +- bool double_discard_supported; ++ NotifyStateClear notify_to_state_clear; + + MemoryRegionSection *section; +- QLIST_ENTRY(RamDiscardListener) next; + }; + +-static inline void ram_discard_listener_init(RamDiscardListener *rdl, +- NotifyRamPopulate populate_fn, +- NotifyRamDiscard discard_fn, +- bool double_discard_supported) +-{ +- rdl->notify_populate = populate_fn; +- rdl->notify_discard = discard_fn; +- rdl->double_discard_supported = double_discard_supported; +-} +- +-typedef int (*ReplayStateChange)(MemoryRegionSection *section, void *opaque); +- + /* +- * RamDiscardManagerClass: +- * +- * A #RamDiscardManager coordinates which parts of specific RAM #MemoryRegion +- * regions are currently populated to be used/accessed by the VM, notifying +- * after parts were discarded (freeing up memory) and before parts will be +- * populated (consuming memory), to be used/accessed by the VM. +- * +- * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the +- * #MemoryRegion isn't mapped into an address space yet (either directly +- * or via an alias); it cannot change while the #MemoryRegion is +- * mapped into an address space. ++ * GenericStateManagerClass: + * +- * The #RamDiscardManager is intended to be used by technologies that are +- * incompatible with discarding of RAM (e.g., VFIO, which may pin all +- * memory inside a #MemoryRegion), and require proper coordination to only +- * map the currently populated parts, to hinder parts that are expected to +- * remain discarded from silently getting populated and consuming memory. +- * Technologies that support discarding of RAM don't have to bother and can +- * simply map the whole #MemoryRegion. +- * +- * An example #RamDiscardManager is virtio-mem, which logically (un)plugs +- * memory within an assigned RAM #MemoryRegion, coordinated with the VM. +- * Logically unplugging memory consists of discarding RAM. The VM agreed to not +- * access unplugged (discarded) memory - especially via DMA. virtio-mem will +- * properly coordinate with listeners before memory is plugged (populated), +- * and after memory is unplugged (discarded). ++ * A #GenericStateManager is a common interface used to manage the state of ++ * a #MemoryRegion. The managed states is a pair of opposite states, such as ++ * populated and discarded, or private and shared. It is abstract as set and ++ * clear in below callbacks, and the actual state is managed by the ++ * implementation. + * +- * Listeners are called in multiples of the minimum granularity (unless it +- * would exceed the registered range) and changes are aligned to the minimum +- * granularity within the #MemoryRegion. Listeners have to prepare for memory +- * becoming discarded in a different granularity than it was populated and the +- * other way around. + */ +-struct RamDiscardManagerClass { ++struct GenericStateManagerClass { + /* private */ + InterfaceClass parent_class; + +@@ -669,122 +631,188 @@ struct RamDiscardManagerClass { + * @get_min_granularity: + * + * Get the minimum granularity in which listeners will get notified +- * about changes within the #MemoryRegion via the #RamDiscardManager. ++ * about changes within the #MemoryRegion via the #GenericStateManager. + * +- * @rdm: the #RamDiscardManager ++ * @gsm: the #GenericStateManager + * @mr: the #MemoryRegion + * + * Returns the minimum granularity. + */ +- uint64_t (*get_min_granularity)(const RamDiscardManager *rdm, ++ uint64_t (*get_min_granularity)(const GenericStateManager *gsm, + const MemoryRegion *mr); + + /** +- * @is_populated: ++ * @is_state_set: + * +- * Check whether the given #MemoryRegionSection is completely populated +- * (i.e., no parts are currently discarded) via the #RamDiscardManager. +- * There are no alignment requirements. ++ * Check whether the given #MemoryRegionSection state is set. ++ * via the #GenericStateManager. + * +- * @rdm: the #RamDiscardManager ++ * @gsm: the #GenericStateManager + * @section: the #MemoryRegionSection + * +- * Returns whether the given range is completely populated. ++ * Returns whether the given range is completely set. + */ +- bool (*is_populated)(const RamDiscardManager *rdm, ++ bool (*is_state_set)(const GenericStateManager *gsm, + const MemoryRegionSection *section); + + /** +- * @replay_populated: ++ * @replay_on_state_set: + * +- * Call the #ReplayStateChange callback for all populated parts within the +- * #MemoryRegionSection via the #RamDiscardManager. ++ * Call the #ReplayStateChange callback for all state set parts within the ++ * #MemoryRegionSection via the #GenericStateManager. + * + * In case any call fails, no further calls are made. + * +- * @rdm: the #RamDiscardManager ++ * @gsm: the #GenericStateManager + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayStateChange callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification failed. + */ +- int (*replay_populated)(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, void *opaque); ++ int (*replay_on_state_set)(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, void *opaque); + + /** +- * @replay_discarded: ++ * @replay_on_state_clear: + * +- * Call the #ReplayStateChange callback for all discarded parts within the +- * #MemoryRegionSection via the #RamDiscardManager. ++ * Call the #ReplayStateChange callback for all state clear parts within the ++ * #MemoryRegionSection via the #GenericStateManager. ++ * ++ * In case any call fails, no further calls are made. + * +- * @rdm: the #RamDiscardManager ++ * @gsm: the #GenericStateManager + * @section: the #MemoryRegionSection + * @replay_fn: the #ReplayStateChange callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification failed. + */ +- int (*replay_discarded)(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, void *opaque); ++ int (*replay_on_state_clear)(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, void *opaque); + + /** + * @register_listener: + * +- * Register a #RamDiscardListener for the given #MemoryRegionSection and +- * immediately notify the #RamDiscardListener about all populated parts +- * within the #MemoryRegionSection via the #RamDiscardManager. ++ * Register a #StateChangeListener for the given #MemoryRegionSection and ++ * immediately notify the #StateChangeListener about all state-set parts ++ * within the #MemoryRegionSection via the #GenericStateManager. + * + * In case any notification fails, no further notifications are triggered + * and an error is logged. + * +- * @rdm: the #RamDiscardManager +- * @rdl: the #RamDiscardListener ++ * @rdm: the #GenericStateManager ++ * @rdl: the #StateChangeListener + * @section: the #MemoryRegionSection + */ +- void (*register_listener)(RamDiscardManager *rdm, +- RamDiscardListener *rdl, ++ void (*register_listener)(GenericStateManager *gsm, ++ StateChangeListener *scl, + MemoryRegionSection *section); + + /** + * @unregister_listener: + * +- * Unregister a previously registered #RamDiscardListener via the +- * #RamDiscardManager after notifying the #RamDiscardListener about all +- * populated parts becoming unpopulated within the registered ++ * Unregister a previously registered #StateChangeListener via the ++ * #GenericStateManager after notifying the #StateChangeListener about all ++ * state-set parts becoming state-cleared within the registered + * #MemoryRegionSection. + * +- * @rdm: the #RamDiscardManager +- * @rdl: the #RamDiscardListener ++ * @rdm: the #GenericStateManager ++ * @rdl: the #StateChangeListener + */ +- void (*unregister_listener)(RamDiscardManager *rdm, +- RamDiscardListener *rdl); ++ void (*unregister_listener)(GenericStateManager *gsm, ++ StateChangeListener *scl); + }; + +-uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm, +- const MemoryRegion *mr); ++uint64_t generic_state_manager_get_min_granularity(const GenericStateManager *gsm, ++ const MemoryRegion *mr); + +-bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, +- const MemoryRegionSection *section); ++bool generic_state_manager_is_state_set(const GenericStateManager *gsm, ++ const MemoryRegionSection *section); + +-int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, +- void *opaque); ++int generic_state_manager_replay_on_state_set(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque); + +-int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, +- void *opaque); ++int generic_state_manager_replay_on_state_clear(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque); + +-void ram_discard_manager_register_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl, +- MemoryRegionSection *section); ++void generic_state_manager_register_listener(GenericStateManager *gsm, ++ StateChangeListener *scl, ++ MemoryRegionSection *section); + +-void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl); ++void generic_state_manager_unregister_listener(GenericStateManager *gsm, ++ StateChangeListener *scl); ++ ++typedef struct RamDiscardListener RamDiscardListener; ++ ++struct RamDiscardListener { ++ struct StateChangeListener scl; ++ ++ /* ++ * @double_discard_supported: ++ * ++ * The listener suppors getting @notify_discard notifications that span ++ * already discarded parts. ++ */ ++ bool double_discard_supported; ++ ++ QLIST_ENTRY(RamDiscardListener) next; ++}; ++ ++static inline void ram_discard_listener_init(RamDiscardListener *rdl, ++ NotifyStateSet populate_fn, ++ NotifyStateClear discard_fn, ++ bool double_discard_supported) ++{ ++ rdl->scl.notify_to_state_set = populate_fn; ++ rdl->scl.notify_to_state_clear = discard_fn; ++ rdl->double_discard_supported = double_discard_supported; ++} ++ ++/* ++ * RamDiscardManagerClass: ++ * ++ * A #RamDiscardManager coordinates which parts of specific RAM #MemoryRegion ++ * regions are currently populated to be used/accessed by the VM, notifying ++ * after parts were discarded (freeing up memory) and before parts will be ++ * populated (consuming memory), to be used/accessed by the VM. ++ * ++ * A #RamDiscardManager can only be set for a RAM #MemoryRegion while the ++ * #MemoryRegion isn't mapped into an address space yet (either directly ++ * or via an alias); it cannot change while the #MemoryRegion is ++ * mapped into an address space. ++ * ++ * The #RamDiscardManager is intended to be used by technologies that are ++ * incompatible with discarding of RAM (e.g., VFIO, which may pin all ++ * memory inside a #MemoryRegion), and require proper coordination to only ++ * map the currently populated parts, to hinder parts that are expected to ++ * remain discarded from silently getting populated and consuming memory. ++ * Technologies that support discarding of RAM don't have to bother and can ++ * simply map the whole #MemoryRegion. ++ * ++ * An example #RamDiscardManager is virtio-mem, which logically (un)plugs ++ * memory within an assigned RAM #MemoryRegion, coordinated with the VM. ++ * Logically unplugging memory consists of discarding RAM. The VM agreed to not ++ * access unplugged (discarded) memory - especially via DMA. virtio-mem will ++ * properly coordinate with listeners before memory is plugged (populated), ++ * and after memory is unplugged (discarded). ++ * ++ * Listeners are called in multiples of the minimum granularity (unless it ++ * would exceed the registered range) and changes are aligned to the minimum ++ * granularity within the #MemoryRegion. Listeners have to prepare for memory ++ * becoming discarded in a different granularity than it was populated and the ++ * other way around. ++ */ ++struct RamDiscardManagerClass { ++ /* private */ ++ GenericStateManagerClass parent_class; ++}; + + bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only, +@@ -851,7 +879,7 @@ struct MemoryRegion { + const char *name; + unsigned ioeventfd_nb; + MemoryRegionIoeventfd *ioeventfds; +- RamDiscardManager *rdm; /* Only for RAM */ ++ GenericStateManager *gsm; /* Only for RAM */ + + /* For devices designed to perform re-entrant IO into their own IO MRs */ + bool disable_reentrancy_guard; +@@ -2529,39 +2557,36 @@ bool memory_region_present(MemoryRegion *container, hwaddr addr); + bool memory_region_is_mapped(MemoryRegion *mr); + + /** +- * memory_region_get_ram_discard_manager: get the #RamDiscardManager for a ++ * memory_region_get_generic_state_manager: get the #GenericStateManager for a + * #MemoryRegion + * +- * The #RamDiscardManager cannot change while a memory region is mapped. ++ * The #GenericStateManager cannot change while a memory region is mapped. + * + * @mr: the #MemoryRegion + */ +-RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr); ++GenericStateManager *memory_region_get_generic_state_manager(MemoryRegion *mr); + + /** +- * memory_region_has_ram_discard_manager: check whether a #MemoryRegion has a +- * #RamDiscardManager assigned ++ * memory_region_set_generic_state_manager: set the #GenericStateManager for a ++ * #MemoryRegion ++ * ++ * This function must not be called for a mapped #MemoryRegion, a #MemoryRegion ++ * that does not cover RAM, or a #MemoryRegion that already has a ++ * #GenericStateManager assigned. Return 0 if the gsm is set successfully. + * + * @mr: the #MemoryRegion ++ * @gsm: #GenericStateManager to set + */ +-static inline bool memory_region_has_ram_discard_manager(MemoryRegion *mr) +-{ +- return !!memory_region_get_ram_discard_manager(mr); +-} ++int memory_region_set_generic_state_manager(MemoryRegion *mr, ++ GenericStateManager *gsm); + + /** +- * memory_region_set_ram_discard_manager: set the #RamDiscardManager for a +- * #MemoryRegion +- * +- * This function must not be called for a mapped #MemoryRegion, a #MemoryRegion +- * that does not cover RAM, or a #MemoryRegion that already has a +- * #RamDiscardManager assigned. Return 0 if the rdm is set successfully. ++ * memory_region_has_ram_discard_manager: check whether a #MemoryRegion has a ++ * #RamDiscardManager assigned + * + * @mr: the #MemoryRegion +- * @rdm: #RamDiscardManager to set + */ +-int memory_region_set_ram_discard_manager(MemoryRegion *mr, +- RamDiscardManager *rdm); ++bool memory_region_has_ram_discard_manager(MemoryRegion *mr); + + /** + * memory_region_find: translate an address/size relative to a +diff --git a/migration/ram.c b/migration/ram.c +index 083a8a8073..e6baecf143 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -882,14 +882,14 @@ static uint64_t ramblock_dirty_bitmap_clear_discarded_pages(RAMBlock *rb) + uint64_t cleared_bits = 0; + + if (rb->mr && rb->bmap && memory_region_has_ram_discard_manager(rb->mr)) { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = int128_make64(qemu_ram_get_used_length(rb)), + }; + +- ram_discard_manager_replay_discarded(rdm, §ion, ++ generic_state_manager_replay_on_state_clear(gsm, §ion, + dirty_bitmap_clear_section, + &cleared_bits); + } +@@ -905,14 +905,14 @@ static uint64_t ramblock_dirty_bitmap_clear_discarded_pages(RAMBlock *rb) + bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start) + { + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = start, + .size = int128_make64(qemu_ram_pagesize(rb)), + }; + +- return !ram_discard_manager_is_populated(rdm, §ion); ++ return !generic_state_manager_is_state_set(gsm, §ion); + } + return false; + } +@@ -1732,14 +1732,14 @@ static void ram_block_populate_read(RAMBlock *rb) + * Note: The result is only stable while migrating (precopy/postcopy). + */ + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = rb->mr->size, + }; + +- ram_discard_manager_replay_populated(rdm, §ion, ++ generic_state_manager_replay_on_state_set(gsm, §ion, + populate_read_section, NULL); + } else { + populate_read_range(rb, 0, rb->used_length); +@@ -1791,14 +1791,14 @@ static int ram_block_uffd_protect(RAMBlock *rb, int uffd_fd) + + /* See ram_block_populate_read() */ + if (rb->mr && memory_region_has_ram_discard_manager(rb->mr)) { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(rb->mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(rb->mr); + MemoryRegionSection section = { + .mr = rb->mr, + .offset_within_region = 0, + .size = rb->mr->size, + }; + +- return ram_discard_manager_replay_populated(rdm, §ion, ++ return generic_state_manager_replay_on_state_set(gsm, §ion, + uffd_protect_section, + (void *)(uintptr_t)uffd_fd); + } +diff --git a/system/memory.c b/system/memory.c +index ace79b0f59..38f73eb48b 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -2113,83 +2113,93 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr) + return imrc->num_indexes(iommu_mr); + } + +-RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr) ++GenericStateManager *memory_region_get_generic_state_manager(MemoryRegion *mr) + { + if (!memory_region_is_ram(mr)) { + return NULL; + } +- return mr->rdm; ++ return mr->gsm; + } + +-int memory_region_set_ram_discard_manager(MemoryRegion *mr, +- RamDiscardManager *rdm) ++int memory_region_set_generic_state_manager(MemoryRegion *mr, ++ GenericStateManager *gsm) + { + g_assert(memory_region_is_ram(mr)); +- if (mr->rdm && rdm) { ++ if (mr->gsm && gsm) { + return -EBUSY; + } + +- mr->rdm = rdm; ++ mr->gsm = gsm; + return 0; + } + +-uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm, +- const MemoryRegion *mr) ++bool memory_region_has_ram_discard_manager(MemoryRegion *mr) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ if (!memory_region_is_ram(mr) || ++ !object_dynamic_cast(OBJECT(mr->gsm), TYPE_RAM_DISCARD_MANAGER)) { ++ return false; ++ } ++ ++ return true; ++} ++ ++uint64_t generic_state_manager_get_min_granularity(const GenericStateManager *gsm, ++ const MemoryRegion *mr) ++{ ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->get_min_granularity); +- return rdmc->get_min_granularity(rdm, mr); ++ g_assert(gsmc->get_min_granularity); ++ return gsmc->get_min_granularity(gsm, mr); + } + +-bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, +- const MemoryRegionSection *section) ++bool generic_state_manager_is_state_set(const GenericStateManager *gsm, ++ const MemoryRegionSection *section) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->is_populated); +- return rdmc->is_populated(rdm, section); ++ g_assert(gsmc->is_state_set); ++ return gsmc->is_state_set(gsm, section); + } + +-int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, +- void *opaque) ++int generic_state_manager_replay_on_state_set(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->replay_populated); +- return rdmc->replay_populated(rdm, section, replay_fn, opaque); ++ g_assert(gsmc->replay_on_state_set); ++ return gsmc->replay_on_state_set(gsm, section, replay_fn, opaque); + } + +-int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayStateChange replay_fn, +- void *opaque) ++int generic_state_manager_replay_on_state_clear(const GenericStateManager *gsm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->replay_discarded); +- return rdmc->replay_discarded(rdm, section, replay_fn, opaque); ++ g_assert(gsmc->replay_on_state_clear); ++ return gsmc->replay_on_state_clear(gsm, section, replay_fn, opaque); + } + +-void ram_discard_manager_register_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl, +- MemoryRegionSection *section) ++void generic_state_manager_register_listener(GenericStateManager *gsm, ++ StateChangeListener *scl, ++ MemoryRegionSection *section) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->register_listener); +- rdmc->register_listener(rdm, rdl, section); ++ g_assert(gsmc->register_listener); ++ gsmc->register_listener(gsm, scl, section); + } + +-void ram_discard_manager_unregister_listener(RamDiscardManager *rdm, +- RamDiscardListener *rdl) ++void generic_state_manager_unregister_listener(GenericStateManager *gsm, ++ StateChangeListener *scl) + { +- RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); ++ GenericStateManagerClass *gsmc = GENERIC_STATE_MANAGER_GET_CLASS(gsm); + +- g_assert(rdmc->unregister_listener); +- rdmc->unregister_listener(rdm, rdl); ++ g_assert(gsmc->unregister_listener); ++ gsmc->unregister_listener(gsm, scl); + } + + /* Called with rcu_read_lock held. */ +@@ -2216,7 +2226,7 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + error_report("iommu map to non memory area %" HWADDR_PRIx "", xlat); + return false; + } else if (memory_region_has_ram_discard_manager(mr)) { +- RamDiscardManager *rdm = memory_region_get_ram_discard_manager(mr); ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(mr); + MemoryRegionSection tmp = { + .mr = mr, + .offset_within_region = xlat, +@@ -2231,7 +2241,7 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + * Disallow that. vmstate priorities make sure any RamDiscardManager + * were already restored before IOMMUs are restored. + */ +- if (!ram_discard_manager_is_populated(rdm, &tmp)) { ++ if (!generic_state_manager_is_state_set(gsm, &tmp)) { + error_report("iommu map to discarded memory (e.g., unplugged via" + " virtio-mem): %" HWADDR_PRIx "", + iotlb->translated_addr); +@@ -3737,8 +3747,15 @@ static const TypeInfo iommu_memory_region_info = { + .abstract = true, + }; + +-static const TypeInfo ram_discard_manager_info = { ++static const TypeInfo generic_state_manager_info = { + .parent = TYPE_INTERFACE, ++ .name = TYPE_GENERIC_STATE_MANAGER, ++ .class_size = sizeof(GenericStateManagerClass), ++ .abstract = true, ++}; ++ ++static const TypeInfo ram_discard_manager_info = { ++ .parent = TYPE_GENERIC_STATE_MANAGER, + .name = TYPE_RAM_DISCARD_MANAGER, + .class_size = sizeof(RamDiscardManagerClass), + }; +@@ -3747,6 +3764,7 @@ static void memory_register_types(void) + { + type_register_static(&memory_region_info); + type_register_static(&iommu_memory_region_info); ++ type_register_static(&generic_state_manager_info); + type_register_static(&ram_discard_manager_info); + } + +diff --git a/system/memory_mapping.c b/system/memory_mapping.c +index 6f884c5b90..7bd8972b55 100644 +--- a/system/memory_mapping.c ++++ b/system/memory_mapping.c +@@ -270,10 +270,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener, + + /* for special sparse regions, only add populated parts */ + if (memory_region_has_ram_discard_manager(section->mr)) { +- RamDiscardManager *rdm; +- +- rdm = memory_region_get_ram_discard_manager(section->mr); +- ram_discard_manager_replay_populated(rdm, section, ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); ++ generic_state_manager_replay_on_state_set(gsm, section, + guest_phys_ram_populate_cb, g); + return; + } +-- +2.33.0 + diff --git a/memory-Unify-the-definiton-of-ReplayRamPopulate-and-.patch b/memory-Unify-the-definiton-of-ReplayRamPopulate-and-.patch new file mode 100644 index 00000000..1e31cc4d --- /dev/null +++ b/memory-Unify-the-definiton-of-ReplayRamPopulate-and-.patch @@ -0,0 +1,222 @@ +From b18b91d25cd224fd4920b804a401c90a6f5ed2b8 Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:23 +0800 +Subject: [PATCH] memory: Unify the definiton of ReplayRamPopulate() and + ReplayRamDiscard() + +Reference:https://gitlab.com/qemu-project/qemu/-/commit/2205b8466733f8c6e3306c964f31c5a7cac69dfa + +Update ReplayRamDiscard() function to return the result and unify the +ReplayRamPopulate() and ReplayRamDiscard() to ReplayStateChange() at +the same time due to their identical definitions. This unification +simplifies related structures, such as VirtIOMEMReplayData, which makes +it more cleaner and maintainable. + +Signed-off-by: Chenyi Qiang +Signed-off-by: houmingyong +--- + hw/virtio/virtio-mem.c | 20 ++++++++++---------- + include/exec/memory.h | 31 ++++++++++++++++--------------- + migration/ram.c | 5 +++-- + system/memory.c | 12 ++++++------ + 4 files changed, 35 insertions(+), 33 deletions(-) + +diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c +index 6f3ecddfc7..f40a816b7f 100644 +--- a/hw/virtio/virtio-mem.c ++++ b/hw/virtio/virtio-mem.c +@@ -1712,7 +1712,7 @@ static bool virtio_mem_rdm_is_populated(const RamDiscardManager *rdm, + } + + struct VirtIOMEMReplayData { +- void *fn; ++ ReplayStateChange fn; + void *opaque; + }; + +@@ -1720,12 +1720,12 @@ static int virtio_mem_rdm_replay_populated_cb(MemoryRegionSection *s, void *arg) + { + struct VirtIOMEMReplayData *data = arg; + +- return ((ReplayRamPopulate)data->fn)(s, data->opaque); ++ return data->fn(s, data->opaque); + } + + static int virtio_mem_rdm_replay_populated(const RamDiscardManager *rdm, + MemoryRegionSection *s, +- ReplayRamPopulate replay_fn, ++ ReplayStateChange replay_fn, + void *opaque) + { + const VirtIOMEM *vmem = VIRTIO_MEM(rdm); +@@ -1744,14 +1744,14 @@ static int virtio_mem_rdm_replay_discarded_cb(MemoryRegionSection *s, + { + struct VirtIOMEMReplayData *data = arg; + +- ((ReplayRamDiscard)data->fn)(s, data->opaque); ++ data->fn(s, data->opaque); + return 0; + } + +-static void virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, +- MemoryRegionSection *s, +- ReplayRamDiscard replay_fn, +- void *opaque) ++static int virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, ++ MemoryRegionSection *s, ++ ReplayStateChange replay_fn, ++ void *opaque) + { + const VirtIOMEM *vmem = VIRTIO_MEM(rdm); + struct VirtIOMEMReplayData data = { +@@ -1760,8 +1760,8 @@ static void virtio_mem_rdm_replay_discarded(const RamDiscardManager *rdm, + }; + + g_assert(s->mr == &vmem->memdev->mr); +- virtio_mem_for_each_unplugged_section(vmem, s, &data, +- virtio_mem_rdm_replay_discarded_cb); ++ return virtio_mem_for_each_unplugged_section(vmem, s, &data, ++ virtio_mem_rdm_replay_discarded_cb); + } + + static void virtio_mem_rdm_register_listener(RamDiscardManager *rdm, +diff --git a/include/exec/memory.h b/include/exec/memory.h +index a4e9e084cd..a3243ee218 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -623,8 +623,7 @@ static inline void ram_discard_listener_init(RamDiscardListener *rdl, + rdl->double_discard_supported = double_discard_supported; + } + +-typedef int (*ReplayRamPopulate)(MemoryRegionSection *section, void *opaque); +-typedef void (*ReplayRamDiscard)(MemoryRegionSection *section, void *opaque); ++typedef int (*ReplayStateChange)(MemoryRegionSection *section, void *opaque); + + /* + * RamDiscardManagerClass: +@@ -698,36 +697,38 @@ struct RamDiscardManagerClass { + /** + * @replay_populated: + * +- * Call the #ReplayRamPopulate callback for all populated parts within the ++ * Call the #ReplayStateChange callback for all populated parts within the + * #MemoryRegionSection via the #RamDiscardManager. + * + * In case any call fails, no further calls are made. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection +- * @replay_fn: the #ReplayRamPopulate callback ++ * @replay_fn: the #ReplayStateChange callback + * @opaque: pointer to forward to the callback + * + * Returns 0 on success, or a negative error if any notification failed. + */ + int (*replay_populated)(const RamDiscardManager *rdm, + MemoryRegionSection *section, +- ReplayRamPopulate replay_fn, void *opaque); ++ ReplayStateChange replay_fn, void *opaque); + + /** + * @replay_discarded: + * +- * Call the #ReplayRamDiscard callback for all discarded parts within the ++ * Call the #ReplayStateChange callback for all discarded parts within the + * #MemoryRegionSection via the #RamDiscardManager. + * + * @rdm: the #RamDiscardManager + * @section: the #MemoryRegionSection +- * @replay_fn: the #ReplayRamDiscard callback ++ * @replay_fn: the #ReplayStateChange callback + * @opaque: pointer to forward to the callback ++ * ++ * Returns 0 on success, or a negative error if any notification failed. + */ +- void (*replay_discarded)(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayRamDiscard replay_fn, void *opaque); ++ int (*replay_discarded)(const RamDiscardManager *rdm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, void *opaque); + + /** + * @register_listener: +@@ -770,13 +771,13 @@ bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, + + int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, + MemoryRegionSection *section, +- ReplayRamPopulate replay_fn, ++ ReplayStateChange replay_fn, + void *opaque); + +-void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayRamDiscard replay_fn, +- void *opaque); ++int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque); + + void ram_discard_manager_register_listener(RamDiscardManager *rdm, + RamDiscardListener *rdl, +diff --git a/migration/ram.c b/migration/ram.c +index 91bec89a6e..083a8a8073 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -841,8 +841,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, + return ret; + } + +-static void dirty_bitmap_clear_section(MemoryRegionSection *section, +- void *opaque) ++static int dirty_bitmap_clear_section(MemoryRegionSection *section, ++ void *opaque) + { + const hwaddr offset = section->offset_within_region; + const hwaddr size = int128_get64(section->size); +@@ -861,6 +861,7 @@ static void dirty_bitmap_clear_section(MemoryRegionSection *section, + } + *cleared_bits += bitmap_count_one_with_offset(rb->bmap, start, npages); + bitmap_clear(rb->bmap, start, npages); ++ return 0; + } + + /* +diff --git a/system/memory.c b/system/memory.c +index c3985e8eef..ace79b0f59 100644 +--- a/system/memory.c ++++ b/system/memory.c +@@ -2153,7 +2153,7 @@ bool ram_discard_manager_is_populated(const RamDiscardManager *rdm, + + int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, + MemoryRegionSection *section, +- ReplayRamPopulate replay_fn, ++ ReplayStateChange replay_fn, + void *opaque) + { + RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); +@@ -2162,15 +2162,15 @@ int ram_discard_manager_replay_populated(const RamDiscardManager *rdm, + return rdmc->replay_populated(rdm, section, replay_fn, opaque); + } + +-void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, +- MemoryRegionSection *section, +- ReplayRamDiscard replay_fn, +- void *opaque) ++int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm, ++ MemoryRegionSection *section, ++ ReplayStateChange replay_fn, ++ void *opaque) + { + RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm); + + g_assert(rdmc->replay_discarded); +- rdmc->replay_discarded(rdm, section, replay_fn, opaque); ++ return rdmc->replay_discarded(rdm, section, replay_fn, opaque); + } + + void ram_discard_manager_register_listener(RamDiscardManager *rdm, +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 43f87215..d6e86575 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 38 +Release: 39 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -953,6 +953,50 @@ Patch0936: target-arm-Adjust-and-validate-mtedesc-sizem1.patch Patch0937: block-io-accept-NULL-qiov-in-bdrv_pad_request.patch Patch0938: target-arm-fix-qemu-arm-target-build-error.patch Patch0939: target-i386-Add-new-Hygon-Chengdu-CPU-model.patch +Patch0940: hw-acpi-Fix-the-memory-leak-issue.patch +Patch0941: virtio-net-Fix-num_buffers-for-version-1.patch +Patch0942: hw-net-cadence_gem-fix-register-mask-initialization.patch +Patch0943: memory-Export-a-helper-to-get-intersection-of-a-Memo.patch +Patch0944: memory-Change-memory_region_set_ram_discard_manager-.patch +Patch0945: memory-Unify-the-definiton-of-ReplayRamPopulate-and-.patch +Patch0946: memory-Introduce-generic-state-change-parent-class-f.patch +Patch0947: memory-Introduce-PrivateSharedManager-Interface-as-c.patch +Patch0948: vfio-Add-the-support-for-PrivateSharedManager-Interf.patch +Patch0949: memory-Change-NotifyStateClear-definition-to-return-.patch +Patch0950: ram-block-attribute-Add-priority-listener-support-fo.patch +Patch0951: linux-headers-Add-KVM-Arm-RME-definitions-to-Linux-h.patch +Patch0952: kvm-Use-kvm_vm_check_extension-where-necessary.patch +Patch0953: include-qom-object.h-New-OBJECT_DEFINE_SIMPLE_TYPE-_.patch +Patch0954: target-arm-Add-confidential-guest-support.patch +Patch0955: target-arm-kvm-Return-immediately-on-error-in-kvm_ar.patch +Patch0956: KVM-track-whether-guest-state-is-encrypted.patch +Patch0957: target-arm-kvm-rme-Initialize-realm.patch +Patch0958: target-arm-kvm-Split-kvm_arch_get-put_registers.patch +Patch0959: target-arm-kvm-rme-Initialize-vCPU.patch +Patch0960: target-arm-kvm-Create-scratch-VM-as-Realm-if-necessa.patch +Patch0961: hw-core-loader-Add-ROM-loader-notifier.patch +Patch0962: target-arm-kvm-rme-Initialize-Realm-memory.patch +Patch0963: target-arm-kvm-rme-Add-Realm-Personalization-Value-p.patch +Patch0964: target-arm-kvm-rme-Add-measurement-algorithm-propert.patch +Patch0965: target-arm-cpu-Set-number-of-breakpoints-and-watchpo.patch +Patch0966: target-arm-cpu-Set-number-of-PMU-counters-in-KVM.patch +Patch0967: target-arm-cpu-Inform-about-reading-confidential-CPU.patch +Patch0968: hw-arm-virt-Add-support-for-Arm-RME.patch +Patch0969: hw-arm-virt-Disable-DTB-randomness-for-confidential-.patch +Patch0970: hw-arm-virt-Reserve-one-bit-of-guest-physical-addres.patch +Patch0971: hw-arm-boot-Mark-all-guest-memory-as-RIPAS_RAM.patch +Patch0972: target-arm-kvm-rme-Add-DMA-remapping-for-the-shared-.patch +Patch0973: hw-arm-virt-Move-virt_flash_create-to-machvirt_init.patch +Patch0974: hw-arm-virt-Use-RAM-instead-of-flash-for-confidentia.patch +Patch0975: docs-interop-firmware.json-Add-arm-rme-firmware-feat.patch +Patch0976: hw-arm-boot-Load-DTB-as-is-for-confidential-VMs.patch +Patch0977: hw-arm-boot-Skip-bootloader-for-confidential-guests.patch +Patch0978: hw-tpm-Add-TPM-event-log.patch +Patch0979: hw-core-loader-Add-fields-to-RomLoaderNotify.patch +Patch0980: target-arm-kvm-rme-Add-measurement-log.patch +Patch0981: hw-arm-virt-Add-measurement-log-for-confidential-boo.patch +Patch0982: On-the-Adaptation-of-CCA-and-virtCCA.patch +Patch0983: Bugfix-Fix-compile-error-in-aarch32.patch BuildRequires: flex BuildRequires: gcc @@ -1551,6 +1595,111 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Tue Aug 26 2025 Pengrui Zhang - 11:8.2.0-39 +- hw/acpi: Fix the memory leak issue +- virtio-net: Fix num_buffers for version 1 +- hw/net/cadence_gem: fix register mask initialization +- memory: Export a helper to get intersection of a MemoryRegionSection with a given range +- memory: Change memory_region_set_ram_discard_manager() to return the result +- memory: Unify the definiton of ReplayRamPopulate() and ReplayRamDiscard() +- memory: Introduce generic state change parent class for RamDiscardManager +- memory: Introduce PrivateSharedManager Interface as child of GenericStateManager +- memory: Add the support for PrivateSharedManager Interface +- vfio: Add the support for PrivateSharedManager Interface +- memory: Change NotifyStateClear() definition to return the result +- ram-block-attribute: Add priority listener support for PrivateSharedListener +- linux-headers: Add KVM Arm RME definitions to Linux headers +- kvm: Use kvm_vm_check_extension() where necessary +- include/qom/object.h: New OBJECT_DEFINE_SIMPLE_TYPE{, _WITH_INTERFACES} macros +- target/arm: Add confidential guest support +- KVM: track whether guest state is encrypted +- target/arm/kvm: Return immediately on error in kvm_arch_init() +- target/arm/kvm: Split kvm_arch_get/put_registers +- target/arm/kvm: Create scratch VM as Realm if necessary +- hw/core/loader: Add ROM loader notifier +- target/arm/kvm-rme: Initialize realm +- target/arm/kvm-rme: Initialize vCPU +- target/arm/kvm-rme: Initialize Realm memory +- target/arm/kvm-rme: Add Realm Personalization Value parameter +- target/arm/kvm-rme: Add measurement algorithm property +- target/arm/cpu: Set number of breakpoints and watchpoints in KVM +- target/arm/cpu: Set number of PMU counters in KVM +- target/arm/cpu: Inform about reading confidential CPU registers +- target/arm/kvm-rme: Initialize Realm memory +- target/arm/kvm-rme: Add Realm Personalization Value parameter +- target/arm/kvm-rme: Add measurement algorithm property +- hw/arm/virt: Add support for Arm RME +- hw/arm/virt: Disable DTB randomness for confidential VMs +- hw/arm/virt: Reserve one bit of guest-physical address for RME +- hw/arm/virt: Move virt_flash_create() to machvirt_init() +- hw/arm/virt: Use RAM instead of flash for confidential guest firmware +- hw/core/loader: Add ROM loader notifier +- target/arm/kvm-rme: Initialize Realm memory +- target/arm/kvm-rme: Add measurement algorithm property +- target/arm/kvm-rme: Add Realm Personalization Value parameter +- target/arm/kvm-rme: Initialize Realm memory +- hw/arm/boot: Mark all guest memory as RIPAS_RAM. +- target/arm/kvm-rme: Add DMA remapping for the shared memory region +- hw/arm/virt: Move virt_flash_create() to machvirt_init() +- hw/arm/virt: Use RAM instead of flash for confidential guest firmware +- hw/core/loader: Add fields to RomLoaderNotify +- docs/interop/firmware.json: Add arm-rme firmware feature +- hw/arm/boot: Load DTB as is for confidential VMs +- hw/arm/boot: Skip bootloader for confidential guests +- hw/tpm: Add TPM event log +- hw/core/loader: Add fields to RomLoaderNotify +- hw/arm/virt: Use RAM instead of flash for confidential guest firmware +- hw/arm/virt: Reserve one bit of guest-physical address for RME +- hw/arm/virt: Disable DTB randomness for confidential VMs +- hw/arm/virt: Add support for Arm RME +- target/arm/cpu: Inform about reading confidential CPU registers +- target/arm/cpu: Set number of PMU counters in KVM +- target/arm/cpu: Set number of breakpoints and watchpoints in KVM +- target/arm/kvm-rme: Add measurement algorithm property +- target/arm/kvm-rme: Add Realm Personalization Value parameter +- target/arm/kvm-rme: Initialize Realm memory +- hw/core/loader: Add ROM loader notifier +- target/arm/kvm: Create scratch VM as Realm if necessary +- target/arm/kvm-rme: Initialize vCPU +- target/arm/kvm: Split kvm_arch_get/put_registers +- target/arm/kvm-rme: Initialize realm +- KVM: track whether guest state is encrypted +- target/arm/kvm: Return immediately on error in kvm_arch_init() +- target/arm: Add confidential guest support +- include/qom/object.h: New OBJECT_DEFINE_SIMPLE_TYPE{, _WITH_INTERFACES} macros +- kvm: Use kvm_vm_check_extension() where necessary +- linux-headers: Add KVM Arm RME definitions to Linux headers +- docs/interop/firmware.json: Add arm-rme firmware feature +- hw/arm/boot: Load DTB as is for confidential VMs +- hw/arm/boot: Skip bootloader for confidential guests +- hw/tpm: Add TPM event log +- hw/core/loader: Add fields to RomLoaderNotify +- hw/arm/virt: Use RAM instead of flash for confidential guest firmware +- hw/arm/virt: Move virt_flash_create() to machvirt_init() +- target/arm/kvm-rme: Add DMA remapping for the shared memory region +- hw/arm/boot: Mark all guest memory as RIPAS_RAM. +- hw/arm/virt: Reserve one bit of guest-physical address for RME +- hw/arm/virt: Disable DTB randomness for confidential VMs +- hw/arm/virt: Add support for Arm RME +- target/arm/cpu: Inform about reading confidential CPU registers +- target/arm/cpu: Set number of PMU counters in KVM +- target/arm/cpu: Set number of breakpoints and watchpoints in KVM +- target/arm/kvm-rme: Add measurement algorithm property +- target/arm/kvm-rme: Add Realm Personalization Value parameter +- target/arm/kvm-rme: Initialize Realm memory +- hw/core/loader: Add ROM loader notifier +- target/arm/kvm: Create scratch VM as Realm if necessary +- target/arm/kvm-rme: Initialize vCPU +- target/arm/kvm: Split kvm_arch_get/put_registers +- target/arm/kvm-rme: Initialize realm +- KVM: track whether guest state is encrypted +- target/arm/kvm: Return immediately on error in kvm_arch_init() +- target/arm: Add confidential guest support +- include/qom/object.h: New OBJECT_DEFINE_SIMPLE_TYPE{, _WITH_INTERFACES} macros +- kvm: Use kvm_vm_check_extension() where necessary +- linux-headers: Add KVM Arm RME definitions to Linux headers +- Bugfix: Fix compile error in aarch32. + * Fri Jul 25 2025 Pengrui Zhang - 11:8.2.0-38 - hw/audio/cs4231a: fix assertion error in isa_bus_get_irq - block/blkio: Make s->mem_region_alignment be 64 bits diff --git a/ram-block-attribute-Add-priority-listener-support-fo.patch b/ram-block-attribute-Add-priority-listener-support-fo.patch new file mode 100644 index 00000000..908c904b --- /dev/null +++ b/ram-block-attribute-Add-priority-listener-support-fo.patch @@ -0,0 +1,99 @@ +From 71e7d77e5724b77fdba7bab48ef44e92b8e0c1ee Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:32 +0800 +Subject: [PATCH] ram-block-attribute: Add priority listener support for + PrivateSharedListener + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/ed4157b155b571b62c4d88ca297909dbcb3922ed + +In-place page conversion requires operations to follow a specific +sequence: unmap-before-conversion-to-private and +map-after-conversion-to-shared. Currently, both attribute changes and +VFIO DMA map/unmap operations are handled by PrivateSharedListeners, +they need to be invoked in a specific order. + +For private to shared conversion: +- Change attribute to shared. +- VFIO populates the shared mappings into the IOMMU. +- Restore attribute if the operation fails. + +For shared to private conversion: +- VFIO discards shared mapping from the IOMMU. +- Change attribute to private. + +To faciliate this sequence, priority support is added to +PrivateSharedListener so that listeners are stored in a determined +order based on priority. A tail queue is used to store listeners, +allowing traversal in either direction. + +Signed-off-by: Chenyi Qiang +Conflicts: + include/exec/ramblock.h + system/ram-block-attribute.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/vfio/common.c | 3 ++- + include/exec/memory.h | 19 +++++++++++++++++-- + 2 files changed, 19 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index 182874eccb..c0bc61fdee 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -530,7 +530,8 @@ static void vfio_register_private_shared_listener(VFIOContainerBase *bcontainer, + + psl = &vpsl->listener; + private_shared_listener_init(psl, vfio_private_shared_notify_to_shared, +- vfio_private_shared_notify_to_private); ++ vfio_private_shared_notify_to_private, ++ PRIVATE_SHARED_LISTENER_PRIORITY_COMMON); + generic_state_manager_register_listener(gsm, &psl->scl, section); + QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); + } +diff --git a/include/exec/memory.h b/include/exec/memory.h +index b93ffb533e..51fe10d4a0 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -827,11 +827,24 @@ struct RamDiscardManagerClass { + GenericStateManagerClass parent_class; + }; + ++#define PRIVATE_SHARED_LISTENER_PRIORITY_MIN 0 ++#define PRIVATE_SHARED_LISTENER_PRIORITY_COMMON 10 ++ + typedef struct PrivateSharedListener PrivateSharedListener; + struct PrivateSharedListener { + struct StateChangeListener scl; + +- QLIST_ENTRY(PrivateSharedListener) next; ++ /* ++ * @priority: ++ * ++ * Govern the order in which ram discard listeners are invoked. Lower priorities ++ * are invoked earlier. ++ * The listener priority can help to undo the effects of previous listeners in ++ * a reverse order in case of a failure callback. ++ */ ++ int priority; ++ ++ QTAILQ_ENTRY(PrivateSharedListener) next; + }; + + struct PrivateSharedManagerClass { +@@ -841,9 +854,11 @@ struct PrivateSharedManagerClass { + + static inline void private_shared_listener_init(PrivateSharedListener *psl, + NotifyStateSet populate_fn, +- NotifyStateClear discard_fn) ++ NotifyStateClear discard_fn, ++ int priority) + { + state_change_listener_init(&psl->scl, populate_fn, discard_fn); ++ psl->priority = priority; + } + + bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, +-- +2.33.0 + diff --git a/target-arm-Add-confidential-guest-support.patch b/target-arm-Add-confidential-guest-support.patch new file mode 100644 index 00000000..6a3a9e86 --- /dev/null +++ b/target-arm-Add-confidential-guest-support.patch @@ -0,0 +1,124 @@ +From 754c30c1d126357d60ea29a2c17428a0abdcca49 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 16 Jun 2022 18:24:55 +0100 +Subject: [PATCH] target/arm: Add confidential guest support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/6353278a78f3942ff1b576aab77d79d926e8f9f0 + +Add a new RmeGuest object, inheriting from ConfidentialGuestSupport, to +support the Arm Realm Management Extension (RME). It is instantiated by +passing on the command-line: + + -M virt,confidential-guest-support= + -object rme-guest,id=[,options...] + +This is only the skeleton. Support will be added in following patches. + +Cc: Eric Blake +Cc: Markus Armbruster +Cc: Daniel P. Berrangé +Cc: Eduardo Habkost +Acked-by: Markus Armbruster +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/meson.build +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + docs/system/confidential-guest-support.rst | 1 + + qapi/qom.json | 1 + + target/arm/kvm-rme.c | 40 ++++++++++++++++++++++ + target/arm/meson.build | 2 +- + 4 files changed, 43 insertions(+), 1 deletion(-) + create mode 100644 target/arm/kvm-rme.c + +diff --git a/docs/system/confidential-guest-support.rst b/docs/system/confidential-guest-support.rst +index 0c490dbda2..acf46d8856 100644 +--- a/docs/system/confidential-guest-support.rst ++++ b/docs/system/confidential-guest-support.rst +@@ -40,5 +40,6 @@ Currently supported confidential guest mechanisms are: + * AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`) + * POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`) + * s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`) ++* Arm Realm Management Extension (RME) + + Other mechanisms may be supported in future. +diff --git a/qapi/qom.json b/qapi/qom.json +index a5336e6b11..e405c51da3 100644 +--- a/qapi/qom.json ++++ b/qapi/qom.json +@@ -999,6 +999,7 @@ + { 'name': 'pr-manager-helper', + 'if': 'CONFIG_LINUX' }, + 'qtest', ++ 'rme-guest', + 'rng-builtin', + 'rng-egd', + { 'name': 'rng-random', +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +new file mode 100644 +index 0000000000..1de65f2b1d +--- /dev/null ++++ b/target/arm/kvm-rme.c +@@ -0,0 +1,40 @@ ++/* ++ * QEMU Arm RME support ++ * ++ * Copyright Linaro 2024 ++ */ ++ ++#include "qemu/osdep.h" ++ ++#include "hw/boards.h" ++#include "hw/core/cpu.h" ++#include "kvm_arm.h" ++#include "migration/blocker.h" ++#include "qapi/error.h" ++#include "qom/object_interfaces.h" ++#include "exec/confidential-guest-support.h" ++#include "sysemu/kvm.h" ++#include "sysemu/runstate.h" ++ ++#define TYPE_RME_GUEST "rme-guest" ++OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST) ++ ++struct RmeGuest { ++ ConfidentialGuestSupport parent_obj; ++}; ++ ++OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, ++ CONFIDENTIAL_GUEST_SUPPORT, ++ { TYPE_USER_CREATABLE }, { }) ++ ++static void rme_guest_class_init(ObjectClass *oc, void *data) ++{ ++} ++ ++static void rme_guest_init(Object *obj) ++{ ++} ++ ++static void rme_guest_finalize(Object *obj) ++{ ++} +diff --git a/target/arm/meson.build b/target/arm/meson.build +index 389ee54658..7973b35cca 100644 +--- a/target/arm/meson.build ++++ b/target/arm/meson.build +@@ -8,7 +8,7 @@ arm_ss.add(files( + )) + arm_ss.add(zlib) + +-arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c', 'kvm64.c'), if_false: files('kvm-stub.c')) ++arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c', 'kvm64.c', 'kvm-rme.c'), if_false: files('kvm-stub.c')) + arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) + arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c', 'kvm-tmm.c'), if_false: files('kvm-stub.c')) + +-- +2.33.0 + diff --git a/target-arm-cpu-Inform-about-reading-confidential-CPU.patch b/target-arm-cpu-Inform-about-reading-confidential-CPU.patch new file mode 100644 index 00000000..772775ed --- /dev/null +++ b/target-arm-cpu-Inform-about-reading-confidential-CPU.patch @@ -0,0 +1,37 @@ +From 21bfc55d5d2580bcf61e174c95cd3fe27c608b27 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Tue, 7 Feb 2023 13:05:40 +0000 +Subject: [PATCH] target/arm/cpu: Inform about reading confidential CPU + registers + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/f7dbc9b0e0677feabac408bed8fb9fcbd9b946c3 + +The host cannot access registers of a Realm. Instead of showing all +registers as zero in "info registers", display a message about this +restriction. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + target/arm/cpu.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 09d391bd34..3de2e1a3c3 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1082,6 +1082,11 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) + const char *ns_status; + bool sve; + ++ if (cpu->kvm_rme) { ++ qemu_fprintf(f, "the CPU registers are confidential to the realm\n"); ++ return; ++ } ++ + qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); + for (i = 0; i < 32; i++) { + if (i == 31) { +-- +2.33.0 + diff --git a/target-arm-cpu-Set-number-of-PMU-counters-in-KVM.patch b/target-arm-cpu-Set-number-of-PMU-counters-in-KVM.patch new file mode 100644 index 00000000..8db2bbaf --- /dev/null +++ b/target-arm-cpu-Set-number-of-PMU-counters-in-KVM.patch @@ -0,0 +1,193 @@ +From 4febb6917e0e09279c86ce1679566bb9bc63b0df Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 7 Dec 2023 17:32:13 +0000 +Subject: [PATCH] target/arm/cpu: Set number of PMU counters in KVM + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/22f6eef79582fc88a779bc5baa502bcd6e592f8f + +Add a "num-pmu-counters" CPU parameter to configure the number of +counters that KVM presents to the guest. This is needed for Realm VMs, +whose parameters include the number of PMU counters and influence the +Realm Initial Measurement. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/arm-qmp-cmds.c + target/arm/kvm.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/arm-qmp-cmds.c | 2 +- + target/arm/cpu.h | 3 +++ + target/arm/cpu64.c | 41 +++++++++++++++++++++++++++++++++++++++ + target/arm/kvm.c | 32 ++++++++++++++++++++++++++++++ + target/arm/kvm64.c | 2 +- + target/arm/kvm_arm.h | 1 + + 6 files changed, 79 insertions(+), 2 deletions(-) + +diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c +index 98b3498428..d201d319bd 100644 +--- a/target/arm/arm-qmp-cmds.c ++++ b/target/arm/arm-qmp-cmds.c +@@ -96,7 +96,7 @@ static const char *cpu_model_advertised_features[] = { + "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048", + "kvm-no-adjvtime", "kvm-steal-time", + "pauth", "pauth-impdef", "pauth-qarma3", +- "num-breakpoints", "num-watchpoints", ++ "num-breakpoints", "num-watchpoints", "num-pmu-counters", + NULL + }; + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 223d8abd8a..cb546a93e2 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1128,6 +1128,7 @@ struct ArchCPU { + /* Allows to override the default configuration */ + uint8_t num_bps; + uint8_t num_wps; ++ int8_t num_pmu_ctrs; + }; + + typedef struct ARMCPUInfo { +@@ -2477,6 +2478,8 @@ FIELD(MFAR, FPA, 12, 40) + FIELD(MFAR, NSE, 62, 1) + FIELD(MFAR, NS, 63, 1) + ++FIELD(PMCR, N, 11, 5) ++ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK); + + /* If adding a feature bit which corresponds to a Linux ELF +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index c0edffb679..4cf8446b6e 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -643,12 +643,53 @@ static void arm_cpu_set_num_bps(Object *obj, Visitor *v, const char *name, + cpu->num_bps = val; + } + ++static void arm_cpu_get_num_pmu_ctrs(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ ++ if (cpu->num_pmu_ctrs == -1) { ++ val = FIELD_EX64(cpu->isar.reset_pmcr_el0, PMCR, N); ++ } else { ++ val = cpu->num_pmu_ctrs; ++ } ++ ++ visit_type_uint8(v, name, &val, errp); ++} ++ ++static void arm_cpu_set_num_pmu_ctrs(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ uint8_t max_ctrs = FIELD_EX64(cpu->isar.reset_pmcr_el0, PMCR, N); ++ ++ if (!visit_type_uint8(v, name, &val, errp)) { ++ return; ++ } ++ ++ if (val > max_ctrs) { ++ error_setg(errp, "invalid number of PMU counters"); ++ return; ++ } ++ ++ cpu->num_pmu_ctrs = val; ++} ++ + static void aarch64_add_kvm_writable_properties(Object *obj) + { ++ ARMCPU *cpu = ARM_CPU(obj); ++ + object_property_add(obj, "num-breakpoints", "uint8", arm_cpu_get_num_bps, + arm_cpu_set_num_bps, NULL, NULL); + object_property_add(obj, "num-watchpoints", "uint8", arm_cpu_get_num_wps, + arm_cpu_set_num_wps, NULL, NULL); ++ ++ cpu->num_pmu_ctrs = -1; ++ object_property_add(obj, "num-pmu-counters", "uint8", ++ arm_cpu_get_num_pmu_ctrs, arm_cpu_set_num_pmu_ctrs, ++ NULL, NULL); + } + #endif /* CONFIG_KVM */ + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index bf17da37e5..f45783a9da 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -724,9 +724,41 @@ static void kvm_arm_configure_aa64dfr0(ARMCPU *cpu) + } + } + ++static void kvm_arm_configure_pmcr(ARMCPU *cpu) ++{ ++ int ret; ++ uint64_t val, newval; ++ CPUState *cs = CPU(cpu); ++ ++ if (cpu->num_pmu_ctrs == -1) { ++ return; ++ } ++ ++ newval = FIELD_DP64(cpu->isar.reset_pmcr_el0, PMCR, N, cpu->num_pmu_ctrs); ++ ret = kvm_set_one_reg(cs, KVM_REG_ARM_PMCR_EL0, &newval); ++ if (ret) { ++ error_report("Failed to set KVM_REG_ARM_PMCR_EL0"); ++ return; ++ } ++ ++ /* ++ * Check if the write succeeded, since older versions of KVM ignore it. ++ */ ++ ret = kvm_get_one_reg(cs, KVM_REG_ARM_PMCR_EL0, &val); ++ if (ret) { ++ error_report("Failed to get KVM_REG_ARM_PMCR_EL0"); ++ return; ++ } ++ ++ if (val != newval) { ++ error_report("Failed to update KVM_REG_ARM_PMCR_EL0"); ++ } ++} ++ + static void kvm_arm_configure_vcpu_regs(ARMCPU *cpu) + { + kvm_arm_configure_aa64dfr0(cpu); ++ kvm_arm_configure_pmcr(cpu); + } + + void kvm_arm_reset_vcpu(ARMCPU *cpu) +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index e84bc9f94d..6a8aad0f06 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -438,7 +438,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + if (pmu_supported) { + /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */ + err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0, +- ARM64_SYS_REG(3, 3, 9, 12, 0)); ++ KVM_REG_ARM_PMCR_EL0); + } + + if (sve_supported) { +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 63b5d9affd..4a9707a435 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -19,6 +19,7 @@ + #define KVM_ARM_VGIC_V3 (1 << 1) + + #define KVM_REG_ARM_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0) ++#define KVM_REG_ARM_PMCR_EL0 ARM64_SYS_REG(3, 3, 9, 12, 0) + + /** + * kvm_arm_init_debug() - initialize guest debug capabilities +-- +2.33.0 + diff --git a/target-arm-cpu-Set-number-of-breakpoints-and-watchpo.patch b/target-arm-cpu-Set-number-of-breakpoints-and-watchpo.patch new file mode 100644 index 00000000..60184a27 --- /dev/null +++ b/target-arm-cpu-Set-number-of-breakpoints-and-watchpo.patch @@ -0,0 +1,253 @@ +From 3b881e82b73be727e783e1762084025233fba0cc Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 4 Dec 2023 18:48:19 +0000 +Subject: [PATCH] target/arm/cpu: Set number of breakpoints and watchpoints in + KVM + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/99082dee9c26b2b0f0f4d39bc9f6f99e73701e2f + +Add "num-breakpoints" and "num-watchpoints" CPU parameters to configure +the debug features that KVM presents to the guest. The KVM vCPU +configuration is modified by calling SET_ONE_REG on the ID register. + +This is needed for Realm VMs, whose parameters include breakpoints and +watchpoints, and influence the Realm Initial Measurement. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/arm-qmp-cmds.c + target/arm/kvm.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/arm-qmp-cmds.c | 1 + + target/arm/cpu.h | 4 ++ + target/arm/cpu64.c | 77 +++++++++++++++++++++++++++++++++++++++ + target/arm/kvm.c | 54 +++++++++++++++++++++++++++ + target/arm/kvm64.c | 2 +- + target/arm/kvm_arm.h | 2 + + 6 files changed, 139 insertions(+), 1 deletion(-) + +diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c +index b53d5efe13..98b3498428 100644 +--- a/target/arm/arm-qmp-cmds.c ++++ b/target/arm/arm-qmp-cmds.c +@@ -96,6 +96,7 @@ static const char *cpu_model_advertised_features[] = { + "sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048", + "kvm-no-adjvtime", "kvm-steal-time", + "pauth", "pauth-impdef", "pauth-qarma3", ++ "num-breakpoints", "num-watchpoints", + NULL + }; + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 12305effd4..223d8abd8a 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1124,6 +1124,10 @@ struct ArchCPU { + + /* Generic timer counter frequency, in Hz */ + uint64_t gt_cntfrq_hz; ++ ++ /* Allows to override the default configuration */ ++ uint8_t num_bps; ++ uint8_t num_wps; + }; + + typedef struct ARMCPUInfo { +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 6eca55ac29..c0edffb679 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -576,6 +576,82 @@ void aarch64_add_pauth_properties(Object *obj) + } + } + ++#if defined(CONFIG_KVM) ++static void arm_cpu_get_num_wps(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ ++ val = cpu->num_wps; ++ if (val == 0) { ++ val = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ } ++ ++ visit_type_uint8(v, name, &val, errp); ++} ++ ++static void arm_cpu_set_num_wps(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ uint8_t max_wps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ ++ if (!visit_type_uint8(v, name, &val, errp)) { ++ return; ++ } ++ ++ if (val < 2 || val > max_wps) { ++ error_setg(errp, "invalid number of watchpoints"); ++ return; ++ } ++ ++ cpu->num_wps = val; ++} ++ ++static void arm_cpu_get_num_bps(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ ++ val = cpu->num_bps; ++ if (val == 0) { ++ val = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ } ++ ++ visit_type_uint8(v, name, &val, errp); ++} ++ ++static void arm_cpu_set_num_bps(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ uint8_t val; ++ ARMCPU *cpu = ARM_CPU(obj); ++ uint8_t max_bps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ ++ if (!visit_type_uint8(v, name, &val, errp)) { ++ return; ++ } ++ ++ if (val < 2 || val > max_bps) { ++ error_setg(errp, "invalid number of breakpoints"); ++ return; ++ } ++ ++ cpu->num_bps = val; ++} ++ ++static void aarch64_add_kvm_writable_properties(Object *obj) ++{ ++ object_property_add(obj, "num-breakpoints", "uint8", arm_cpu_get_num_bps, ++ arm_cpu_set_num_bps, NULL, NULL); ++ object_property_add(obj, "num-watchpoints", "uint8", arm_cpu_get_num_wps, ++ arm_cpu_set_num_wps, NULL, NULL); ++} ++#endif /* CONFIG_KVM */ ++ + void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) + { + uint64_t t; +@@ -789,6 +865,7 @@ static void aarch64_host_initfn(Object *obj) + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); ++ aarch64_add_kvm_writable_properties(obj); + } + #elif defined(CONFIG_HVF) + ARMCPU *cpu = ARM_CPU(obj); +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index cec95483f3..bf17da37e5 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -681,6 +681,54 @@ void kvm_arm_cpu_post_load(ARMCPU *cpu) + } + } + ++static void kvm_arm_configure_aa64dfr0(ARMCPU *cpu) ++{ ++ int ret; ++ uint64_t val, newval; ++ CPUState *cs = CPU(cpu); ++ ++ if (!cpu->num_bps && !cpu->num_wps) { ++ return; ++ } ++ ++ newval = cpu->isar.id_aa64dfr0; ++ if (cpu->num_bps) { ++ uint64_t ctx_cmps = FIELD_EX64(newval, ID_AA64DFR0, CTX_CMPS); ++ ++ /* CTX_CMPs is never greater than BRPs */ ++ ctx_cmps = MIN(ctx_cmps, cpu->num_bps - 1); ++ newval = FIELD_DP64(newval, ID_AA64DFR0, BRPS, cpu->num_bps - 1); ++ newval = FIELD_DP64(newval, ID_AA64DFR0, CTX_CMPS, ctx_cmps); ++ } ++ if (cpu->num_wps) { ++ newval = FIELD_DP64(newval, ID_AA64DFR0, WRPS, cpu->num_wps - 1); ++ } ++ ret = kvm_set_one_reg(cs, KVM_REG_ARM_ID_AA64DFR0_EL1, &newval); ++ if (ret) { ++ error_report("Failed to set KVM_REG_ARM_ID_AA64DFR0_EL1"); ++ return; ++ } ++ ++ /* ++ * Check if the write succeeded. KVM does offer the writable mask for this ++ * register, but this way we also check if the value we wrote was sane. ++ */ ++ ret = kvm_get_one_reg(cs, KVM_REG_ARM_ID_AA64DFR0_EL1, &val); ++ if (ret) { ++ error_report("Failed to get KVM_REG_ARM_ID_AA64DFR0_EL1"); ++ return; ++ } ++ ++ if (val != newval) { ++ error_report("Failed to update KVM_REG_ARM_ID_AA64DFR0_EL1"); ++ } ++} ++ ++static void kvm_arm_configure_vcpu_regs(ARMCPU *cpu) ++{ ++ kvm_arm_configure_aa64dfr0(cpu); ++} ++ + void kvm_arm_reset_vcpu(ARMCPU *cpu) + { + int ret; +@@ -694,6 +742,12 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu) + fprintf(stderr, "kvm_arm_vcpu_init failed: %s\n", strerror(-ret)); + abort(); + } ++ ++ /* ++ * Before loading the KVM values into CPUState, update the KVM configuration ++ */ ++ kvm_arm_configure_vcpu_regs(cpu); ++ + if (!write_kvmstate_to_list(cpu)) { + fprintf(stderr, "write_kvmstate_to_list failed\n"); + abort(); +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index d314927027..e84bc9f94d 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -338,7 +338,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, + ARM64_SYS_REG(3, 0, 0, 4, 5)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, +- ARM64_SYS_REG(3, 0, 0, 5, 0)); ++ KVM_REG_ARM_ID_AA64DFR0_EL1); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, + ARM64_SYS_REG(3, 0, 0, 5, 1)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 78ff8b7375..63b5d9affd 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -18,6 +18,8 @@ + #define KVM_ARM_VGIC_V2 (1 << 0) + #define KVM_ARM_VGIC_V3 (1 << 1) + ++#define KVM_REG_ARM_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0) ++ + /** + * kvm_arm_init_debug() - initialize guest debug capabilities + * @s: KVMState +-- +2.33.0 + diff --git a/target-arm-kvm-Create-scratch-VM-as-Realm-if-necessa.patch b/target-arm-kvm-Create-scratch-VM-as-Realm-if-necessa.patch new file mode 100644 index 00000000..077ffffe --- /dev/null +++ b/target-arm-kvm-Create-scratch-VM-as-Realm-if-necessa.patch @@ -0,0 +1,47 @@ +From 64f88add04d798c28bfa5e61a134ccde67fcada9 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 4 Dec 2023 18:48:36 +0000 +Subject: [PATCH] target/arm/kvm: Create scratch VM as Realm if necessary + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/bf7f456dfa60a022ac690004ddb08695b23ccde4 + +Some ID registers have a different value for a Realm VM, for example +ID_AA64DFR0_EL1 contains the number of breakpoints/watchpoints +implemented by RMM instead of the hardware. + +Even though RMM is in charge of setting up most Realm registers, KVM +still provides GET_ONE_REG interface on a Realm VM to probe the VM's +capabilities. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + target/arm/kvm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 83462f3f62..cec95483f3 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -73,6 +73,7 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, + { + int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1; + int max_vm_pa_size; ++ int vm_type; + + kvmfd = qemu_open_old("/dev/kvm", O_RDWR); + if (kvmfd < 0) { +@@ -82,8 +83,9 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, + if (max_vm_pa_size < 0) { + max_vm_pa_size = 0; + } ++ vm_type = kvm_arm_rme_vm_type(MACHINE(qdev_get_machine())); + do { +- vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size); ++ vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size | vm_type); + } while (vmfd == -1 && errno == EINTR); + if (vmfd < 0) { + goto err; +-- +2.33.0 + diff --git a/target-arm-kvm-Return-immediately-on-error-in-kvm_ar.patch b/target-arm-kvm-Return-immediately-on-error-in-kvm_ar.patch new file mode 100644 index 00000000..4c97a2f7 --- /dev/null +++ b/target-arm-kvm-Return-immediately-on-error-in-kvm_ar.patch @@ -0,0 +1,77 @@ +From 06d0249f7fc42d05b8461e6b2675f8d1fddb0707 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 21 Feb 2024 15:50:42 +0000 +Subject: [PATCH] target/arm/kvm: Return immediately on error in + kvm_arch_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/1385e5d0517c42a8a3d18c4eb36db48e86370aa3 + +Returning an error to kvm_init() is fatal anyway, no need to continue +the initialization. + +Leave the `ret` variable in the function scope because it will be reused +when adding RME support. + +Signed-off-by: Jean-Philippe Brucker +Reviewed-by: Philippe Mathieu-Daudé +Conflicts: + target/arm/kvm.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/kvm.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index ab31515a2a..e32a064f94 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -276,7 +276,7 @@ static void kvm_update_ipiv_cap(KVMState *s) + int kvm_arch_init(MachineState *ms, KVMState *s) + { + MachineClass *mc = MACHINE_GET_CLASS(ms); +- int ret = 0; ++ int ret; + + /* For ARM interrupt delivery is always asynchronous, + * whether we are using an in-kernel VGIC or not. +@@ -295,7 +295,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) { + error_report("Using more than 256 vcpus requires a host kernel " + "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2"); +- ret = -EINVAL; ++ return -EINVAL; + } + + if (kvm_check_extension(s, KVM_CAP_ARM_NISV_TO_USER)) { +@@ -317,13 +317,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + warn_report("Eager Page Split support not available"); + } else if (!(s->kvm_eager_split_size & sizes)) { + error_report("Eager Page Split requested chunk size not valid"); +- ret = -EINVAL; ++ return -EINVAL; + } else { + ret = kvm_vm_enable_cap(s, KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE, 0, + s->kvm_eager_split_size); + if (ret < 0) { + error_report("Enabling of Eager Page Split failed: %s", + strerror(-ret)); ++ return ret; + } + } + } +@@ -348,7 +349,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + kvm_arm_init_debug(s); + kvm_update_ipiv_cap(s); + +- return ret; ++ return 0; + } + + unsigned long kvm_arch_vcpu_id(CPUState *cpu) +-- +2.33.0 + diff --git a/target-arm-kvm-Split-kvm_arch_get-put_registers.patch b/target-arm-kvm-Split-kvm_arch_get-put_registers.patch new file mode 100644 index 00000000..13f20f72 --- /dev/null +++ b/target-arm-kvm-Split-kvm_arch_get-put_registers.patch @@ -0,0 +1,85 @@ +From 4b69d18a5600e610d08584fafb87030e272ebb2b Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Tue, 21 Jun 2022 11:52:14 +0100 +Subject: [PATCH] target/arm/kvm: Split kvm_arch_get/put_registers + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/a66c2761d7d6ba0f1f0db383cbad158e4cced72f + +The confidential guest support in KVM limits the number of registers +that we can read and write. Split the get/put_registers function to +prepare for it. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/kvm.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/kvm64.c | 30 ++++++++++++++++++++++++++++-- + 1 file changed, 28 insertions(+), 2 deletions(-) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 651f603dd8..20a357061c 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -838,7 +838,7 @@ static int kvm_arch_put_sve(CPUState *cs) + return 0; + } + +-int kvm_arch_put_registers(CPUState *cs, int level) ++static int kvm_arm_put_core_regs(CPUState *cs, int level) + { + uint64_t val; + uint32_t fpr; +@@ -941,6 +941,19 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + ++ return 0; ++} ++ ++int kvm_arch_put_registers(CPUState *cs, int level) ++{ ++ int ret; ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ ret = kvm_arm_put_core_regs(cs, level); ++ if (ret) { ++ return ret; ++ } ++ + write_cpustate_to_list(cpu, true); + + if (!write_list_to_kvmstate(cpu, level)) { +@@ -1024,7 +1037,7 @@ static int kvm_arch_get_sve(CPUState *cs) + return 0; + } + +-int kvm_arch_get_registers(CPUState *cs) ++static int kvm_arm_get_core_regs(CPUState *cs) + { + uint64_t val; + unsigned int el; +@@ -1127,6 +1140,19 @@ int kvm_arch_get_registers(CPUState *cs) + } + vfp_set_fpcr(env, fpr); + ++ return 0; ++} ++ ++int kvm_arch_get_registers(CPUState *cs) ++{ ++ int ret; ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ ret = kvm_arm_get_core_regs(cs); ++ if (ret) { ++ return ret; ++ } ++ + ret = kvm_get_vcpu_events(cpu); + if (ret) { + return ret; +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Add-DMA-remapping-for-the-shared-.patch b/target-arm-kvm-rme-Add-DMA-remapping-for-the-shared-.patch new file mode 100644 index 00000000..9c11a569 --- /dev/null +++ b/target-arm-kvm-rme-Add-DMA-remapping-for-the-shared-.patch @@ -0,0 +1,363 @@ +From 3b1146d0a9d5e7a31e84b1c26b7331c84d0b5b05 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 8 Jan 2025 17:34:11 +0000 +Subject: [PATCH] target/arm/kvm-rme: Add DMA remapping for the shared memory + region + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/1efc2744bf6ac5fc074baedd42d3d40ed73c6405 + +In Arm CCA, the guest-physical address space is split in half. The top +half represents memory shared between guest and host, and the bottom +half is private to the guest. From QEMU's point of view, the two halves +are merged into a single region, and pages within this region are either +shared or private. + +Addresses used by device DMA can potentially target both halves. +Physical devices assigned to the VM access the top half, until they are +authenticated using features like PCIe CMA-SPDM at which point they can +also access memory private to the guest. + +Virtual devices implemented by the host are only allowed to access the +top half. For emulated MMIO, KVM strips the GPA before returning to +QEMU, so the GPA already belongs to QEMU's merged view of guest memory. +However DMA addresses cannot be stripped this way and need special +handling by the VMM: + +* When emulating DMA the VMM needs to translate the addresses into its + merged view. Add an IOMMU memory region on the top half, that + retargets DMA accesses to the merged sysmem. + +* when creating IOMMU mappings for (unauthenticated) VFIO devices, the VMM + needs to map the top half of guest-physical addresses to the shared pages. + Install RAM discard listeners that issue IOMMU map and unmap requests + to IOMMU listeners such as VFIO. + +The resulting mtree looks like this: + + address-space: vfio-pci + 0000000000000000-ffffffffffffffff (prio 0, i/o): bus master container + 0000000000000000-000001ffffffffff (prio 0, i/o): alias bus master @realm-dma-region 0000000000000000-000001ffffffffff + + memory-region: realm-dma-region + 0000000000000000-000001ffffffffff (prio 0, i/o): realm-dma-region + +There are at least two problems with this approach: given that we use +the PCI bus master address space, a vIOMMU cannot install its own +address space at the moment. And since sysbus devices can't have an +IOMMU at the moment, DMA from non-PCI devices isn't supported. + +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + hw/arm/virt.c | 2 + + target/arm/kvm-rme.c | 222 +++++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 15 +++ + 3 files changed, 239 insertions(+) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 51f7c940f4..95f6acf655 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2880,6 +2880,8 @@ static void machvirt_init(MachineState *machine) + vms->fw_cfg, OBJECT(vms)); + } + ++ kvm_arm_rme_init_gpa_space(vms->highest_gpa, vms->bus); ++ + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 5e785fa3b6..299af009d9 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -9,6 +9,7 @@ + #include "hw/boards.h" + #include "hw/core/cpu.h" + #include "hw/loader.h" ++#include "hw/pci/pci.h" + #include "kvm_arm.h" + #include "migration/blocker.h" + #include "qapi/error.h" +@@ -24,6 +25,35 @@ OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST) + + #define RME_PAGE_SIZE qemu_real_host_page_size() + ++/* ++ * Realms have a split guest-physical address space: the bottom half is private ++ * to the realm, and the top half is shared with the host. Within QEMU, we use a ++ * merged view of both halves. Most of RAM is private to the guest and not ++ * accessible to us, but the guest shares some pages with us. ++ * ++ * For DMA, devices generally target the shared half (top) of the guest address ++ * space. Only the devices trusted by the guest (using mechanisms like TDISP for ++ * device authentication) can access the bottom half. ++ * ++ * RealmDmaRegion performs remapping of top-half accesses to system memory. ++ */ ++struct RealmDmaRegion { ++ IOMMUMemoryRegion parent_obj; ++}; ++ ++#define TYPE_REALM_DMA_REGION "realm-dma-region" ++OBJECT_DECLARE_SIMPLE_TYPE(RealmDmaRegion, REALM_DMA_REGION) ++OBJECT_DEFINE_SIMPLE_TYPE(RealmDmaRegion, realm_dma_region, ++ REALM_DMA_REGION, IOMMU_MEMORY_REGION); ++ ++typedef struct RealmPrivateSharedListener { ++ MemoryRegion *mr; ++ hwaddr offset_within_region; ++ uint64_t granularity; ++ PrivateSharedListener listener; ++ QLIST_ENTRY(RealmPrivateSharedListener) rpsl_next; ++} RealmPrivateSharedListener; ++ + typedef struct { + hwaddr base; + hwaddr size; +@@ -39,6 +69,12 @@ struct RmeGuest { + RmeGuestMeasurementAlgorithm measurement_algo; + + RmeRamRegion init_ram; ++ uint8_t ipa_bits; ++ ++ RealmDmaRegion *dma_region; ++ QLIST_HEAD(, RealmPrivateSharedListener) ram_discard_list; ++ MemoryListener memory_listener; ++ AddressSpace dma_as; + }; + + OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, +@@ -305,6 +341,7 @@ static void rme_guest_init(Object *obj) + + static void rme_guest_finalize(Object *obj) + { ++ memory_listener_unregister(&rme_guest->memory_listener); + } + + static gint rme_compare_ram_regions(gconstpointer a, gconstpointer b) +@@ -404,3 +441,188 @@ int kvm_arm_rme_vm_type(MachineState *ms) + } + return 0; + } ++ ++static int rme_ram_discard_notify(StateChangeListener *scl, ++ MemoryRegionSection *section, ++ bool populate) ++{ ++ hwaddr gpa, next; ++ IOMMUTLBEvent event; ++ const hwaddr end = section->offset_within_address_space + ++ int128_get64(section->size); ++ const hwaddr address_mask = MAKE_64BIT_MASK(0, rme_guest->ipa_bits - 1); ++ PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); ++ RealmPrivateSharedListener *rpsl = container_of(psl, RealmPrivateSharedListener, ++ listener); ++ ++ assert(rme_guest->dma_region != NULL); ++ ++ event.type = populate ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP; ++ event.entry.target_as = &address_space_memory; ++ event.entry.perm = populate ? IOMMU_RW : IOMMU_NONE; ++ event.entry.addr_mask = rpsl->granularity - 1; ++ ++ assert(end <= address_mask); ++ ++ /* ++ * Create IOMMU mappings from the top half of the address space to the RAM ++ * region. ++ */ ++ for (gpa = section->offset_within_address_space; gpa < end; gpa = next) { ++ event.entry.iova = gpa + address_mask + 1; ++ event.entry.translated_addr = gpa; ++ memory_region_notify_iommu(IOMMU_MEMORY_REGION(rme_guest->dma_region), ++ 0, event); ++ ++ next = ROUND_UP(gpa + 1, rpsl->granularity); ++ next = MIN(next, end); ++ } ++ ++ return 0; ++} ++ ++static int rme_ram_discard_notify_populate(StateChangeListener *scl, ++ MemoryRegionSection *section) ++{ ++ return rme_ram_discard_notify(scl, section, /* populate */ true); ++} ++ ++static int rme_ram_discard_notify_discard(StateChangeListener *scl, ++ MemoryRegionSection *section) ++{ ++ return rme_ram_discard_notify(scl, section, /* populate */ false); ++} ++ ++/* Install a RAM discard listener */ ++static void rme_listener_region_add(MemoryListener *listener, ++ MemoryRegionSection *section) ++{ ++ RealmPrivateSharedListener *rpsl; ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); ++ ++ ++ if (!gsm) { ++ return; ++ } ++ ++ rpsl = g_new0(RealmPrivateSharedListener, 1); ++ rpsl->mr = section->mr; ++ rpsl->offset_within_region = section->offset_within_region; ++ rpsl->granularity = generic_state_manager_get_min_granularity(gsm, ++ section->mr); ++ QLIST_INSERT_HEAD(&rme_guest->ram_discard_list, rpsl, rpsl_next); ++ ++ private_shared_listener_init(&rpsl->listener, ++ rme_ram_discard_notify_populate, ++ rme_ram_discard_notify_discard, true); ++ generic_state_manager_register_listener(gsm, &rpsl->listener.scl, section); ++} ++ ++static void rme_listener_region_del(MemoryListener *listener, ++ MemoryRegionSection *section) ++{ ++ RealmPrivateSharedListener *rpsl; ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); ++ ++ if (!gsm) { ++ return; ++ } ++ ++ QLIST_FOREACH(rpsl, &rme_guest->ram_discard_list, rpsl_next) { ++ if (MEMORY_REGION(rpsl->mr) == section->mr && ++ rpsl->offset_within_region == section->offset_within_region) { ++ generic_state_manager_unregister_listener(gsm, &rpsl->listener.scl); ++ g_free(rpsl); ++ break; ++ } ++ } ++} ++ ++static AddressSpace *rme_dma_get_address_space(PCIBus *bus, void *opaque, ++ int devfn) ++{ ++ return &rme_guest->dma_as; ++} ++ ++static const PCIIOMMUOps rme_dma_ops = { ++ .get_address_space = rme_dma_get_address_space, ++}; ++ ++void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus) ++{ ++ RealmDmaRegion *dma_region; ++ const unsigned int ipa_bits = 64 - clz64(highest_gpa) + 1; ++ ++ if (!rme_guest) { ++ return; ++ } ++ ++ assert(ipa_bits < 64); ++ ++ /* ++ * Setup a DMA translation from the shared top half of the guest-physical ++ * address space to our merged view of RAM. ++ */ ++ dma_region = g_new0(RealmDmaRegion, 1); ++ ++ memory_region_init_iommu(dma_region, sizeof(*dma_region), ++ TYPE_REALM_DMA_REGION, OBJECT(rme_guest), ++ "realm-dma-region", 1ULL << ipa_bits); ++ address_space_init(&rme_guest->dma_as, MEMORY_REGION(dma_region), ++ TYPE_REALM_DMA_REGION); ++ rme_guest->dma_region = dma_region; ++ ++ pci_setup_iommu(pci_bus, &rme_dma_ops, NULL); ++ ++ /* ++ * Install notifiers to forward RAM discard changes to the IOMMU notifiers ++ * (ie. tell VFIO to map shared pages and unmap private ones). ++ */ ++ rme_guest->memory_listener = (MemoryListener) { ++ .name = "rme", ++ .region_add = rme_listener_region_add, ++ .region_del = rme_listener_region_del, ++ }; ++ memory_listener_register(&rme_guest->memory_listener, ++ &address_space_memory); ++ ++ rme_guest->ipa_bits = ipa_bits; ++} ++ ++static void realm_dma_region_init(Object *obj) ++{ ++} ++ ++static IOMMUTLBEntry realm_dma_region_translate(IOMMUMemoryRegion *mr, ++ hwaddr addr, ++ IOMMUAccessFlags flag, ++ int iommu_idx) ++{ ++ const hwaddr address_mask = MAKE_64BIT_MASK(0, rme_guest->ipa_bits - 1); ++ IOMMUTLBEntry entry = { ++ .target_as = &address_space_memory, ++ .iova = addr, ++ .translated_addr = addr & address_mask, ++ .addr_mask = address_mask, ++ .perm = IOMMU_RW, ++ }; ++ ++ return entry; ++} ++ ++static void realm_dma_region_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *n) ++{ ++ /* Nothing is shared at boot */ ++} ++ ++static void realm_dma_region_finalize(Object *obj) ++{ ++} ++ ++static void realm_dma_region_class_init(ObjectClass *oc, void *data) ++{ ++ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(oc); ++ ++ imrc->translate = realm_dma_region_translate; ++ imrc->replay = realm_dma_region_replay; ++} +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 4a9707a435..b4d54e816f 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -441,6 +441,16 @@ int kvm_arm_rme_vcpu_init(CPUState *cs); + */ + void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size); + ++/** ++ * kvm_arm_rme_setup_gpa ++ * @highest_gpa: highest address of the lower half of the guest address space ++ * @pci_bus: The main PCI bus, for which PCI queries DMA address spaces ++ * ++ * Setup the guest-physical address space for a Realm. Install a memory region ++ * and notifier to manage the shared upper half of the address space. ++ */ ++void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus); ++ + #else + + /* +@@ -471,6 +481,11 @@ static inline void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size) + { + } + ++static inline void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, ++ PCIBus *pci_bus) ++{ ++} ++ + /* + * These functions should never actually be called without KVM support. + */ +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Add-Realm-Personalization-Value-p.patch b/target-arm-kvm-rme-Add-Realm-Personalization-Value-p.patch new file mode 100644 index 00000000..1408e429 --- /dev/null +++ b/target-arm-kvm-rme-Add-Realm-Personalization-Value-p.patch @@ -0,0 +1,190 @@ +From 853f2c56d022c88aff929824ed5278c958a47a6d Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Tue, 7 Feb 2023 18:55:22 +0000 +Subject: [PATCH] target/arm/kvm-rme: Add Realm Personalization Value parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/c2659aa7e7fde76a3bc9914f348ee5c2d7b4d15d + +The Realm Personalization Value (RPV) is provided by the user to +distinguish Realms that have the same initial measurement. + +The user provides a base64 string encoding 64 bytes. They are stored +into the RPV in the same order. + +Cc: Eric Blake +Cc: Markus Armbruster +Cc: Daniel P. Berrangé +Cc: Eduardo Habkost +Acked-by: Markus Armbruster +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + qapi/qom.json | 15 ++++++++ + target/arm/kvm-rme.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 100 insertions(+) + +diff --git a/qapi/qom.json b/qapi/qom.json +index e405c51da3..0120369454 100644 +--- a/qapi/qom.json ++++ b/qapi/qom.json +@@ -952,6 +952,20 @@ + '*kae': 'uint32', + '*measurement-algo': 'TmmGuestMeasurementAlgo' } } + ++## ++# @RmeGuestProperties: ++# ++# Properties for rme-guest objects. ++# ++# @personalization-value: a base64 string encoding a 64-byte (512-bit) value. ++# This optional parameter allows to uniquely identify the VM instance ++# during attestation. (default: all-zero) ++# ++# Since: 10.0 ++## ++{ 'struct': 'RmeGuestProperties', ++ 'data': { '*personalization-value': 'str' } } ++ + ## + # @ObjectType: + # +@@ -1070,6 +1084,7 @@ + 'pr-manager-helper': { 'type': 'PrManagerHelperProperties', + 'if': 'CONFIG_LINUX' }, + 'qtest': 'QtestProperties', ++ 'rme-guest': 'RmeGuestProperties', + 'rng-builtin': 'RngProperties', + 'rng-egd': 'RngEgdProperties', + 'rng-random': { 'type': 'RngRandomProperties', +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 1f42187699..e8976e4740 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -12,6 +12,7 @@ + #include "kvm_arm.h" + #include "migration/blocker.h" + #include "qapi/error.h" ++#include "qemu/base64.h" + #include "qemu/error-report.h" + #include "qom/object_interfaces.h" + #include "exec/confidential-guest-support.h" +@@ -33,6 +34,9 @@ struct RmeGuest { + Notifier rom_load_notifier; + GSList *ram_regions; + ++ char *personalization_value_str; ++ uint8_t personalization_value[ARM_RME_CONFIG_RPV_SIZE]; ++ + RmeRamRegion init_ram; + }; + +@@ -42,6 +46,48 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, + + static RmeGuest *rme_guest; + ++static int rme_configure_one(RmeGuest *guest, uint32_t cfg, Error **errp) ++{ ++ int ret; ++ const char *cfg_str; ++ struct arm_rme_config args = { ++ .cfg = cfg, ++ }; ++ ++ switch (cfg) { ++ case ARM_RME_CONFIG_RPV: ++ memcpy(args.rpv, guest->personalization_value, ARM_RME_CONFIG_RPV_SIZE); ++ cfg_str = "personalization value"; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, ++ KVM_CAP_ARM_RME_CONFIG_REALM, (intptr_t)&args); ++ if (ret) { ++ error_setg_errno(errp, -ret, "failed to configure %s", cfg_str); ++ } ++ return ret; ++} ++ ++static int rme_configure(Error **errp) ++{ ++ int ret; ++ size_t option; ++ const uint32_t config_options[] = { ++ ARM_RME_CONFIG_RPV, ++ }; ++ ++ for (option = 0; option < ARRAY_SIZE(config_options); option++) { ++ ret = rme_configure_one(rme_guest, config_options[option], errp); ++ if (ret) { ++ return ret; ++ } ++ } ++ return 0; ++} ++ + static int rme_init_ram(RmeRamRegion *ram, Error **errp) + { + int ret; +@@ -122,6 +168,10 @@ static int rme_create_realm(Error **errp) + { + int ret; + ++ if (rme_configure(errp)) { ++ return -1; ++ } ++ + ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_RME_CREATE_REALM); + if (ret) { +@@ -167,8 +217,43 @@ static void rme_vm_state_change(void *opaque, bool running, RunState state) + } + } + ++static char *rme_get_rpv(Object *obj, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ ++ return g_strdup(guest->personalization_value_str); ++} ++ ++static void rme_set_rpv(Object *obj, const char *value, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ g_autofree uint8_t *rpv = NULL; ++ size_t len; ++ ++ rpv = qbase64_decode(value, -1, &len, errp); ++ if (!rpv) { ++ return; ++ } ++ ++ if (len != sizeof(guest->personalization_value)) { ++ error_setg(errp, ++ "expecting a Realm Personalization Value of size %zu, got %zu\n", ++ sizeof(guest->personalization_value), len); ++ return; ++ } ++ memcpy(guest->personalization_value, rpv, len); ++ ++ /* Save the value so we don't need to encode it in the getter */ ++ g_free(guest->personalization_value_str); ++ guest->personalization_value_str = g_strdup(value); ++} ++ + static void rme_guest_class_init(ObjectClass *oc, void *data) + { ++ object_class_property_add_str(oc, "personalization-value", rme_get_rpv, ++ rme_set_rpv); ++ object_class_property_set_description(oc, "personalization-value", ++ "Realm personalization value (64 bytes encodede in base64)"); + } + + static void rme_guest_init(Object *obj) +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Add-measurement-algorithm-propert.patch b/target-arm-kvm-rme-Add-measurement-algorithm-propert.patch new file mode 100644 index 00000000..d7b88e94 --- /dev/null +++ b/target-arm-kvm-rme-Add-measurement-algorithm-propert.patch @@ -0,0 +1,158 @@ +From 82c8a1979a23a073c3ed8965de10f79e3a676b2c Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 27 Oct 2022 19:22:48 +0100 +Subject: [PATCH] target/arm/kvm-rme: Add measurement algorithm property +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/26ed0bafc44a8d4d8fcc46a1ee7a2b8aa35b1c33 + +This option selects which measurement algorithm to use for attestation. +Supported values are SHA256 and SHA512. Default to SHA512 arbitrarily. + +SHA512 is generally faster on 64-bit architectures. On a few arm64 CPUs +I tested SHA256 is much faster, but that's most likely because they only +support acceleration via FEAT_SHA256 (Armv8.0) and not FEAT_SHA512 +(Armv8.2). Future CPUs supporting RME are likely to also support +FEAT_SHA512. + +Cc: Eric Blake +Cc: Markus Armbruster +Cc: Daniel P. Berrangé +Cc: Eduardo Habkost +Acked-by: Markus Armbruster +Signed-off-by: Jean-Philippe Brucker +Signed-off-by: houmingyong +--- + qapi/qom.json | 20 +++++++++++++++++++- + target/arm/kvm-rme.c | 38 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 57 insertions(+), 1 deletion(-) + +diff --git a/qapi/qom.json b/qapi/qom.json +index 0120369454..02b45e1068 100644 +--- a/qapi/qom.json ++++ b/qapi/qom.json +@@ -952,6 +952,20 @@ + '*kae': 'uint32', + '*measurement-algo': 'TmmGuestMeasurementAlgo' } } + ++## ++# @RmeGuestMeasurementAlgorithm: ++# ++# @sha256: Use the SHA256 algorithm ++# ++# @sha512: Use the SHA512 algorithm ++# ++# Algorithm to use for realm measurements ++# ++# Since: 10.0 ++## ++{ 'enum': 'RmeGuestMeasurementAlgorithm', ++ 'data': ['sha256', 'sha512'] } ++ + ## + # @RmeGuestProperties: + # +@@ -961,10 +975,14 @@ + # This optional parameter allows to uniquely identify the VM instance + # during attestation. (default: all-zero) + # ++# @measurement-algorithm: Realm measurement algorithm ++# (default: sha512) ++# + # Since: 10.0 + ## + { 'struct': 'RmeGuestProperties', +- 'data': { '*personalization-value': 'str' } } ++ 'data': { '*personalization-value': 'str', ++ '*measurement-algorithm': 'RmeGuestMeasurementAlgorithm' } } + + ## + # @ObjectType: +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index e8976e4740..5e785fa3b6 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -36,6 +36,7 @@ struct RmeGuest { + + char *personalization_value_str; + uint8_t personalization_value[ARM_RME_CONFIG_RPV_SIZE]; ++ RmeGuestMeasurementAlgorithm measurement_algo; + + RmeRamRegion init_ram; + }; +@@ -59,6 +60,19 @@ static int rme_configure_one(RmeGuest *guest, uint32_t cfg, Error **errp) + memcpy(args.rpv, guest->personalization_value, ARM_RME_CONFIG_RPV_SIZE); + cfg_str = "personalization value"; + break; ++ case ARM_RME_CONFIG_HASH_ALGO: ++ switch (guest->measurement_algo) { ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA256: ++ args.hash_algo = ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA256; ++ break; ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA512: ++ args.hash_algo = ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA512; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ cfg_str = "hash algorithm"; ++ break; + default: + g_assert_not_reached(); + } +@@ -77,6 +91,7 @@ static int rme_configure(Error **errp) + size_t option; + const uint32_t config_options[] = { + ARM_RME_CONFIG_RPV, ++ ARM_RME_CONFIG_HASH_ALGO, + }; + + for (option = 0; option < ARRAY_SIZE(config_options); option++) { +@@ -248,12 +263,34 @@ static void rme_set_rpv(Object *obj, const char *value, Error **errp) + guest->personalization_value_str = g_strdup(value); + } + ++static int rme_get_measurement_algo(Object *obj, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ ++ return guest->measurement_algo; ++} ++ ++static void rme_set_measurement_algo(Object *obj, int algo, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ ++ guest->measurement_algo = algo; ++} ++ + static void rme_guest_class_init(ObjectClass *oc, void *data) + { + object_class_property_add_str(oc, "personalization-value", rme_get_rpv, + rme_set_rpv); + object_class_property_set_description(oc, "personalization-value", + "Realm personalization value (64 bytes encodede in base64)"); ++ ++ object_class_property_add_enum(oc, "measurement-algorithm", ++ "RmeGuestMeasurementAlgorithm", ++ &RmeGuestMeasurementAlgorithm_lookup, ++ rme_get_measurement_algo, ++ rme_set_measurement_algo); ++ object_class_property_set_description(oc, "measurement-algorithm", ++ "Realm measurement algorithm ('sha256', 'sha512')"); + } + + static void rme_guest_init(Object *obj) +@@ -263,6 +300,7 @@ static void rme_guest_init(Object *obj) + exit(1); + } + rme_guest = RME_GUEST(obj); ++ rme_guest->measurement_algo = RME_GUEST_MEASUREMENT_ALGORITHM_SHA512; + } + + static void rme_guest_finalize(Object *obj) +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Add-measurement-log.patch b/target-arm-kvm-rme-Add-measurement-log.patch new file mode 100644 index 00000000..cf5ac318 --- /dev/null +++ b/target-arm-kvm-rme-Add-measurement-log.patch @@ -0,0 +1,636 @@ +From 58bb383f608b5f4f58f9fac365efe742c1f0335c Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Thu, 7 Nov 2024 17:38:11 +0000 +Subject: [PATCH] target/arm/kvm-rme: Add measurement log + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/4a2fc9b28becfdae3d5662218b921f8970825bd6 + +Create an event log in the format defined by Trusted Computing Group +for TPM2. It contains information about the VMM, the Realm parameters, +any data loaded into guest memory before boot, and the initial vCPU +state. + +The guest can access this log from RAM and send it to a verifier, to +help the verifier independently compute the Realm Initial Measurement, +and check that the data we load into guest RAM is known-good images. +Without this log, in order to end up with the right Measurement, the +verifier needs to guess what is loaded, where and in what order. + +Cc: Stefan Berger +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/Kconfig + target/arm/kvm-rme.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + qapi/qom.json | 9 +- + target/arm/Kconfig | 1 + + target/arm/kvm-rme.c | 403 ++++++++++++++++++++++++++++++++++++++++++- + target/arm/kvm_arm.h | 15 ++ + 4 files changed, 426 insertions(+), 2 deletions(-) + +diff --git a/qapi/qom.json b/qapi/qom.json +index 02b45e1068..e0590a6019 100644 +--- a/qapi/qom.json ++++ b/qapi/qom.json +@@ -978,11 +978,18 @@ + # @measurement-algorithm: Realm measurement algorithm + # (default: sha512) + # ++# @measurement-log: Enable a measurement log for the Realm. All events ++# that contribute to the Realm Initial Measurement (RIM) are added ++# to a log in TCG TPM2 format, which is itself loaded into Realm ++# memory (unmeasured) and can then be read by a verifier to ++# reconstruct the RIM. ++# + # Since: 10.0 + ## + { 'struct': 'RmeGuestProperties', + 'data': { '*personalization-value': 'str', +- '*measurement-algorithm': 'RmeGuestMeasurementAlgorithm' } } ++ '*measurement-algorithm': 'RmeGuestMeasurementAlgorithm', ++ '*measurement-log': 'bool'} } + + ## + # @ObjectType: +diff --git a/target/arm/Kconfig b/target/arm/Kconfig +index bf57d739cd..14977f1d83 100644 +--- a/target/arm/Kconfig ++++ b/target/arm/Kconfig +@@ -9,3 +9,4 @@ config ARM + config AARCH64 + bool + select ARM ++ select TPM_LOG if KVM +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 299af009d9..26dda39df6 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -10,11 +10,13 @@ + #include "hw/core/cpu.h" + #include "hw/loader.h" + #include "hw/pci/pci.h" ++#include "hw/tpm/tpm_log.h" + #include "kvm_arm.h" + #include "migration/blocker.h" + #include "qapi/error.h" + #include "qemu/base64.h" + #include "qemu/error-report.h" ++#include "qemu/units.h" + #include "qom/object_interfaces.h" + #include "exec/confidential-guest-support.h" + #include "sysemu/kvm.h" +@@ -25,6 +27,14 @@ OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST) + + #define RME_PAGE_SIZE qemu_real_host_page_size() + ++#define RME_MEASUREMENT_LOG_SIZE (64 * KiB) ++ ++typedef struct RmeLogFiletype { ++ uint32_t event_type; ++ /* Description copied into the log event */ ++ const char *desc; ++} RmeLogFiletype; ++ + /* + * Realms have a split guest-physical address space: the bottom half is private + * to the realm, and the top half is shared with the host. Within QEMU, we use a +@@ -57,6 +67,8 @@ typedef struct RealmPrivateSharedListener { + typedef struct { + hwaddr base; + hwaddr size; ++ uint8_t *blob_ptr; ++ RmeLogFiletype *filetype; + } RmeRamRegion; + + struct RmeGuest { +@@ -67,22 +79,335 @@ struct RmeGuest { + char *personalization_value_str; + uint8_t personalization_value[ARM_RME_CONFIG_RPV_SIZE]; + RmeGuestMeasurementAlgorithm measurement_algo; ++ bool use_measurement_log; + + RmeRamRegion init_ram; + uint8_t ipa_bits; ++ size_t num_cpus; + + RealmDmaRegion *dma_region; + QLIST_HEAD(, RealmPrivateSharedListener) ram_discard_list; + MemoryListener memory_listener; + AddressSpace dma_as; ++ ++ TpmLog *log; ++ GHashTable *images; + }; + + OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, + CONFIDENTIAL_GUEST_SUPPORT, + { TYPE_USER_CREATABLE }, { }) + ++typedef struct { ++ char signature[16]; ++ char name[32]; ++ char version[40]; ++ uint64_t ram_size; ++ uint32_t num_cpus; ++ uint64_t flags; ++} EventLogVmmVersion; ++ ++typedef struct { ++ uint32_t id; ++ uint32_t data_size; ++ uint8_t data[]; ++} EventLogTagged; ++ ++#define EVENT_LOG_TAG_REALM_CREATE 1 ++#define EVENT_LOG_TAG_INIT_RIPAS 2 ++#define EVENT_LOG_TAG_REC_CREATE 3 ++ ++#define REALM_PARAMS_FLAG_SVE (1 << 1) ++#define REALM_PARAMS_FLAG_PMU (1 << 2) ++ ++#define REC_CREATE_FLAG_RUNNABLE (1 << 0) ++ + static RmeGuest *rme_guest; + ++static int rme_init_measurement_log(MachineState *ms) ++{ ++ Object *log; ++ gpointer filename; ++ TpmLogDigestAlgo algo; ++ RmeLogFiletype *filetype; ++ ++ if (!rme_guest->use_measurement_log) { ++ return 0; ++ } ++ ++ switch (rme_guest->measurement_algo) { ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA256: ++ algo = TPM_LOG_DIGEST_ALGO_SHA256; ++ break; ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA512: ++ algo = TPM_LOG_DIGEST_ALGO_SHA512; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ log = object_new_with_props(TYPE_TPM_LOG, OBJECT(rme_guest), ++ "log", &error_fatal, ++ "digest-algo", TpmLogDigestAlgo_str(algo), ++ NULL); ++ ++ tpm_log_create(TPM_LOG(log), RME_MEASUREMENT_LOG_SIZE, &error_fatal); ++ rme_guest->log = TPM_LOG(log); ++ ++ /* ++ * Write down the image names we're expecting to encounter when handling the ++ * ROM load notifications, so we can record the type of image being loaded ++ * to help the verifier. ++ */ ++ rme_guest->images = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, ++ g_free); ++ ++ filename = g_strdup(ms->kernel_filename); ++ if (filename) { ++ filetype = g_new0(RmeLogFiletype, 1); ++ filetype->event_type = TCG_EV_POST_CODE2; ++ filetype->desc = "KERNEL"; ++ g_hash_table_insert(rme_guest->images, filename, (gpointer)filetype); ++ } ++ ++ filename = g_strdup(ms->initrd_filename); ++ if (filename) { ++ filetype = g_new0(RmeLogFiletype, 1); ++ filetype->event_type = TCG_EV_POST_CODE2; ++ filetype->desc = "INITRD"; ++ g_hash_table_insert(rme_guest->images, filename, (gpointer)filetype); ++ } ++ ++ filename = g_strdup(ms->firmware); ++ if (filename) { ++ filetype = g_new0(RmeLogFiletype, 1); ++ filetype->event_type = TCG_EV_EFI_PLATFORM_FIRMWARE_BLOB2; ++ filetype->desc = "FIRMWARE"; ++ g_hash_table_insert(rme_guest->images, filename, filetype); ++ } ++ ++ filename = g_strdup(ms->dtb); ++ if (!filename) { ++ filename = g_strdup("dtb"); ++ } ++ filetype = g_new0(RmeLogFiletype, 1); ++ filetype->event_type = TCG_EV_POST_CODE2; ++ filetype->desc = "DTB"; ++ g_hash_table_insert(rme_guest->images, filename, filetype); ++ ++ return 0; ++} ++ ++static int rme_log_event_tag(uint32_t id, uint8_t *data, size_t size, ++ Error **errp) ++{ ++ int ret; ++ EventLogTagged event = { ++ .id = id, ++ .data_size = size, ++ }; ++ GByteArray *bytes = g_byte_array_new(); ++ ++ if (!rme_guest->log) { ++ return 0; ++ } ++ ++ g_byte_array_append(bytes, (uint8_t *)&event, sizeof(event)); ++ g_byte_array_append(bytes, data, size); ++ ret = tpm_log_add_event(rme_guest->log, TCG_EV_EVENT_TAG, bytes->data, ++ bytes->len, NULL, 0, errp); ++ g_byte_array_free(bytes, true); ++ return ret; ++} ++ ++/* Log VM type and Realm Descriptor create */ ++static int rme_log_realm_create(Error **errp) ++{ ++ int ret; ++ ARMCPU *cpu; ++ EventLogVmmVersion vmm_version = { ++ .signature = "VM VERSION", ++ .name = "QEMU", ++ .version = QEMU_VERSION, ++ .ram_size = cpu_to_le64(rme_guest->init_ram.size), ++ .num_cpus = cpu_to_le32(rme_guest->num_cpus), ++ .flags = 0, ++ }; ++ struct { ++ uint64_t flags; ++ uint8_t s2sz; ++ uint8_t sve_vl; ++ uint8_t num_bps; ++ uint8_t num_wps; ++ uint8_t pmu_num_ctrs; ++ uint8_t hash_algo; ++ } params = { ++ .s2sz = rme_guest->ipa_bits, ++ }; ++ ++ if (!rme_guest->log) { ++ return 0; ++ } ++ ++ ret = tpm_log_add_event(rme_guest->log, TCG_EV_NO_ACTION, ++ (uint8_t *)&vmm_version, sizeof(vmm_version), ++ NULL, 0, errp); ++ if (ret) { ++ return ret; ++ } ++ ++ /* With KVM all CPUs have the same capability */ ++ cpu = ARM_CPU(first_cpu); ++ if (cpu->has_pmu) { ++ params.flags |= REALM_PARAMS_FLAG_PMU; ++ params.pmu_num_ctrs = FIELD_EX64(cpu->isar.reset_pmcr_el0, PMCR, N); ++ } ++ ++ if (cpu->sve_max_vq) { ++ params.flags |= REALM_PARAMS_FLAG_SVE; ++ params.sve_vl = cpu->sve_max_vq - 1; ++ } ++ params.num_bps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); ++ params.num_wps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); ++ ++ switch (rme_guest->measurement_algo) { ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA256: ++ params.hash_algo = ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA256; ++ break; ++ case RME_GUEST_MEASUREMENT_ALGORITHM_SHA512: ++ params.hash_algo = ARM_RME_CONFIG_MEASUREMENT_ALGO_SHA512; ++ break; ++ default: ++ g_assert_not_reached(); ++ } ++ ++ return rme_log_event_tag(EVENT_LOG_TAG_REALM_CREATE, (uint8_t *)¶ms, ++ sizeof(params), errp); ++} ++ ++/* unmeasured images are logged with @data == NULL */ ++static int rme_log_image(RmeLogFiletype *filetype, uint8_t *data, hwaddr base, ++ size_t size, Error **errp) ++{ ++ int ret; ++ size_t desc_size; ++ GByteArray *event = g_byte_array_new(); ++ struct UefiPlatformFirmwareBlob2Head head = {0}; ++ struct UefiPlatformFirmwareBlob2Tail tail = {0}; ++ ++ if (!rme_guest->log) { ++ return 0; ++ } ++ ++ if (!filetype) { ++ error_setg(errp, "cannot log image without a filetype"); ++ return -1; ++ } ++ ++ /* EV_POST_CODE2 strings are not NUL-terminated */ ++ desc_size = strlen(filetype->desc); ++ head.blob_description_size = desc_size; ++ tail.blob_base = cpu_to_le64(base); ++ tail.blob_size = cpu_to_le64(size); ++ ++ g_byte_array_append(event, (guint8 *)&head, sizeof(head)); ++ g_byte_array_append(event, (guint8 *)filetype->desc, desc_size); ++ g_byte_array_append(event, (guint8 *)&tail, sizeof(tail)); ++ ++ ret = tpm_log_add_event(rme_guest->log, filetype->event_type, event->data, ++ event->len, data, size, errp); ++ g_byte_array_free(event, true); ++ return ret; ++} ++ ++static int rme_log_ripas(hwaddr base, size_t size, Error **errp) ++{ ++ struct { ++ uint64_t base; ++ uint64_t size; ++ } init_ripas = { ++ .base = cpu_to_le64(base), ++ .size = cpu_to_le64(size), ++ }; ++ ++ return rme_log_event_tag(EVENT_LOG_TAG_INIT_RIPAS, (uint8_t *)&init_ripas, ++ sizeof(init_ripas), errp); ++} ++ ++static int rme_log_rec(uint64_t flags, uint64_t pc, uint64_t gprs[8], Error **errp) ++{ ++ struct { ++ uint64_t flags; ++ uint64_t pc; ++ uint64_t gprs[8]; ++ } rec_create = { ++ .flags = cpu_to_le64(flags), ++ .pc = cpu_to_le64(pc), ++ .gprs[0] = cpu_to_le64(gprs[0]), ++ .gprs[1] = cpu_to_le64(gprs[1]), ++ .gprs[2] = cpu_to_le64(gprs[2]), ++ .gprs[3] = cpu_to_le64(gprs[3]), ++ .gprs[4] = cpu_to_le64(gprs[4]), ++ .gprs[5] = cpu_to_le64(gprs[5]), ++ .gprs[6] = cpu_to_le64(gprs[6]), ++ .gprs[7] = cpu_to_le64(gprs[7]), ++ }; ++ ++ return rme_log_event_tag(EVENT_LOG_TAG_REC_CREATE, (uint8_t *)&rec_create, ++ sizeof(rec_create), errp); ++} ++ ++static int rme_populate_range(hwaddr base, size_t size, bool measure, ++ Error **errp); ++ ++static int rme_close_measurement_log(Error **errp) ++{ ++ int ret; ++ hwaddr base; ++ size_t size; ++ RmeLogFiletype filetype = { ++ .event_type = TCG_EV_POST_CODE2, ++ .desc = "LOG", ++ }; ++ ++ if (!rme_guest->log) { ++ return 0; ++ } ++ ++ base = object_property_get_uint(OBJECT(rme_guest->log), "load-addr", errp); ++ if (*errp) { ++ return -1; ++ } ++ ++ size = object_property_get_uint(OBJECT(rme_guest->log), "max-size", errp); ++ if (*errp) { ++ return -1; ++ } ++ ++ /* Log the log itself */ ++ ret = rme_log_image(&filetype, NULL, base, size, errp); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = tpm_log_write_and_close(rme_guest->log, errp); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = rme_populate_range(base, size, /* measure */ false, errp); ++ if (ret) { ++ return ret; ++ } ++ ++ g_hash_table_destroy(rme_guest->images); ++ ++ /* The log is now in the guest. Free this object */ ++ object_unparent(OBJECT(rme_guest->log)); ++ rme_guest->log = NULL; ++ return 0; ++} ++ + static int rme_configure_one(RmeGuest *guest, uint32_t cfg, Error **errp) + { + int ret; +@@ -156,9 +481,10 @@ static int rme_init_ram(RmeRamRegion *ram, Error **errp) + error_setg_errno(errp, -ret, + "failed to init RAM [0x%"HWADDR_PRIx", 0x%"HWADDR_PRIx")", + start, end); ++ return ret; + } + +- return ret; ++ return rme_log_ripas(ram->base, ram->size, errp); + } + + static int rme_populate_range(hwaddr base, size_t size, bool measure, +@@ -194,23 +520,42 @@ static void rme_populate_ram_region(gpointer data, gpointer err) + } + + rme_populate_range(region->base, region->size, /* measure */ true, errp); ++ if (*errp) { ++ return; ++ } ++ ++ rme_log_image(region->filetype, region->blob_ptr, region->base, ++ region->size, errp); + } + + static int rme_init_cpus(Error **errp) + { + int ret; + CPUState *cs; ++ bool logged_primary_cpu = false; + + /* + * Now that do_cpu_reset() initialized the boot PC and + * kvm_cpu_synchronize_post_reset() registered it, we can finalize the REC. + */ + CPU_FOREACH(cs) { ++ ARMCPU *cpu = ARM_CPU(cs); ++ + ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_REC); + if (ret) { + error_setg_errno(errp, -ret, "failed to finalize vCPU"); + return ret; + } ++ ++ if (!logged_primary_cpu) { ++ ret = rme_log_rec(REC_CREATE_FLAG_RUNNABLE, cpu->env.pc, ++ cpu->env.xregs, errp); ++ if (ret) { ++ return ret; ++ } ++ ++ logged_primary_cpu = true; ++ } + } + return 0; + } +@@ -230,6 +575,10 @@ static int rme_create_realm(Error **errp) + return -1; + } + ++ if (rme_log_realm_create(errp)) { ++ return -1; ++ } ++ + if (rme_init_ram(&rme_guest->init_ram, errp)) { + return -1; + } +@@ -244,6 +593,10 @@ static int rme_create_realm(Error **errp) + return -1; + } + ++ if (rme_close_measurement_log(errp)) { ++ return -1; ++ } ++ + ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + KVM_CAP_ARM_RME_ACTIVATE_REALM); + if (ret) { +@@ -313,6 +666,20 @@ static void rme_set_measurement_algo(Object *obj, int algo, Error **errp) + guest->measurement_algo = algo; + } + ++static bool rme_get_measurement_log(Object *obj, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ ++ return guest->use_measurement_log; ++} ++ ++static void rme_set_measurement_log(Object *obj, bool value, Error **errp) ++{ ++ RmeGuest *guest = RME_GUEST(obj); ++ ++ guest->use_measurement_log = value; ++} ++ + static void rme_guest_class_init(ObjectClass *oc, void *data) + { + object_class_property_add_str(oc, "personalization-value", rme_get_rpv, +@@ -327,6 +694,12 @@ static void rme_guest_class_init(ObjectClass *oc, void *data) + rme_set_measurement_algo); + object_class_property_set_description(oc, "measurement-algorithm", + "Realm measurement algorithm ('sha256', 'sha512')"); ++ ++ object_class_property_add_bool(oc, "measurement-log", ++ rme_get_measurement_log, ++ rme_set_measurement_log); ++ object_class_property_set_description(oc, "measurement-log", ++ "Enable/disable Realm measurement log"); + } + + static void rme_guest_init(Object *obj) +@@ -370,6 +743,20 @@ static void rme_rom_load_notify(Notifier *notifier, void *data) + region = g_new0(RmeRamRegion, 1); + region->base = rom->addr; + region->size = rom->len; ++ /* ++ * TODO: double-check lifetime. Is data is still available when we measure ++ * it, while writing the log. Should be fine since data is kept for the next ++ * reset. ++ */ ++ region->blob_ptr = rom->blob_ptr; ++ ++ /* ++ * rme_guest->images is destroyed after ram_regions, so we can store ++ * filetype even if we don't own the struct. ++ */ ++ if (rme_guest->images) { ++ region->filetype = g_hash_table_lookup(rme_guest->images, rom->name); ++ } + + /* + * The Realm Initial Measurement (RIM) depends on the order in which we +@@ -399,6 +786,12 @@ int kvm_arm_rme_init(MachineState *ms) + return -ENODEV; + } + ++ if (rme_init_measurement_log(ms)) { ++ return -ENODEV; ++ } ++ ++ rme_guest->num_cpus = ms->smp.max_cpus; ++ + error_setg(&rme_mig_blocker, "RME: migration is not implemented"); + migrate_add_blocker(&rme_mig_blocker, &error_fatal); + +@@ -626,3 +1019,11 @@ static void realm_dma_region_class_init(ObjectClass *oc, void *data) + imrc->translate = realm_dma_region_translate; + imrc->replay = realm_dma_region_replay; + } ++ ++Object *kvm_arm_rme_get_measurement_log(void) ++{ ++ if (rme_guest && rme_guest->log) { ++ return OBJECT(rme_guest->log); ++ } ++ return NULL; ++} +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index b4d54e816f..8e9b2039c4 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -451,6 +451,16 @@ void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size); + */ + void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus); + ++/** ++ * kvm_arm_rme_get_measurement_log ++ * ++ * Obtain the measurement log object if enabled, in order to get its size and ++ * set its base address. ++ * ++ * Returns NULL if measurement log is disabled. ++ */ ++Object *kvm_arm_rme_get_measurement_log(void); ++ + #else + + /* +@@ -486,6 +496,11 @@ static inline void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, + { + } + ++static inline Object *kvm_arm_rme_get_measurement_log(void) ++{ ++ return NULL; ++} ++ + /* + * These functions should never actually be called without KVM support. + */ +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Initialize-Realm-memory.patch b/target-arm-kvm-rme-Initialize-Realm-memory.patch new file mode 100644 index 00000000..865e640e --- /dev/null +++ b/target-arm-kvm-rme-Initialize-Realm-memory.patch @@ -0,0 +1,236 @@ +From 113dda44a4857134af03ea8001a656dfea730f0e Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Wed, 14 Jun 2023 16:54:00 +0100 +Subject: [PATCH] target/arm/kvm-rme: Initialize Realm memory + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/7f3408b58fee5e7aaf7cda65bd506f7b7ce4b789 + +Initialize the IPA state of RAM. Collect the images copied into guest +RAM into a sorted list, and issue POPULATE_REALM KVM ioctls once we've +created the Realm Descriptor. The images are part of the Realm Initial +Measurement. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/kvm-rme.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/kvm-rme.c | 127 +++++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 14 +++++ + 2 files changed, 141 insertions(+) + +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index b080552076..1f42187699 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -8,6 +8,7 @@ + + #include "hw/boards.h" + #include "hw/core/cpu.h" ++#include "hw/loader.h" + #include "kvm_arm.h" + #include "migration/blocker.h" + #include "qapi/error.h" +@@ -20,8 +21,19 @@ + #define TYPE_RME_GUEST "rme-guest" + OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST) + ++#define RME_PAGE_SIZE qemu_real_host_page_size() ++ ++typedef struct { ++ hwaddr base; ++ hwaddr size; ++} RmeRamRegion; ++ + struct RmeGuest { + ConfidentialGuestSupport parent_obj; ++ Notifier rom_load_notifier; ++ GSList *ram_regions; ++ ++ RmeRamRegion init_ram; + }; + + OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, +@@ -30,6 +42,63 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, + + static RmeGuest *rme_guest; + ++static int rme_init_ram(RmeRamRegion *ram, Error **errp) ++{ ++ int ret; ++ hwaddr start = QEMU_ALIGN_DOWN(ram->base, RME_PAGE_SIZE); ++ hwaddr end = QEMU_ALIGN_UP(ram->base + ram->size, RME_PAGE_SIZE); ++ struct arm_rme_init_ripas init_args = { ++ .base = start, ++ .size = end - start, ++ }; ++ ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, ++ KVM_CAP_ARM_RME_INIT_RIPAS_REALM, ++ (intptr_t)&init_args); ++ if (ret) { ++ error_setg_errno(errp, -ret, ++ "failed to init RAM [0x%"HWADDR_PRIx", 0x%"HWADDR_PRIx")", ++ start, end); ++ } ++ ++ return ret; ++} ++ ++static int rme_populate_range(hwaddr base, size_t size, bool measure, ++ Error **errp) ++{ ++ int ret; ++ hwaddr start = QEMU_ALIGN_DOWN(base, RME_PAGE_SIZE); ++ hwaddr end = QEMU_ALIGN_UP(base + size, RME_PAGE_SIZE); ++ struct arm_rme_populate_realm populate_args = { ++ .base = start, ++ .size = end - start, ++ .flags = measure ? KVM_ARM_RME_POPULATE_FLAGS_MEASURE : 0, ++ }; ++ ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, ++ KVM_CAP_ARM_RME_POPULATE_REALM, ++ (intptr_t)&populate_args); ++ if (ret) { ++ error_setg_errno(errp, -ret, ++ "failed to populate realm [0x%"HWADDR_PRIx", 0x%"HWADDR_PRIx")", ++ start, end); ++ } ++ return ret; ++} ++ ++static void rme_populate_ram_region(gpointer data, gpointer err) ++{ ++ Error **errp = err; ++ const RmeRamRegion *region = data; ++ ++ if (*errp) { ++ return; ++ } ++ ++ rme_populate_range(region->base, region->size, /* measure */ true, errp); ++} ++ + static int rme_init_cpus(Error **errp) + { + int ret; +@@ -60,6 +129,16 @@ static int rme_create_realm(Error **errp) + return -1; + } + ++ if (rme_init_ram(&rme_guest->init_ram, errp)) { ++ return -1; ++ } ++ ++ g_slist_foreach(rme_guest->ram_regions, rme_populate_ram_region, errp); ++ g_slist_free_full(g_steal_pointer(&rme_guest->ram_regions), g_free); ++ if (*errp) { ++ return -1; ++ } ++ + if (rme_init_cpus(errp)) { + return -1; + } +@@ -105,6 +184,43 @@ static void rme_guest_finalize(Object *obj) + { + } + ++static gint rme_compare_ram_regions(gconstpointer a, gconstpointer b) ++{ ++ const RmeRamRegion *ra = a; ++ const RmeRamRegion *rb = b; ++ ++ g_assert(ra->base != rb->base); ++ return ra->base < rb->base ? -1 : 1; ++} ++ ++static void rme_rom_load_notify(Notifier *notifier, void *data) ++{ ++ RmeRamRegion *region; ++ RomLoaderNotifyData *rom = data; ++ ++ if (rom->addr == -1) { ++ /* ++ * These blobs (ACPI tables) are not loaded into guest RAM at reset. ++ * Instead the firmware will load them via fw_cfg and measure them ++ * itself. ++ */ ++ return; ++ } ++ ++ region = g_new0(RmeRamRegion, 1); ++ region->base = rom->addr; ++ region->size = rom->len; ++ ++ /* ++ * The Realm Initial Measurement (RIM) depends on the order in which we ++ * initialize and populate the RAM regions. To help a verifier ++ * independently calculate the RIM, sort regions by GPA. ++ */ ++ rme_guest->ram_regions = g_slist_insert_sorted(rme_guest->ram_regions, ++ region, ++ rme_compare_ram_regions); ++} ++ + int kvm_arm_rme_init(MachineState *ms) + { + static Error *rme_mig_blocker; +@@ -132,10 +248,21 @@ int kvm_arm_rme_init(MachineState *ms) + */ + qemu_add_vm_change_state_handler(rme_vm_state_change, NULL); + ++ rme_guest->rom_load_notifier.notify = rme_rom_load_notify; ++ rom_add_load_notifier(&rme_guest->rom_load_notifier); ++ + cgs->ready = true; + return 0; + } + ++void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size) ++{ ++ if (rme_guest) { ++ rme_guest->init_ram.base = base; ++ rme_guest->init_ram.size = size; ++ } ++} ++ + int kvm_arm_rme_vcpu_init(CPUState *cs) + { + ARMCPU *cpu = ARM_CPU(cs); +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index b6a07eb80f..78ff8b7375 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -428,6 +428,16 @@ int kvm_arm_rme_vm_type(MachineState *ms); + */ + int kvm_arm_rme_vcpu_init(CPUState *cs); + ++/* ++ * kvm_arm_rme_init_guest_ram ++ * @base: base address of RAM ++ * @size: size of RAM ++ * ++ * If the user requested a Realm, set the base and size of guest RAM, in order ++ * to initialize the Realm IPA space. ++ */ ++void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size); ++ + #else + + /* +@@ -454,6 +464,10 @@ static inline bool kvm_arm_steal_time_supported(void) + return false; + } + ++static inline void kvm_arm_rme_init_guest_ram(hwaddr base, size_t size) ++{ ++} ++ + /* + * These functions should never actually be called without KVM support. + */ +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Initialize-realm.patch b/target-arm-kvm-rme-Initialize-realm.patch new file mode 100644 index 00000000..703996e0 --- /dev/null +++ b/target-arm-kvm-rme-Initialize-realm.patch @@ -0,0 +1,272 @@ +From fa74508ed08091c350f431438f42a78b54896e3e Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 9 Jan 2023 10:45:27 +0000 +Subject: [PATCH] target/arm/kvm-rme: Initialize realm + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/017b4eea65b93578831312e9548f8b3c6479fc08 + +The machine code calls kvm_arm_rme_vm_type() to get the VM flag and KVM +calls kvm_arm_rme_init() to prepare for launching a Realm. Once VM +creation is complete, create the Realm: + +* Create the realm descriptor, +* load images into Realm RAM (in another patch), +* finalize the REC (vCPU) after the registers are reset, +* activate the realm, at which point the realm is sealed. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/kvm.c + target/arm/kvm_arm.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/kvm-rme.c | 105 +++++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm.c | 7 ++- + target/arm/kvm_arm.h | 53 ++++++++++++++++------ + 3 files changed, 150 insertions(+), 15 deletions(-) + +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 1de65f2b1d..3c6fecc741 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -11,6 +11,7 @@ + #include "kvm_arm.h" + #include "migration/blocker.h" + #include "qapi/error.h" ++#include "qemu/error-report.h" + #include "qom/object_interfaces.h" + #include "exec/confidential-guest-support.h" + #include "sysemu/kvm.h" +@@ -27,14 +28,118 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RmeGuest, rme_guest, RME_GUEST, + CONFIDENTIAL_GUEST_SUPPORT, + { TYPE_USER_CREATABLE }, { }) + ++static RmeGuest *rme_guest; ++ ++static int rme_init_cpus(Error **errp) ++{ ++ int ret; ++ CPUState *cs; ++ ++ /* ++ * Now that do_cpu_reset() initialized the boot PC and ++ * kvm_cpu_synchronize_post_reset() registered it, we can finalize the REC. ++ */ ++ CPU_FOREACH(cs) { ++ ret = kvm_arm_vcpu_finalize(cs, KVM_ARM_VCPU_REC); ++ if (ret) { ++ error_setg_errno(errp, -ret, "failed to finalize vCPU"); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int rme_create_realm(Error **errp) ++{ ++ int ret; ++ ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, ++ KVM_CAP_ARM_RME_CREATE_REALM); ++ if (ret) { ++ error_setg_errno(errp, -ret, "failed to create Realm Descriptor"); ++ return -1; ++ } ++ ++ if (rme_init_cpus(errp)) { ++ return -1; ++ } ++ ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, ++ KVM_CAP_ARM_RME_ACTIVATE_REALM); ++ if (ret) { ++ error_setg_errno(errp, -ret, "failed to activate realm"); ++ return -1; ++ } ++ ++ kvm_mark_guest_state_protected(); ++ return 0; ++} ++ ++static void rme_vm_state_change(void *opaque, bool running, RunState state) ++{ ++ Error *err = NULL; ++ ++ if (!running) { ++ return; ++ } ++ ++ if (rme_create_realm(&err)) { ++ error_propagate_prepend(&error_fatal, err, "RME: "); ++ } ++} ++ + static void rme_guest_class_init(ObjectClass *oc, void *data) + { + } + + static void rme_guest_init(Object *obj) + { ++ if (rme_guest) { ++ error_report("a single instance of RmeGuest is supported"); ++ exit(1); ++ } ++ rme_guest = RME_GUEST(obj); + } + + static void rme_guest_finalize(Object *obj) + { + } ++ ++int kvm_arm_rme_init(MachineState *ms) ++{ ++ static Error *rme_mig_blocker; ++ ConfidentialGuestSupport *cgs = ms->cgs; ++ ++ if (!rme_guest) { ++ return 0; ++ } ++ ++ if (!cgs) { ++ error_report("missing -machine confidential-guest-support parameter"); ++ return -EINVAL; ++ } ++ ++ if (!kvm_check_extension(kvm_state, KVM_CAP_ARM_RME)) { ++ return -ENODEV; ++ } ++ ++ error_setg(&rme_mig_blocker, "RME: migration is not implemented"); ++ migrate_add_blocker(&rme_mig_blocker, &error_fatal); ++ ++ /* ++ * The realm activation is done last, when the VM starts, after all images ++ * have been loaded and all vcpus finalized. ++ */ ++ qemu_add_vm_change_state_handler(rme_vm_state_change, NULL); ++ ++ cgs->ready = true; ++ return 0; ++} ++ ++int kvm_arm_rme_vm_type(MachineState *ms) ++{ ++ if (rme_guest) { ++ return KVM_VM_TYPE_ARM_REALM; ++ } ++ return 0; ++} +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index e32a064f94..83462f3f62 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -349,7 +349,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + kvm_arm_init_debug(s); + kvm_update_ipiv_cap(s); + +- return 0; ++ ret = kvm_arm_rme_init(ms); ++ if (ret) { ++ error_report("Failed to enable RME: %s", strerror(-ret)); ++ } ++ ++ return ret; + } + + unsigned long kvm_arch_vcpu_id(CPUState *cpu) +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index a29d4548f4..f17de8855a 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -38,20 +38,6 @@ void kvm_arm_init_debug(KVMState *s); + */ + int kvm_arm_vcpu_init(CPUState *cs); + +-/** +- * kvm_arm_vcpu_finalize: +- * @cs: CPUState +- * @feature: feature to finalize +- * +- * Finalizes the configuration of the specified VCPU feature by +- * invoking the KVM_ARM_VCPU_FINALIZE ioctl. Features requiring +- * this are documented in the "KVM_ARM_VCPU_FINALIZE" section of +- * KVM's API documentation. +- * +- * Returns: 0 if success else < 0 error code +- */ +-int kvm_arm_vcpu_finalize(CPUState *cs, int feature); +- + /** + * kvm_arm_register_device: + * @mr: memory region for this device +@@ -285,6 +271,14 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); + */ + void kvm_arm_add_vcpu_properties(Object *obj); + ++/** ++ * @cs: CPUState ++ * @feature: a KVM_ARM_VCPU_* feature ++ * ++ * Finalize the configuration of the given vcpu feature. ++ */ ++int kvm_arm_vcpu_finalize(CPUState *cs, int feature); ++ + /** + * kvm_arm_steal_time_finalize: + * @cpu: ARMCPU for which to finalize kvm-steal-time +@@ -408,6 +402,22 @@ bool kvm_arm_tmm_enabled(void); + */ + int kvm_arm_set_smccc_filter(uint64_t func, uint8_t faction); + ++/** ++ * kvm_arm_rme_init ++ * @ms: the machine state ++ * ++ * Prepare the machine to be a Realm, if the user enabled it. ++ */ ++int kvm_arm_rme_init(MachineState *ms); ++ ++/** ++ * kvm_arm_rme_vm_type ++ * @ms: the machine state ++ * ++ * Returns the Realm KVM VM type if the user requested a Realm, 0 otherwise. ++ */ ++int kvm_arm_rme_vm_type(MachineState *ms); ++ + #else + + /* +@@ -447,6 +457,11 @@ static inline void kvm_arm_add_vcpu_properties(Object *obj) + g_assert_not_reached(); + } + ++static inline int kvm_arm_vcpu_finalize(CPUState *cs, int feature) ++{ ++ g_assert_not_reached(); ++} ++ + static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa) + { + g_assert_not_reached(); +@@ -512,6 +527,16 @@ static inline int tmm_get_kae_num(void) + { + g_assert_not_reached(); + } ++ ++static inline int kvm_arm_rme_init(MachineState *ms) ++{ ++ g_assert_not_reached(); ++} ++ ++static inline int kvm_arm_rme_vm_type(MachineState *ms) ++{ ++ g_assert_not_reached(); ++} + #endif + + /** +-- +2.33.0 + diff --git a/target-arm-kvm-rme-Initialize-vCPU.patch b/target-arm-kvm-rme-Initialize-vCPU.patch new file mode 100644 index 00000000..44f493f3 --- /dev/null +++ b/target-arm-kvm-rme-Initialize-vCPU.patch @@ -0,0 +1,191 @@ +From 7f5d4809907044fd11fa040210f62b520f16ba02 Mon Sep 17 00:00:00 2001 +From: Jean-Philippe Brucker +Date: Mon, 9 Jan 2023 10:55:32 +0000 +Subject: [PATCH] target/arm/kvm-rme: Initialize vCPU + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/0808c64a827150c4a8576e52101386df9c08c136 + +The target code calls kvm_arm_vcpu_init() to mark the vCPU as part of a +Realm. For a Realm vCPU, only x0-x7 can be set at runtime. Before boot, +the PC can also be set, and is ignored at runtime. KVM also accepts a +few system register changes during initial configuration, as returned by +KVM_GET_REG_LIST. + +Signed-off-by: Jean-Philippe Brucker +Conflicts: + target/arm/kvm.c + target/arm/kvm_arm.h +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + target/arm/cpu.h | 3 +++ + target/arm/kvm-rme.c | 11 +++++++++ + target/arm/kvm64.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 16 +++++++++++++ + 4 files changed, 83 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index a5ba7f2a26..12305effd4 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -976,6 +976,9 @@ struct ArchCPU { + bool kvm_sve_finalized; + #endif /* CONFIG_KVM */ + ++ /* Realm Management Extension */ ++ bool kvm_rme; ++ + /* Uniprocessor system with MP extensions */ + bool mp_is_up; + +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 3c6fecc741..b080552076 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -136,6 +136,17 @@ int kvm_arm_rme_init(MachineState *ms) + return 0; + } + ++int kvm_arm_rme_vcpu_init(CPUState *cs) ++{ ++ ARMCPU *cpu = ARM_CPU(cs); ++ ++ if (rme_guest) { ++ cpu->kvm_rme = true; ++ cpu->kvm_init_features[0] |= (1 << KVM_ARM_VCPU_REC); ++ } ++ return 0; ++} ++ + int kvm_arm_rme_vm_type(MachineState *ms) + { + if (rme_guest) { +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 20a357061c..d314927027 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -646,6 +646,11 @@ int kvm_arch_init_vcpu(CPUState *cs) + 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC); + } + ++ ret = kvm_arm_rme_vcpu_init(cs); ++ if (ret) { ++ return ret; ++ } ++ + /* Do KVM_ARM_VCPU_INIT ioctl */ + ret = kvm_arm_vcpu_init(cs); + if (ret) { +@@ -838,6 +843,29 @@ static int kvm_arch_put_sve(CPUState *cs) + return 0; + } + ++static int kvm_arm_rme_put_core_regs(CPUState *cs) ++{ ++ int i, ret; ++ ARMCPU *cpu = ARM_CPU(cs); ++ CPUARMState *env = &cpu->env; ++ ++ /* The RME ABI only allows us to set 8 GPRs and the PC */ ++ for (i = 0; i < 8; i++) { ++ ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]), ++ &env->xregs[i]); ++ if (ret) { ++ return ret; ++ } ++ } ++ ++ ret = kvm_set_one_reg(cs, AARCH64_CORE_REG(regs.pc), &env->pc); ++ if (ret) { ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int kvm_arm_put_core_regs(CPUState *cs, int level) + { + uint64_t val; +@@ -848,6 +876,10 @@ static int kvm_arm_put_core_regs(CPUState *cs, int level) + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + ++ if (cpu->kvm_rme) { ++ return kvm_arm_rme_put_core_regs(cs); ++ } ++ + /* If we are in AArch32 mode then we need to copy the AArch32 regs to the + * AArch64 registers before pushing them out to 64-bit KVM. + */ +@@ -1037,6 +1069,23 @@ static int kvm_arch_get_sve(CPUState *cs) + return 0; + } + ++static int kvm_arm_rme_get_core_regs(CPUState *cs) ++{ ++ int i, ret; ++ ARMCPU *cpu = ARM_CPU(cs); ++ CPUARMState *env = &cpu->env; ++ ++ for (i = 0; i < 8; i++) { ++ ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]), ++ &env->xregs[i]); ++ if (ret) { ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static int kvm_arm_get_core_regs(CPUState *cs) + { + uint64_t val; +@@ -1047,6 +1096,10 @@ static int kvm_arm_get_core_regs(CPUState *cs) + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + ++ if (cpu->kvm_rme) { ++ return kvm_arm_rme_get_core_regs(cs); ++ } ++ + for (i = 0; i < 31; i++) { + ret = kvm_get_one_reg(cs, AARCH64_CORE_REG(regs.regs[i]), + &env->xregs[i]); +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index f17de8855a..b6a07eb80f 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -418,6 +418,16 @@ int kvm_arm_rme_init(MachineState *ms); + */ + int kvm_arm_rme_vm_type(MachineState *ms); + ++/** ++ * kvm_arm_rme_vcpu_init ++ * @cs: the CPU ++ * ++ * If the user requested a Realm, setup the given vCPU accordingly. Realm vCPUs ++ * behave a little differently, for example most of their register state is ++ * hidden from the host. ++ */ ++int kvm_arm_rme_vcpu_init(CPUState *cs); ++ + #else + + /* +@@ -537,6 +547,12 @@ static inline int kvm_arm_rme_vm_type(MachineState *ms) + { + g_assert_not_reached(); + } ++ ++static inline int kvm_arm_rme_vcpu_init(CPUState *cs) ++{ ++ g_assert_not_reached(); ++} ++ + #endif + + /** +-- +2.33.0 + diff --git a/vfio-Add-the-support-for-PrivateSharedManager-Interf.patch b/vfio-Add-the-support-for-PrivateSharedManager-Interf.patch new file mode 100644 index 00000000..5721d362 --- /dev/null +++ b/vfio-Add-the-support-for-PrivateSharedManager-Interf.patch @@ -0,0 +1,254 @@ +From 2cf51bbf91b9409b411e0904cd3a2f4875646fec Mon Sep 17 00:00:00 2001 +From: Chenyi Qiang +Date: Mon, 7 Apr 2025 15:49:26 +0800 +Subject: [PATCH] vfio: Add the support for PrivateSharedManager Interface + +Reference:https://git.codelinaro.org/linaro/dcap/qemu/-/commit/f301a300d981459e74387ee10de01e8589d35451 + +Subsystems like VFIO previously disabled ram block discard and only +allowed coordinated discarding via RamDiscardManager. However, +guest_memfd in confidential VMs relies on discard operations for page +conversion between private and shared memory. This can lead to stale +IOMMU mapping issue when assigning a hardware device to a confidential +VM via shared memory. With the introduction of PrivateSharedManager +interface to manage private and shared states and being distinct from +RamDiscardManager, include PrivateSharedManager in coordinated RAM +discard and add related support in VFIO. + +Currently, migration support for confidential VMs is not available, so +vfio_sync_dirty_bitmap() handling for PrivateSharedListener can be +ignored. The register/unregister of PrivateSharedListener is necessary +during vfio_listener_region_add/del(). The listener callbacks are +similar between RamDiscardListener and PrivateSharedListener, allowing +for extraction of common parts opportunisticlly. + +Signed-off-by: Chenyi Qiang +Conflicts: + hw/vfio/container-base.c +Signed-off-by: frankyj915 +Signed-off-by: houmingyong +--- + hw/vfio/common.c | 104 +++++++++++++++++++++++--- + hw/vfio/container-base.c | 1 + + include/hw/vfio/vfio-container-base.h | 10 +++ + 3 files changed, 105 insertions(+), 10 deletions(-) + +diff --git a/hw/vfio/common.c b/hw/vfio/common.c +index ab7450f3bd..62a2000acd 100644 +--- a/hw/vfio/common.c ++++ b/hw/vfio/common.c +@@ -350,13 +350,9 @@ out: + rcu_read_unlock(); + } + +-static void vfio_ram_discard_notify_discard(StateChangeListener *scl, +- MemoryRegionSection *section) ++static void vfio_state_change_notify_to_state_clear(VFIOContainerBase *bcontainer, ++ MemoryRegionSection *section) + { +- RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); +- VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, +- listener); +- VFIOContainerBase *bcontainer = vrdl->bcontainer; + const hwaddr size = int128_get64(section->size); + const hwaddr iova = section->offset_within_address_space; + int ret; +@@ -369,13 +365,28 @@ static void vfio_ram_discard_notify_discard(StateChangeListener *scl, + } + } + +-static int vfio_ram_discard_notify_populate(StateChangeListener *scl, ++static void vfio_ram_discard_notify_discard(StateChangeListener *scl, + MemoryRegionSection *section) + { + RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); + VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, + listener); +- VFIOContainerBase *bcontainer = vrdl->bcontainer; ++ vfio_state_change_notify_to_state_clear(vrdl->bcontainer, section); ++} ++ ++static void vfio_private_shared_notify_to_private(StateChangeListener *scl, ++ MemoryRegionSection *section) ++{ ++ PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); ++ VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, ++ listener); ++ vfio_state_change_notify_to_state_clear(vpsl->bcontainer, section); ++} ++ ++static int vfio_state_change_notify_to_state_set(VFIOContainerBase *bcontainer, ++ MemoryRegionSection *section, ++ uint64_t granularity) ++{ + const hwaddr end = section->offset_within_region + + int128_get64(section->size); + hwaddr start, next, iova; +@@ -387,7 +398,7 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, + * unmap in minimum granularity later. + */ + for (start = section->offset_within_region; start < end; start = next) { +- next = ROUND_UP(start + 1, vrdl->granularity); ++ next = ROUND_UP(start + 1, granularity); + next = MIN(next, end); + + iova = start - section->offset_within_region + +@@ -398,13 +409,33 @@ static int vfio_ram_discard_notify_populate(StateChangeListener *scl, + vaddr, section->readonly); + if (ret) { + /* Rollback */ +- vfio_ram_discard_notify_discard(scl, section); ++ vfio_state_change_notify_to_state_clear(bcontainer, section); + return ret; + } + } + return 0; + } + ++static int vfio_ram_discard_notify_populate(StateChangeListener *scl, ++ MemoryRegionSection *section) ++{ ++ RamDiscardListener *rdl = container_of(scl, RamDiscardListener, scl); ++ VFIORamDiscardListener *vrdl = container_of(rdl, VFIORamDiscardListener, ++ listener); ++ return vfio_state_change_notify_to_state_set(vrdl->bcontainer, section, ++ vrdl->granularity); ++} ++ ++static int vfio_private_shared_notify_to_shared(StateChangeListener *scl, ++ MemoryRegionSection *section) ++{ ++ PrivateSharedListener *psl = container_of(scl, PrivateSharedListener, scl); ++ VFIOPrivateSharedListener *vpsl = container_of(psl, VFIOPrivateSharedListener, ++ listener); ++ return vfio_state_change_notify_to_state_set(vpsl->bcontainer, section, ++ vpsl->granularity); ++} ++ + static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) + { +@@ -481,6 +512,27 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, + } + } + ++static void vfio_register_private_shared_listener(VFIOContainerBase *bcontainer, ++ MemoryRegionSection *section) ++{ ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); ++ VFIOPrivateSharedListener *vpsl; ++ PrivateSharedListener *psl; ++ ++ vpsl = g_new0(VFIOPrivateSharedListener, 1); ++ vpsl->bcontainer = bcontainer; ++ vpsl->mr = section->mr; ++ vpsl->offset_within_address_space = section->offset_within_address_space; ++ vpsl->granularity = generic_state_manager_get_min_granularity(gsm, ++ section->mr); ++ ++ psl = &vpsl->listener; ++ private_shared_listener_init(psl, vfio_private_shared_notify_to_shared, ++ vfio_private_shared_notify_to_private); ++ generic_state_manager_register_listener(gsm, &psl->scl, section); ++ QLIST_INSERT_HEAD(&bcontainer->vpsl_list, vpsl, next); ++} ++ + static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, + MemoryRegionSection *section) + { +@@ -506,6 +558,31 @@ static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, + g_free(vrdl); + } + ++static void vfio_unregister_private_shared_listener(VFIOContainerBase *bcontainer, ++ MemoryRegionSection *section) ++{ ++ GenericStateManager *gsm = memory_region_get_generic_state_manager(section->mr); ++ VFIOPrivateSharedListener *vpsl = NULL; ++ PrivateSharedListener *psl; ++ ++ QLIST_FOREACH(vpsl, &bcontainer->vpsl_list, next) { ++ if (vpsl->mr == section->mr && ++ vpsl->offset_within_address_space == ++ section->offset_within_address_space) { ++ break; ++ } ++ } ++ ++ if (!vpsl) { ++ hw_error("vfio: Trying to unregister missing RAM discard listener"); ++ } ++ ++ psl = &vpsl->listener; ++ generic_state_manager_unregister_listener(gsm, &psl->scl); ++ QLIST_REMOVE(vpsl, next); ++ g_free(vpsl); ++} ++ + static bool vfio_known_safe_misalignment(MemoryRegionSection *section) + { + MemoryRegion *mr = section->mr; +@@ -677,6 +754,9 @@ static void vfio_listener_region_add(MemoryListener *listener, + if (memory_region_has_ram_discard_manager(section->mr)) { + vfio_register_ram_discard_listener(bcontainer, section); + return; ++ } else if (memory_region_has_private_shared_manager(section->mr)) { ++ vfio_register_private_shared_listener(bcontainer, section); ++ return; + } + + vaddr = memory_region_get_ram_ptr(section->mr) + +@@ -796,6 +876,10 @@ static void vfio_listener_region_del(MemoryListener *listener, + vfio_unregister_ram_discard_listener(bcontainer, section); + /* Unregistering will trigger an unmap. */ + try_unmap = false; ++ } else if (memory_region_has_private_shared_manager(section->mr)) { ++ vfio_unregister_private_shared_listener(bcontainer, section); ++ /* Unregistering will trigger an unmap. */ ++ try_unmap = false; + } + + if (try_unmap) { +diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c +index 913ae49077..a356ae91a9 100644 +--- a/hw/vfio/container-base.c ++++ b/hw/vfio/container-base.c +@@ -82,6 +82,7 @@ void vfio_container_init(VFIOContainerBase *bcontainer, VFIOAddressSpace *space, + bcontainer->iova_ranges = NULL; + QLIST_INIT(&bcontainer->giommu_list); + QLIST_INIT(&bcontainer->vrdl_list); ++ QLIST_INIT(&bcontainer->vpsl_list); + } + + void vfio_container_destroy(VFIOContainerBase *bcontainer) +diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h +index 7a4c575115..faed33bf92 100644 +--- a/include/hw/vfio/vfio-container-base.h ++++ b/include/hw/vfio/vfio-container-base.h +@@ -46,6 +46,7 @@ typedef struct VFIOContainerBase { + bool dirty_pages_supported; + QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; + QLIST_HEAD(, VFIORamDiscardListener) vrdl_list; ++ QLIST_HEAD(, VFIOPrivateSharedListener) vpsl_list; + QLIST_ENTRY(VFIOContainerBase) next; + QLIST_HEAD(, VFIODevice) device_list; + GList *iova_ranges; +@@ -69,6 +70,15 @@ typedef struct VFIORamDiscardListener { + QLIST_ENTRY(VFIORamDiscardListener) next; + } VFIORamDiscardListener; + ++typedef struct VFIOPrivateSharedListener { ++ VFIOContainerBase *bcontainer; ++ MemoryRegion *mr; ++ hwaddr offset_within_address_space; ++ uint64_t granularity; ++ PrivateSharedListener listener; ++ QLIST_ENTRY(VFIOPrivateSharedListener) next; ++} VFIOPrivateSharedListener; ++ + int vfio_container_dma_map(VFIOContainerBase *bcontainer, + hwaddr iova, ram_addr_t size, + void *vaddr, bool readonly); +-- +2.33.0 + diff --git a/virtio-net-Fix-num_buffers-for-version-1.patch b/virtio-net-Fix-num_buffers-for-version-1.patch new file mode 100644 index 00000000..764af99b --- /dev/null +++ b/virtio-net-Fix-num_buffers-for-version-1.patch @@ -0,0 +1,41 @@ +From a9f926fc672b06739f6feed770187d705d7d3e6c Mon Sep 17 00:00:00 2001 +From: lijunwei +Date: Tue, 1 Jul 2025 17:55:18 +0800 +Subject: [PATCH] virtio-net: Fix num_buffers for version 1 + +The specification says the device MUST set num_buffers to 1 if +VIRTIO_NET_F_MRG_RXBUF has not been negotiated. + +Fixes: df91055db5c9 ("virtio-net: enable virtio 1.0") +Signed-off-by: Akihiko Odaki +Message-Id: <20250108-buffers-v1-1-a0c85ff31aeb@daynix.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit c17ad4b11bd268a35506cd976884562df6ca69d7) +(Mjt: adjust for 8.2.x) +Signed-off-by: Michael Tokarev +--- + hw/net/virtio-net.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 7184c9c526..25044385dc 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1996,7 +1996,9 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + sg, elem->in_num, + offsetof(typeof(mhdr), num_buffers), + sizeof(mhdr.num_buffers)); +- } ++ }else { ++ mhdr.num_buffers = cpu_to_le16(1); ++ } + + receive_header(n, sg, elem->in_num, buf, size); + if (n->rss_data.populate_hash) { +-- +2.33.0 + -- Gitee From e0fbd25fb4bfaff6b47209c00bdb75c3c66d4edc Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Tue, 26 Aug 2025 18:56:52 +0800 Subject: [PATCH 04/14] QEMU update to version 8.2.0-40: Signed-off-by: zhangpengrui --- ...-set-vms-bootinfo.confidential-in-vi.patch | 33 ++++ ...-build.c-Migrate-fw_cfg-creation-to-.patch | 180 ++++++++++++++++++ ...-build.c-Migrate-virtio-creation-to-.patch | 158 +++++++++++++++ ...rovm.c-Use-common-function-to-add-vi.patch | 57 ++++++ ...ex-Define-properties-for-MMIO-ranges.patch | 128 +++++++++++++ ...ke-few-IMSIC-macros-and-functions-pu.patch | 117 ++++++++++++ ...-Update-GPEX-MMIO-related-properties.patch | 117 ++++++++++++ ...cpi-build.c-Add-AIA-support-in-RINTC.patch | 114 +++++++++++ ...t-acpi-build.c-Add-APLIC-in-the-MADT.patch | 76 ++++++++ ...pi-build.c-Add-CMO-information-in-RH.patch | 131 +++++++++++++ ...t-acpi-build.c-Add-IMSIC-in-the-MADT.patch | 76 ++++++++ ...pi-build.c-Add-IO-controllers-and-de.patch | 160 ++++++++++++++++ ...rt-acpi-build.c-Add-MMU-node-in-RHCT.patch | 102 ++++++++++ ...v-virt-acpi-build.c-Add-PLIC-in-MADT.patch | 72 +++++++ ...pi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch | 112 +++++++++++ ...pi-build.c-Add-namespace-devices-for.patch | 78 ++++++++ ...irt-acpi-build.c-Generate-SPCR-table.patch | 78 ++++++++ ...pi-build.c-Update-the-HID-of-RISC-V-.patch | 41 ++++ ...fix-the-interrupts-extended-property.patch | 92 +++++++++ ...ix-deadlock-when-resetting-uninstall.patch | 39 ++++ qemu.spec | 49 ++++- ...uffer-overrun-when-using-path-option.patch | 42 ++++ ...Refine-VMX-controls-setting-for-back.patch | 68 +++++++ 23 files changed, 2119 insertions(+), 1 deletion(-) create mode 100644 Bugfix-Correctly-set-vms-bootinfo.confidential-in-vi.patch create mode 100644 hw-arm-virt-acpi-build.c-Migrate-fw_cfg-creation-to-.patch create mode 100644 hw-arm-virt-acpi-build.c-Migrate-virtio-creation-to-.patch create mode 100644 hw-i386-acpi-microvm.c-Use-common-function-to-add-vi.patch create mode 100644 hw-pci-host-gpex-Define-properties-for-MMIO-ranges.patch create mode 100644 hw-riscv-virt-Make-few-IMSIC-macros-and-functions-pu.patch create mode 100644 hw-riscv-virt-Update-GPEX-MMIO-related-properties.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-AIA-support-in-RINTC.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-APLIC-in-the-MADT.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-CMO-information-in-RH.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-IMSIC-in-the-MADT.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-IO-controllers-and-de.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-MMU-node-in-RHCT.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-PLIC-in-MADT.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch create mode 100644 hw-riscv-virt-acpi-build.c-Add-namespace-devices-for.patch create mode 100644 hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch create mode 100644 hw-riscv-virt-acpi-build.c-Update-the-HID-of-RISC-V-.patch create mode 100644 hw-riscv-virt.c-fix-the-interrupts-extended-property.patch create mode 100644 plugins-loader-fix-deadlock-when-resetting-uninstall.patch create mode 100644 smbios-Fix-buffer-overrun-when-using-path-option.patch create mode 100644 target-i386-kvm-Refine-VMX-controls-setting-for-back.patch diff --git a/Bugfix-Correctly-set-vms-bootinfo.confidential-in-vi.patch b/Bugfix-Correctly-set-vms-bootinfo.confidential-in-vi.patch new file mode 100644 index 00000000..8a2af28e --- /dev/null +++ b/Bugfix-Correctly-set-vms-bootinfo.confidential-in-vi.patch @@ -0,0 +1,33 @@ +From 07e397a40e7f33ca980b29ba6c8b6de0c7419991 Mon Sep 17 00:00:00 2001 +From: yxk +Date: Wed, 20 Aug 2025 03:22:03 +0800 +Subject: [PATCH] Bugfix: Correctly set vms->bootinfo.confidential in virtCCA + senarios. + +Both CCA and virtCCA senarios can set vms->bootinfo.confidential in +hw/arm/virt.c. + +Signed-off-by: yxk +--- + hw/arm/virt.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index f12bc645d2..cf4156ed49 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -2930,9 +2930,9 @@ static void machvirt_init(MachineState *machine) + vms->bootinfo.firmware_loaded = firmware_loaded; + vms->bootinfo.firmware_base = vms->memmap[VIRT_FLASH].base; + vms->bootinfo.firmware_max_size = vms->memmap[VIRT_FLASH].size; +- vms->bootinfo.confidential = virtcca_cvm_enabled(); + vms->bootinfo.psci_conduit = vms->psci_conduit; +- vms->bootinfo.confidential = virt_machine_is_confidential(vms); ++ vms->bootinfo.confidential = virt_machine_is_confidential(vms) || ++ virtcca_cvm_enabled(); + vms->bootinfo.skip_bootloader = vms->bootinfo.confidential; + arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo); + +-- +2.33.0 + diff --git a/hw-arm-virt-acpi-build.c-Migrate-fw_cfg-creation-to-.patch b/hw-arm-virt-acpi-build.c-Migrate-fw_cfg-creation-to-.patch new file mode 100644 index 00000000..10b2a1da --- /dev/null +++ b/hw-arm-virt-acpi-build.c-Migrate-fw_cfg-creation-to-.patch @@ -0,0 +1,180 @@ +From 948c605badb09d87eb439a711940d932d07cdd1e Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:24 +0800 +Subject: [PATCH 01/18] hw/arm/virt-acpi-build.c: Migrate fw_cfg creation to + common location + +commit 4c7f4f4f0516ad1bad45b011235202f5be6899de upstream + +RISC-V also needs to use the same code to create fw_cfg in DSDT. So, +avoid code duplication by moving the code in arm and riscv to a device +specific file. + +Suggested-by: Igor Mammedov +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Alistair Francis +Reviewed-by: Andrew Jones +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-2-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/arm/virt-acpi-build.c | 19 ++----------------- + hw/nvram/fw_cfg-acpi.c | 23 +++++++++++++++++++++++ + hw/nvram/meson.build | 1 + + hw/riscv/virt-acpi-build.c | 19 ++----------------- + include/hw/nvram/fw_cfg_acpi.h | 15 +++++++++++++++ + 5 files changed, 43 insertions(+), 34 deletions(-) + create mode 100644 hw/nvram/fw_cfg-acpi.c + create mode 100644 include/hw/nvram/fw_cfg_acpi.h + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 5e949671a1..81ca26c052 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -35,7 +35,7 @@ + #include "target/arm/cpu.h" + #include "hw/acpi/acpi-defs.h" + #include "hw/acpi/acpi.h" +-#include "hw/nvram/fw_cfg.h" ++#include "hw/nvram/fw_cfg_acpi.h" + #include "hw/acpi/bios-linker-loader.h" + #include "hw/acpi/aml-build.h" + #include "hw/acpi/utils.h" +@@ -341,21 +341,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + aml_append(scope, dev); + } + +-static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) +-{ +- Aml *dev = aml_device("FWCF"); +- aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); +- /* device present, functioning, decoding, not shown in UI */ +- aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); +- aml_append(dev, aml_name_decl("_CCA", aml_int(1))); +- +- Aml *crs = aml_resource_template(); +- aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, +- fw_cfg_memmap->size, AML_READ_WRITE)); +- aml_append(dev, aml_name_decl("_CRS", crs)); +- aml_append(scope, dev); +-} +- + static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) + { + Aml *dev, *crs; +@@ -1318,7 +1303,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + if (vmc->acpi_expose_flash) { + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + } +- acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); ++ fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); + acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], + (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); + acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); +diff --git a/hw/nvram/fw_cfg-acpi.c b/hw/nvram/fw_cfg-acpi.c +new file mode 100644 +index 0000000000..4e48baeaa0 +--- /dev/null ++++ b/hw/nvram/fw_cfg-acpi.c +@@ -0,0 +1,23 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Add fw_cfg device in DSDT ++ * ++ */ ++ ++#include "hw/nvram/fw_cfg_acpi.h" ++#include "hw/acpi/aml-build.h" ++ ++void fw_cfg_acpi_dsdt_add(Aml *scope, const MemMapEntry *fw_cfg_memmap) ++{ ++ Aml *dev = aml_device("FWCF"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); ++ /* device present, functioning, decoding, not shown in UI */ ++ aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); ++ aml_append(dev, aml_name_decl("_CCA", aml_int(1))); ++ ++ Aml *crs = aml_resource_template(); ++ aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, ++ fw_cfg_memmap->size, AML_READ_WRITE)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++} +diff --git a/hw/nvram/meson.build b/hw/nvram/meson.build +index 75e415b1a0..4996c72456 100644 +--- a/hw/nvram/meson.build ++++ b/hw/nvram/meson.build +@@ -17,3 +17,4 @@ system_ss.add(when: 'CONFIG_XLNX_EFUSE_ZYNQMP', if_true: files( + system_ss.add(when: 'CONFIG_XLNX_BBRAM', if_true: files('xlnx-bbram.c')) + + specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_nvram.c')) ++specific_ss.add(when: 'CONFIG_ACPI', if_true: files('fw_cfg-acpi.c')) +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 7331248f59..d8772c2821 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -28,6 +28,7 @@ + #include "hw/acpi/acpi.h" + #include "hw/acpi/aml-build.h" + #include "hw/acpi/utils.h" ++#include "hw/nvram/fw_cfg_acpi.h" + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "sysemu/reset.h" +@@ -97,22 +98,6 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) + } + } + +-static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) +-{ +- Aml *dev = aml_device("FWCF"); +- aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); +- +- /* device present, functioning, decoding, not shown in UI */ +- aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); +- aml_append(dev, aml_name_decl("_CCA", aml_int(1))); +- +- Aml *crs = aml_resource_template(); +- aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, +- fw_cfg_memmap->size, AML_READ_WRITE)); +- aml_append(dev, aml_name_decl("_CRS", crs)); +- aml_append(scope, dev); +-} +- + /* RHCT Node[N] starts at offset 56 */ + #define RHCT_NODE_ARRAY_OFFSET 56 + +@@ -226,7 +211,7 @@ static void build_dsdt(GArray *table_data, + scope = aml_scope("\\_SB"); + acpi_dsdt_add_cpus(scope, s); + +- acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); ++ fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); + + aml_append(dsdt, scope); + +diff --git a/include/hw/nvram/fw_cfg_acpi.h b/include/hw/nvram/fw_cfg_acpi.h +new file mode 100644 +index 0000000000..b6553d86fc +--- /dev/null ++++ b/include/hw/nvram/fw_cfg_acpi.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * ACPI support for fw_cfg ++ * ++ */ ++ ++#ifndef FW_CFG_ACPI_H ++#define FW_CFG_ACPI_H ++ ++#include "qemu/osdep.h" ++#include "exec/hwaddr.h" ++ ++void fw_cfg_acpi_dsdt_add(Aml *scope, const MemMapEntry *fw_cfg_memmap); ++ ++#endif +-- +2.33.0 + diff --git a/hw-arm-virt-acpi-build.c-Migrate-virtio-creation-to-.patch b/hw-arm-virt-acpi-build.c-Migrate-virtio-creation-to-.patch new file mode 100644 index 00000000..da6031d8 --- /dev/null +++ b/hw-arm-virt-acpi-build.c-Migrate-virtio-creation-to-.patch @@ -0,0 +1,158 @@ +From 4339104293871dba77a50502357ed96962edae2c Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:25 +0800 +Subject: [PATCH 02/18] hw/arm/virt-acpi-build.c: Migrate virtio creation to + common location + +commit 57ba8436282940b59d9a069cc01a601bbc8036c5 upstream + +RISC-V also needs to create the virtio in DSDT in the same way as ARM. +So, instead of duplicating the code, move this function to the device +specific file which is common across architectures. + +Suggested-by: Igor Mammedov +Signed-off-by: Sunil V L +Reviewed-by: Alistair Francis +Reviewed-by: Andrew Jones +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-3-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/arm/virt-acpi-build.c | 32 ++++---------------------------- + hw/virtio/meson.build | 1 + + hw/virtio/virtio-acpi.c | 33 +++++++++++++++++++++++++++++++++ + include/hw/virtio/virtio-acpi.h | 16 ++++++++++++++++ + 4 files changed, 54 insertions(+), 28 deletions(-) + create mode 100644 hw/virtio/virtio-acpi.c + create mode 100644 include/hw/virtio/virtio-acpi.h + +diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c +index 81ca26c052..b389ef7622 100644 +--- a/hw/arm/virt-acpi-build.c ++++ b/hw/arm/virt-acpi-build.c +@@ -59,6 +59,7 @@ + #include "hw/acpi/ghes.h" + #include "hw/acpi/viot.h" + #include "kvm_arm.h" ++#include "hw/virtio/virtio-acpi.h" + + #define ARM_SPI_BASE 32 + +@@ -365,32 +366,6 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) + aml_append(scope, dev); + } + +-static void acpi_dsdt_add_virtio(Aml *scope, +- const MemMapEntry *virtio_mmio_memmap, +- uint32_t mmio_irq, int num) +-{ +- hwaddr base = virtio_mmio_memmap->base; +- hwaddr size = virtio_mmio_memmap->size; +- int i; +- +- for (i = 0; i < num; i++) { +- uint32_t irq = mmio_irq + i; +- Aml *dev = aml_device("VR%02u", i); +- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); +- aml_append(dev, aml_name_decl("_UID", aml_int(i))); +- aml_append(dev, aml_name_decl("_CCA", aml_int(1))); +- +- Aml *crs = aml_resource_template(); +- aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); +- aml_append(crs, +- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, +- AML_EXCLUSIVE, &irq, 1)); +- aml_append(dev, aml_name_decl("_CRS", crs)); +- aml_append(scope, dev); +- base += size; +- } +-} +- + static void acpi_dsdt_add_hisi_sec(Aml *scope, + const MemMapEntry *virtio_mmio_memmap, + int dev_id) +@@ -1304,8 +1279,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + } + fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); +- acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], +- (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); ++ virtio_acpi_dsdt_add(scope, memmap[VIRT_MMIO].base, memmap[VIRT_MMIO].size, ++ (irqmap[VIRT_MMIO] + ARM_SPI_BASE), ++ 0, NUM_VIRTIO_TRANSPORTS); + acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); + + if (virtcca_cvm_enabled()) { +diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build +index 67291563d3..7f29622099 100644 +--- a/hw/virtio/meson.build ++++ b/hw/virtio/meson.build +@@ -79,3 +79,4 @@ system_ss.add(when: 'CONFIG_ALL', if_true: files('virtio-stub.c')) + system_ss.add(files('virtio-hmp-cmds.c')) + + specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: specific_virtio_ss) ++system_ss.add(when: 'CONFIG_ACPI', if_true: files('virtio-acpi.c')) +diff --git a/hw/virtio/virtio-acpi.c b/hw/virtio/virtio-acpi.c +new file mode 100644 +index 0000000000..e18cb38bdb +--- /dev/null ++++ b/hw/virtio/virtio-acpi.c +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * virtio ACPI Support ++ * ++ */ ++ ++#include "hw/virtio/virtio-acpi.h" ++#include "hw/acpi/aml-build.h" ++ ++void virtio_acpi_dsdt_add(Aml *scope, const hwaddr base, const hwaddr size, ++ uint32_t mmio_irq, long int start_index, int num) ++{ ++ hwaddr virtio_base = base; ++ uint32_t irq = mmio_irq; ++ long int i; ++ ++ for (i = start_index; i < start_index + num; i++) { ++ Aml *dev = aml_device("VR%02u", (unsigned)i); ++ aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(i))); ++ aml_append(dev, aml_name_decl("_CCA", aml_int(1))); ++ ++ Aml *crs = aml_resource_template(); ++ aml_append(crs, aml_memory32_fixed(virtio_base, size, AML_READ_WRITE)); ++ aml_append(crs, ++ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, ++ AML_EXCLUSIVE, &irq, 1)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++ virtio_base += size; ++ irq++; ++ } ++} +diff --git a/include/hw/virtio/virtio-acpi.h b/include/hw/virtio/virtio-acpi.h +new file mode 100644 +index 0000000000..844e102569 +--- /dev/null ++++ b/include/hw/virtio/virtio-acpi.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * ACPI support for virtio ++ */ ++ ++#ifndef VIRTIO_ACPI_H ++#define VIRTIO_ACPI_H ++ ++#include "qemu/osdep.h" ++#include "exec/hwaddr.h" ++ ++void virtio_acpi_dsdt_add(Aml *scope, const hwaddr virtio_mmio_base, ++ const hwaddr virtio_mmio_size, uint32_t mmio_irq, ++ long int start_index, int num); ++ ++#endif +-- +2.33.0 + diff --git a/hw-i386-acpi-microvm.c-Use-common-function-to-add-vi.patch b/hw-i386-acpi-microvm.c-Use-common-function-to-add-vi.patch new file mode 100644 index 00000000..ea0ba795 --- /dev/null +++ b/hw-i386-acpi-microvm.c-Use-common-function-to-add-vi.patch @@ -0,0 +1,57 @@ +From be7b030b8ae20a284aee2ab41f49337db3ebe48d Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:26 +0800 +Subject: [PATCH 03/18] hw/i386/acpi-microvm.c: Use common function to add + virtio in DSDT + +commit 8199bf48ea1fdb8e491311a0dc28cea30af18c95 uptream + +With common function to add virtio in DSDT created now, update microvm +code also to use it instead of duplicate code. + +Suggested-by: Andrew Jones +Signed-off-by: Sunil V L +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-4-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/i386/acpi-microvm.c | 15 ++------------- + 1 file changed, 2 insertions(+), 13 deletions(-) + +diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c +index 2909a73933..279da6b4aa 100644 +--- a/hw/i386/acpi-microvm.c ++++ b/hw/i386/acpi-microvm.c +@@ -37,6 +37,7 @@ + #include "hw/pci/pci.h" + #include "hw/pci/pcie_host.h" + #include "hw/usb/xhci.h" ++#include "hw/virtio/virtio-acpi.h" + #include "hw/virtio/virtio-mmio.h" + #include "hw/input/i8042.h" + +@@ -77,19 +78,7 @@ static void acpi_dsdt_add_virtio(Aml *scope, + uint32_t irq = mms->virtio_irq_base + index; + hwaddr base = VIRTIO_MMIO_BASE + index * 512; + hwaddr size = 512; +- +- Aml *dev = aml_device("VR%02u", (unsigned)index); +- aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); +- aml_append(dev, aml_name_decl("_UID", aml_int(index))); +- aml_append(dev, aml_name_decl("_CCA", aml_int(1))); +- +- Aml *crs = aml_resource_template(); +- aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); +- aml_append(crs, +- aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, +- AML_EXCLUSIVE, &irq, 1)); +- aml_append(dev, aml_name_decl("_CRS", crs)); +- aml_append(scope, dev); ++ virtio_acpi_dsdt_add(scope, base, size, irq, index, 1); + } + } + } +-- +2.33.0 + diff --git a/hw-pci-host-gpex-Define-properties-for-MMIO-ranges.patch b/hw-pci-host-gpex-Define-properties-for-MMIO-ranges.patch new file mode 100644 index 00000000..787bd0e5 --- /dev/null +++ b/hw-pci-host-gpex-Define-properties-for-MMIO-ranges.patch @@ -0,0 +1,128 @@ +From 7ec434a0f9935a7a6a14896140f33c7e1436111e Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:34 +0800 +Subject: [PATCH 10/18] hw/pci-host/gpex: Define properties for MMIO ranges + +commit 8f6a4874887c226b0df35f5b78fa77f197507d96 upstream + +ACPI DSDT generator needs information like ECAM range, PIO range, 32-bit +and 64-bit PCI MMIO range etc related to the PCI host bridge. Instead of +making these values machine specific, create properties for the GPEX +host bridge with default value 0. During initialization, the firmware +can initialize these properties with correct values for the platform. +This basically allows DSDT generator code independent of the machine +specific memory map accesses. + +Suggested-by: Igor Mammedov +Signed-off-by: Sunil V L +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Reviewed-by: Daniel Henrique Barboza +Message-ID: <20231218150247.466427-11-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/pci-host/gpex-acpi.c | 13 +++++++++++++ + hw/pci-host/gpex.c | 12 ++++++++++++ + include/hw/pci-host/gpex.h | 30 +++++++++++++++++++++--------- + 3 files changed, 46 insertions(+), 9 deletions(-) + +diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c +index 162f6221ab..020ded0ff6 100644 +--- a/hw/pci-host/gpex-acpi.c ++++ b/hw/pci-host/gpex-acpi.c +@@ -296,3 +296,16 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) + + crs_range_set_free(&crs_range_set); + } ++ ++void acpi_dsdt_add_gpex_host(Aml *scope, uint32_t irq) ++{ ++ bool ambig; ++ Object *obj = object_resolve_path_type("", TYPE_GPEX_HOST, &ambig); ++ ++ if (!obj || ambig) { ++ return; ++ } ++ ++ GPEX_HOST(obj)->gpex_cfg.irq = irq; ++ acpi_dsdt_add_gpex(scope, &GPEX_HOST(obj)->gpex_cfg); ++} +diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c +index a6752fac5e..41f4e73f6e 100644 +--- a/hw/pci-host/gpex.c ++++ b/hw/pci-host/gpex.c +@@ -154,6 +154,18 @@ static Property gpex_host_properties[] = { + */ + DEFINE_PROP_BOOL("allow-unmapped-accesses", GPEXHost, + allow_unmapped_accesses, true), ++ DEFINE_PROP_UINT64(PCI_HOST_ECAM_BASE, GPEXHost, gpex_cfg.ecam.base, 0), ++ DEFINE_PROP_SIZE(PCI_HOST_ECAM_SIZE, GPEXHost, gpex_cfg.ecam.size, 0), ++ DEFINE_PROP_UINT64(PCI_HOST_PIO_BASE, GPEXHost, gpex_cfg.pio.base, 0), ++ DEFINE_PROP_SIZE(PCI_HOST_PIO_SIZE, GPEXHost, gpex_cfg.pio.size, 0), ++ DEFINE_PROP_UINT64(PCI_HOST_BELOW_4G_MMIO_BASE, GPEXHost, ++ gpex_cfg.mmio32.base, 0), ++ DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MMIO_SIZE, GPEXHost, ++ gpex_cfg.mmio32.size, 0), ++ DEFINE_PROP_UINT64(PCI_HOST_ABOVE_4G_MMIO_BASE, GPEXHost, ++ gpex_cfg.mmio64.base, 0), ++ DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost, ++ gpex_cfg.mmio64.size, 0), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h +index 65475f7f9d..c414ae5190 100644 +--- a/include/hw/pci-host/gpex.h ++++ b/include/hw/pci-host/gpex.h +@@ -40,6 +40,16 @@ struct GPEXRootState { + /*< public >*/ + }; + ++struct GPEXConfig { ++ MemMapEntry ecam; ++ MemMapEntry mmio32; ++ MemMapEntry mmio64; ++ MemMapEntry pio; ++ int irq; ++ PCIBus *bus; ++ bool preserve_config; ++}; ++ + struct GPEXHost { + /*< private >*/ + PCIExpressHost parent_obj; +@@ -55,20 +65,22 @@ struct GPEXHost { + int irq_num[GPEX_NUM_IRQS]; + + bool allow_unmapped_accesses; +-}; + +-struct GPEXConfig { +- MemMapEntry ecam; +- MemMapEntry mmio32; +- MemMapEntry mmio64; +- MemMapEntry pio; +- int irq; +- PCIBus *bus; +- bool preserve_config; ++ struct GPEXConfig gpex_cfg; + }; + + int gpex_set_irq_num(GPEXHost *s, int index, int gsi); + + void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg); ++void acpi_dsdt_add_gpex_host(Aml *scope, uint32_t irq); ++ ++#define PCI_HOST_PIO_BASE "x-pio-base" ++#define PCI_HOST_PIO_SIZE "x-pio-size" ++#define PCI_HOST_ECAM_BASE "x-ecam-base" ++#define PCI_HOST_ECAM_SIZE "x-ecam-size" ++#define PCI_HOST_BELOW_4G_MMIO_BASE "x-below-4g-mmio-base" ++#define PCI_HOST_BELOW_4G_MMIO_SIZE "x-below-4g-mmio-size" ++#define PCI_HOST_ABOVE_4G_MMIO_BASE "x-above-4g-mmio-base" ++#define PCI_HOST_ABOVE_4G_MMIO_SIZE "x-above-4g-mmio-size" + + #endif /* HW_GPEX_H */ +-- +2.33.0 + diff --git a/hw-riscv-virt-Make-few-IMSIC-macros-and-functions-pu.patch b/hw-riscv-virt-Make-few-IMSIC-macros-and-functions-pu.patch new file mode 100644 index 00000000..d8940846 --- /dev/null +++ b/hw-riscv-virt-Make-few-IMSIC-macros-and-functions-pu.patch @@ -0,0 +1,117 @@ +From 2ce3c25215a931f183ad530baba7a07ddd55cfe6 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:27 +0800 +Subject: [PATCH 04/18] hw/riscv: virt: Make few IMSIC macros and functions + public + +commit 68c8b403c78b8f20acbebba3cdc46320853fe5ca upstream + +Some macros and static function related to IMSIC are defined in virt.c. +They are required in virt-acpi-build.c. So, make them public. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Alistair Francis +Reviewed-by: Andrew Jones +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-5-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt.c | 25 +------------------------ + include/hw/riscv/virt.h | 25 +++++++++++++++++++++++++ + 2 files changed, 26 insertions(+), 24 deletions(-) + +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c +index 9b29ed1108..30b9f8cab6 100644 +--- a/hw/riscv/virt.c ++++ b/hw/riscv/virt.c +@@ -39,7 +39,6 @@ + #include "hw/firmware/smbios.h" + #include "hw/intc/riscv_aclint.h" + #include "hw/intc/riscv_aplic.h" +-#include "hw/intc/riscv_imsic.h" + #include "hw/intc/sifive_plic.h" + #include "hw/misc/sifive_test.h" + #include "hw/platform-bus.h" +@@ -55,28 +54,6 @@ + #include "hw/acpi/aml-build.h" + #include "qapi/qapi-visit-common.h" + +-/* +- * The virt machine physical address space used by some of the devices +- * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets, +- * number of CPUs, and number of IMSIC guest files. +- * +- * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS, +- * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization +- * of virt machine physical address space. +- */ +- +-#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT) +-#if VIRT_IMSIC_GROUP_MAX_SIZE < \ +- IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS) +-#error "Can't accommodate single IMSIC group in address space" +-#endif +- +-#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \ +- VIRT_IMSIC_GROUP_MAX_SIZE) +-#if 0x4000000 < VIRT_IMSIC_MAX_SIZE +-#error "Can't accommodate all IMSIC groups in address space" +-#endif +- + /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */ + static bool virt_use_kvm_aia(RISCVVirtState *s) + { +@@ -513,7 +490,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s, + g_free(plic_cells); + } + +-static uint32_t imsic_num_bits(uint32_t count) ++uint32_t imsic_num_bits(uint32_t count) + { + uint32_t ret = 0; + +diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h +index e5c474b26e..5b03575ed3 100644 +--- a/include/hw/riscv/virt.h ++++ b/include/hw/riscv/virt.h +@@ -23,6 +23,7 @@ + #include "hw/riscv/riscv_hart.h" + #include "hw/sysbus.h" + #include "hw/block/flash.h" ++#include "hw/intc/riscv_imsic.h" + + #define VIRT_CPUS_MAX_BITS 9 + #define VIRT_CPUS_MAX (1 << VIRT_CPUS_MAX_BITS) +@@ -127,4 +128,28 @@ enum { + + bool virt_is_acpi_enabled(RISCVVirtState *s); + void virt_acpi_setup(RISCVVirtState *vms); ++uint32_t imsic_num_bits(uint32_t count); ++ ++/* ++ * The virt machine physical address space used by some of the devices ++ * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets, ++ * number of CPUs, and number of IMSIC guest files. ++ * ++ * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS, ++ * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization ++ * of virt machine physical address space. ++ */ ++ ++#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT) ++#if VIRT_IMSIC_GROUP_MAX_SIZE < \ ++ IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS) ++#error "Can't accomodate single IMSIC group in address space" ++#endif ++ ++#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \ ++ VIRT_IMSIC_GROUP_MAX_SIZE) ++#if 0x4000000 < VIRT_IMSIC_MAX_SIZE ++#error "Can't accomodate all IMSIC groups in address space" ++#endif ++ + #endif +-- +2.33.0 + diff --git a/hw-riscv-virt-Update-GPEX-MMIO-related-properties.patch b/hw-riscv-virt-Update-GPEX-MMIO-related-properties.patch new file mode 100644 index 00000000..818ec896 --- /dev/null +++ b/hw-riscv-virt-Update-GPEX-MMIO-related-properties.patch @@ -0,0 +1,117 @@ +From 9367132cdc0340ebc17d434527818fe87f1f0fa4 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:35 +0800 +Subject: [PATCH 11/18] hw/riscv/virt: Update GPEX MMIO related properties + +commit e86e95270e2b10e57c69852778452b54b31e1c19 upstream + +Update the GPEX host bridge properties related to MMIO ranges with +values set for the virt machine. + +Suggested-by: Igor Mammedov +Signed-off-by: Sunil V L +Reviewed-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-12-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt.c | 47 ++++++++++++++++++++++++++++------------- + include/hw/riscv/virt.h | 1 + + 2 files changed, 33 insertions(+), 15 deletions(-) + +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c +index 30b9f8cab6..c47df46bfc 100644 +--- a/hw/riscv/virt.c ++++ b/hw/riscv/virt.c +@@ -1055,21 +1055,45 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) + } + + static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, +- hwaddr ecam_base, hwaddr ecam_size, +- hwaddr mmio_base, hwaddr mmio_size, +- hwaddr high_mmio_base, +- hwaddr high_mmio_size, +- hwaddr pio_base, +- DeviceState *irqchip) ++ DeviceState *irqchip, ++ RISCVVirtState *s) + { + DeviceState *dev; + MemoryRegion *ecam_alias, *ecam_reg; + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; ++ hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base; ++ hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size; ++ hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base; ++ hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size; ++ hwaddr high_mmio_base = virt_high_pcie_memmap.base; ++ hwaddr high_mmio_size = virt_high_pcie_memmap.size; ++ hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base; ++ hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size; + qemu_irq irq; + int i; + + dev = qdev_new(TYPE_GPEX_HOST); + ++ /* Set GPEX object properties for the virt machine */ ++ object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_BASE, ++ ecam_base, NULL); ++ object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_SIZE, ++ ecam_size, NULL); ++ object_property_set_uint(OBJECT(GPEX_HOST(dev)), ++ PCI_HOST_BELOW_4G_MMIO_BASE, ++ mmio_base, NULL); ++ object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_BELOW_4G_MMIO_SIZE, ++ mmio_size, NULL); ++ object_property_set_uint(OBJECT(GPEX_HOST(dev)), ++ PCI_HOST_ABOVE_4G_MMIO_BASE, ++ high_mmio_base, NULL); ++ object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ABOVE_4G_MMIO_SIZE, ++ high_mmio_size, NULL); ++ object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_BASE, ++ pio_base, NULL); ++ object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_SIZE, ++ pio_size, NULL); ++ + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + + ecam_alias = g_new0(MemoryRegion, 1); +@@ -1100,6 +1124,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, + gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); + } + ++ GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(GPEX_HOST(dev))->bus; + return dev; + } + +@@ -1536,15 +1561,7 @@ static void virt_machine_init(MachineState *machine) + qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); + } + +- gpex_pcie_init(system_memory, +- memmap[VIRT_PCIE_ECAM].base, +- memmap[VIRT_PCIE_ECAM].size, +- memmap[VIRT_PCIE_MMIO].base, +- memmap[VIRT_PCIE_MMIO].size, +- virt_high_pcie_memmap.base, +- virt_high_pcie_memmap.size, +- memmap[VIRT_PCIE_PIO].base, +- pcie_irqchip); ++ gpex_pcie_init(system_memory, pcie_irqchip, s); + + create_platform_bus(s, mmio_irqchip); + +diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h +index 5b03575ed3..f89790fd58 100644 +--- a/include/hw/riscv/virt.h ++++ b/include/hw/riscv/virt.h +@@ -61,6 +61,7 @@ struct RISCVVirtState { + char *oem_table_id; + OnOffAuto acpi; + const MemMapEntry *memmap; ++ struct GPEXHost *gpex_host; + }; + + enum { +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-AIA-support-in-RINTC.patch b/hw-riscv-virt-acpi-build.c-Add-AIA-support-in-RINTC.patch new file mode 100644 index 00000000..14d6e29e --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-AIA-support-in-RINTC.patch @@ -0,0 +1,114 @@ +From bd3c5ec667493e193db4a2fdf165b96f45af8262 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:28 +0800 +Subject: [PATCH 05/18] hw/riscv/virt-acpi-build.c: Add AIA support in RINTC + +commit 0efb12b713338e2be713b689d1c9743f7163f85d upstream + +Update the RINTC structure in MADT with AIA related fields. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Acked-by: Alistair Francis +Reviewed-by: Andrew Jones +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-6-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 43 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 39 insertions(+), 4 deletions(-) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index d8772c2821..3f9536356e 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -38,6 +38,7 @@ + #include "hw/intc/riscv_aclint.h" + + #define ACPI_BUILD_TABLE_SIZE 0x20000 ++#define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index)) + + typedef struct AcpiBuildState { + /* Copy of table in RAM (for patching) */ +@@ -59,17 +60,50 @@ static void acpi_align_size(GArray *blob, unsigned align) + + static void riscv_acpi_madt_add_rintc(uint32_t uid, + const CPUArchIdList *arch_ids, +- GArray *entry) ++ GArray *entry, ++ RISCVVirtState *s) + { ++ uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); + uint64_t hart_id = arch_ids->cpus[uid].arch_id; ++ uint32_t imsic_size, local_cpu_id, socket_id; ++ uint64_t imsic_socket_addr, imsic_addr; ++ MachineState *ms = MACHINE(s); + ++ socket_id = arch_ids->cpus[uid].props.node_id; ++ local_cpu_id = (arch_ids->cpus[uid].arch_id - ++ riscv_socket_first_hartid(ms, socket_id)) % ++ riscv_socket_hart_count(ms, socket_id); ++ imsic_socket_addr = s->memmap[VIRT_IMSIC_S].base + ++ (socket_id * VIRT_IMSIC_GROUP_MAX_SIZE); ++ imsic_size = IMSIC_HART_SIZE(guest_index_bits); ++ imsic_addr = imsic_socket_addr + local_cpu_id * imsic_size; + build_append_int_noprefix(entry, 0x18, 1); /* Type */ +- build_append_int_noprefix(entry, 20, 1); /* Length */ ++ build_append_int_noprefix(entry, 36, 1); /* Length */ + build_append_int_noprefix(entry, 1, 1); /* Version */ + build_append_int_noprefix(entry, 0, 1); /* Reserved */ + build_append_int_noprefix(entry, 0x1, 4); /* Flags */ + build_append_int_noprefix(entry, hart_id, 8); /* Hart ID */ + build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */ ++ /* External Interrupt Controller ID */ ++ if (s->aia_type == VIRT_AIA_TYPE_APLIC) { ++ build_append_int_noprefix(entry, ++ ACPI_BUILD_INTC_ID( ++ arch_ids->cpus[uid].props.node_id, ++ local_cpu_id), ++ 4); ++ } else { ++ build_append_int_noprefix(entry, 0, 4); ++ } ++ ++ if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { ++ /* IMSIC Base address */ ++ build_append_int_noprefix(entry, imsic_addr, 8); ++ /* IMSIC Size */ ++ build_append_int_noprefix(entry, imsic_size, 4); ++ } else { ++ build_append_int_noprefix(entry, 0, 8); ++ build_append_int_noprefix(entry, 0, 4); ++ } + } + + static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) +@@ -88,7 +122,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) + aml_int(arch_ids->cpus[i].arch_id))); + + /* build _MAT object */ +- riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf); ++ riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf, s); + aml_append(dev, aml_name_decl("_MAT", + aml_buffer(madt_buf->len, + (uint8_t *)madt_buf->data))); +@@ -227,6 +261,7 @@ static void build_dsdt(GArray *table_data, + * 5.2.12 Multiple APIC Description Table (MADT) + * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15 + * https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view ++ * https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view + */ + static void build_madt(GArray *table_data, + BIOSLinker *linker, +@@ -246,7 +281,7 @@ static void build_madt(GArray *table_data, + + /* RISC-V Local INTC structures per HART */ + for (int i = 0; i < arch_ids->len; i++) { +- riscv_acpi_madt_add_rintc(i, arch_ids, table_data); ++ riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s); + } + + acpi_table_end(linker, &table); +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-APLIC-in-the-MADT.patch b/hw-riscv-virt-acpi-build.c-Add-APLIC-in-the-MADT.patch new file mode 100644 index 00000000..92cad725 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-APLIC-in-the-MADT.patch @@ -0,0 +1,76 @@ +From d9f8fe22148991711170825346b61ff3f8adfb0f Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:30 +0800 +Subject: [PATCH 07/18] hw/riscv/virt-acpi-build.c: Add APLIC in the MADT + +commit 7d189186f68b2b249c0bd6c84984f3aad2bcd1ca upstream + +Add APLIC structures for each socket in the MADT when system is configured +with APLIC as the external wired interrupt controller. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Andrew Jones +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-8-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 6bb21014fd..ec49c8804b 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -274,6 +274,8 @@ static void build_madt(GArray *table_data, + uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); + uint16_t imsic_max_hart_per_socket = 0; + uint8_t hart_index_bits; ++ uint64_t aplic_addr; ++ uint32_t gsi_base; + uint8_t socket; + + for (socket = 0; socket < riscv_socket_count(ms); socket++) { +@@ -319,6 +321,38 @@ static void build_madt(GArray *table_data, + build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1); + } + ++ if (s->aia_type != VIRT_AIA_TYPE_NONE) { ++ /* APLICs */ ++ for (socket = 0; socket < riscv_socket_count(ms); socket++) { ++ aplic_addr = s->memmap[VIRT_APLIC_S].base + ++ s->memmap[VIRT_APLIC_S].size * socket; ++ gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket; ++ build_append_int_noprefix(table_data, 0x1A, 1); /* Type */ ++ build_append_int_noprefix(table_data, 36, 1); /* Length */ ++ build_append_int_noprefix(table_data, 1, 1); /* Version */ ++ build_append_int_noprefix(table_data, socket, 1); /* APLIC ID */ ++ build_append_int_noprefix(table_data, 0, 4); /* Flags */ ++ build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */ ++ /* Number of IDCs */ ++ if (s->aia_type == VIRT_AIA_TYPE_APLIC) { ++ build_append_int_noprefix(table_data, ++ s->soc[socket].num_harts, ++ 2); ++ } else { ++ build_append_int_noprefix(table_data, 0, 2); ++ } ++ /* Total External Interrupt Sources Supported */ ++ build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2); ++ /* Global System Interrupt Base */ ++ build_append_int_noprefix(table_data, gsi_base, 4); ++ /* APLIC Address */ ++ build_append_int_noprefix(table_data, aplic_addr, 8); ++ /* APLIC size */ ++ build_append_int_noprefix(table_data, ++ s->memmap[VIRT_APLIC_S].size, 4); ++ } ++ } ++ + acpi_table_end(linker, &table); + } + +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-CMO-information-in-RH.patch b/hw-riscv-virt-acpi-build.c-Add-CMO-information-in-RH.patch new file mode 100644 index 00000000..02b01291 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-CMO-information-in-RH.patch @@ -0,0 +1,131 @@ +From 99684e0a5700edb5d7ca51f255f23a54749efd1a Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:31 +0800 +Subject: [PATCH 08/18] hw/riscv/virt-acpi-build.c: Add CMO information in RHCT + +commit e810a5177c44509e17293d4c7e6cffab8ce197c9 stream + +When CMO related extensions like Zicboz, Zicbom and Zicbop are enabled, the +block size for those extensions need to be communicated via CMO node in +RHCT. Add CMO node in RHCT if any of those CMO extensions are detected. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Andrew Jones +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-9-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 64 +++++++++++++++++++++++++++++++++----- + 1 file changed, 56 insertions(+), 8 deletions(-) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index ec49c8804b..506d487ede 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -140,6 +140,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) + * 5.2.36 RISC-V Hart Capabilities Table (RHCT) + * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16 + * https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view ++ * https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view + */ + static void build_rhct(GArray *table_data, + BIOSLinker *linker, +@@ -149,8 +150,8 @@ static void build_rhct(GArray *table_data, + MachineState *ms = MACHINE(s); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); + size_t len, aligned_len; +- uint32_t isa_offset, num_rhct_nodes; +- RISCVCPU *cpu; ++ uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0; ++ RISCVCPU *cpu = &s->soc[0].harts[0]; + char *isa; + + AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, +@@ -166,6 +167,9 @@ static void build_rhct(GArray *table_data, + + /* ISA + N hart info */ + num_rhct_nodes = 1 + ms->smp.cpus; ++ if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) { ++ num_rhct_nodes++; ++ } + + /* Number of RHCT nodes*/ + build_append_int_noprefix(table_data, num_rhct_nodes, 4); +@@ -177,7 +181,6 @@ static void build_rhct(GArray *table_data, + isa_offset = table_data->len - table.table_offset; + build_append_int_noprefix(table_data, 0, 2); /* Type 0 */ + +- cpu = &s->soc[0].harts[0]; + isa = riscv_isa_string(cpu); + len = 8 + strlen(isa) + 1; + aligned_len = (len % 2) ? (len + 1) : len; +@@ -193,14 +196,59 @@ static void build_rhct(GArray *table_data, + build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */ + } + ++ /* CMO node */ ++ if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) { ++ cmo_offset = table_data->len - table.table_offset; ++ build_append_int_noprefix(table_data, 1, 2); /* Type */ ++ build_append_int_noprefix(table_data, 10, 2); /* Length */ ++ build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ ++ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ ++ ++ /* CBOM block size */ ++ if (cpu->cfg.cbom_blocksize) { ++ build_append_int_noprefix(table_data, ++ __builtin_ctz(cpu->cfg.cbom_blocksize), ++ 1); ++ } else { ++ build_append_int_noprefix(table_data, 0, 1); ++ } ++ ++ /* CBOP block size */ ++ build_append_int_noprefix(table_data, 0, 1); ++ ++ /* CBOZ block size */ ++ if (cpu->cfg.cboz_blocksize) { ++ build_append_int_noprefix(table_data, ++ __builtin_ctz(cpu->cfg.cboz_blocksize), ++ 1); ++ } else { ++ build_append_int_noprefix(table_data, 0, 1); ++ } ++ } ++ + /* Hart Info Node */ + for (int i = 0; i < arch_ids->len; i++) { ++ len = 16; ++ int num_offsets = 1; + build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */ +- build_append_int_noprefix(table_data, 16, 2); /* Length */ +- build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ +- build_append_int_noprefix(table_data, 1, 2); /* Number of offsets */ +- build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ +- build_append_int_noprefix(table_data, isa_offset, 4); /* Offsets[0] */ ++ ++ /* Length */ ++ if (cmo_offset) { ++ len += 4; ++ num_offsets++; ++ } ++ ++ build_append_int_noprefix(table_data, len, 2); ++ build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ ++ /* Number of offsets */ ++ build_append_int_noprefix(table_data, num_offsets, 2); ++ build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ ++ ++ /* Offsets */ ++ build_append_int_noprefix(table_data, isa_offset, 4); ++ if (cmo_offset) { ++ build_append_int_noprefix(table_data, cmo_offset, 4); ++ } + } + + acpi_table_end(linker, &table); +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-IMSIC-in-the-MADT.patch b/hw-riscv-virt-acpi-build.c-Add-IMSIC-in-the-MADT.patch new file mode 100644 index 00000000..adfac94e --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-IMSIC-in-the-MADT.patch @@ -0,0 +1,76 @@ +From ff2e662b539eb2cf9a754f1c5fb2e055e67ac3f7 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:29 +0800 +Subject: [PATCH 06/18] hw/riscv/virt-acpi-build.c: Add IMSIC in the MADT + +commit 66ac45b75975a64aa3fbcaa038aecfbc11ac8547 upstream + +Add IMSIC structure in MADT when IMSIC is configured. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Andrew Jones +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-7-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 3f9536356e..6bb21014fd 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -270,6 +270,19 @@ static void build_madt(GArray *table_data, + MachineClass *mc = MACHINE_GET_CLASS(s); + MachineState *ms = MACHINE(s); + const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); ++ uint8_t group_index_bits = imsic_num_bits(riscv_socket_count(ms)); ++ uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); ++ uint16_t imsic_max_hart_per_socket = 0; ++ uint8_t hart_index_bits; ++ uint8_t socket; ++ ++ for (socket = 0; socket < riscv_socket_count(ms); socket++) { ++ if (imsic_max_hart_per_socket < s->soc[socket].num_harts) { ++ imsic_max_hart_per_socket = s->soc[socket].num_harts; ++ } ++ } ++ ++ hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket); + + AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id, + .oem_table_id = s->oem_table_id }; +@@ -284,6 +297,28 @@ static void build_madt(GArray *table_data, + riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s); + } + ++ /* IMSIC */ ++ if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { ++ /* IMSIC */ ++ build_append_int_noprefix(table_data, 0x19, 1); /* Type */ ++ build_append_int_noprefix(table_data, 16, 1); /* Length */ ++ build_append_int_noprefix(table_data, 1, 1); /* Version */ ++ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ ++ build_append_int_noprefix(table_data, 0, 4); /* Flags */ ++ /* Number of supervisor mode Interrupt Identities */ ++ build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); ++ /* Number of guest mode Interrupt Identities */ ++ build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); ++ /* Guest Index Bits */ ++ build_append_int_noprefix(table_data, guest_index_bits, 1); ++ /* Hart Index Bits */ ++ build_append_int_noprefix(table_data, hart_index_bits, 1); ++ /* Group Index Bits */ ++ build_append_int_noprefix(table_data, group_index_bits, 1); ++ /* Group Index Shift */ ++ build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1); ++ } ++ + acpi_table_end(linker, &table); + } + +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-IO-controllers-and-de.patch b/hw-riscv-virt-acpi-build.c-Add-IO-controllers-and-de.patch new file mode 100644 index 00000000..b37a4ce6 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-IO-controllers-and-de.patch @@ -0,0 +1,160 @@ +From 58d2550602ca8ccf9cc4b80bb7ddd1580052eeab Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:36 +0800 +Subject: [PATCH 12/18] hw/riscv/virt-acpi-build.c: Add IO controllers and + devices + +commit 55ecd83b3697d0e4002c1dfde3265ebe6fa887cc upstream + +Add basic IO controllers and devices like PCI, VirtIO and UART in the +ACPI namespace. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-13-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/Kconfig | 1 + + hw/riscv/virt-acpi-build.c | 79 ++++++++++++++++++++++++++++++++++++-- + 2 files changed, 76 insertions(+), 4 deletions(-) + +diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig +index 1e11ac9432..5d644eb7b1 100644 +--- a/hw/riscv/Kconfig ++++ b/hw/riscv/Kconfig +@@ -46,6 +46,7 @@ config RISCV_VIRT + select FW_CFG_DMA + select PLATFORM_BUS + select ACPI ++ select ACPI_PCI + + config SHAKTI_C + bool +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 86c38f7c2b..4d03a27efd 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -27,15 +27,18 @@ + #include "hw/acpi/acpi-defs.h" + #include "hw/acpi/acpi.h" + #include "hw/acpi/aml-build.h" ++#include "hw/acpi/pci.h" + #include "hw/acpi/utils.h" ++#include "hw/intc/riscv_aclint.h" + #include "hw/nvram/fw_cfg_acpi.h" ++#include "hw/pci-host/gpex.h" ++#include "hw/riscv/virt.h" ++#include "hw/riscv/numa.h" ++#include "hw/virtio/virtio-acpi.h" ++#include "migration/vmstate.h" + #include "qapi/error.h" + #include "qemu/error-report.h" + #include "sysemu/reset.h" +-#include "migration/vmstate.h" +-#include "hw/riscv/virt.h" +-#include "hw/riscv/numa.h" +-#include "hw/intc/riscv_aclint.h" + + #define ACPI_BUILD_TABLE_SIZE 0x20000 + #define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index)) +@@ -132,6 +135,39 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) + } + } + ++static void ++acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, ++ uint32_t uart_irq) ++{ ++ Aml *dev = aml_device("COM0"); ++ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(0))); ++ ++ Aml *crs = aml_resource_template(); ++ aml_append(crs, aml_memory32_fixed(uart_memmap->base, ++ uart_memmap->size, AML_READ_WRITE)); ++ aml_append(crs, ++ aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, ++ AML_EXCLUSIVE, &uart_irq, 1)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ ++ Aml *pkg = aml_package(2); ++ aml_append(pkg, aml_string("clock-frequency")); ++ aml_append(pkg, aml_int(3686400)); ++ ++ Aml *UUID = aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"); ++ ++ Aml *pkg1 = aml_package(1); ++ aml_append(pkg1, pkg); ++ ++ Aml *package = aml_package(2); ++ aml_append(package, UUID); ++ aml_append(package, pkg1); ++ ++ aml_append(dev, aml_name_decl("_DSD", package)); ++ aml_append(scope, dev); ++} ++ + /* RHCT Node[N] starts at offset 56 */ + #define RHCT_NODE_ARRAY_OFFSET 56 + +@@ -310,6 +346,8 @@ static void build_dsdt(GArray *table_data, + RISCVVirtState *s) + { + Aml *scope, *dsdt; ++ MachineState *ms = MACHINE(s); ++ uint8_t socket_count; + const MemMapEntry *memmap = s->memmap; + AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id, + .oem_table_id = s->oem_table_id }; +@@ -329,6 +367,29 @@ static void build_dsdt(GArray *table_data, + + fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); + ++ socket_count = riscv_socket_count(ms); ++ ++ acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); ++ ++ if (socket_count == 1) { ++ virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, ++ memmap[VIRT_VIRTIO].size, ++ VIRTIO_IRQ, 0, VIRTIO_COUNT); ++ acpi_dsdt_add_gpex_host(scope, PCIE_IRQ); ++ } else if (socket_count == 2) { ++ virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, ++ memmap[VIRT_VIRTIO].size, ++ VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0, ++ VIRTIO_COUNT); ++ acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES); ++ } else { ++ virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, ++ memmap[VIRT_VIRTIO].size, ++ VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0, ++ VIRTIO_COUNT); ++ acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2); ++ } ++ + aml_append(dsdt, scope); + + /* copy AML table into ACPI tables blob and patch header there */ +@@ -465,6 +526,16 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) + acpi_add_table(table_offsets, tables_blob); + build_rhct(tables_blob, tables->linker, s); + ++ acpi_add_table(table_offsets, tables_blob); ++ { ++ AcpiMcfgInfo mcfg = { ++ .base = s->memmap[VIRT_PCIE_MMIO].base, ++ .size = s->memmap[VIRT_PCIE_MMIO].size, ++ }; ++ build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id, ++ s->oem_table_id); ++ } ++ + /* XSDT is pointed to by RSDP */ + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id, +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-MMU-node-in-RHCT.patch b/hw-riscv-virt-acpi-build.c-Add-MMU-node-in-RHCT.patch new file mode 100644 index 00000000..24a1c290 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-MMU-node-in-RHCT.patch @@ -0,0 +1,102 @@ +From 7310f0bc6612ced123be51af2fd720e84955759a Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:33 +0800 +Subject: [PATCH 09/18] hw/riscv/virt-acpi-build.c: Add MMU node in RHCT + +commit a52aea263e0f25993e368ee682d96f32aff52499 upstream + +MMU type information is available via MMU node in RHCT. Add this node in +RHCT. + +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Andrew Jones +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-10-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 506d487ede..86c38f7c2b 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -152,6 +152,8 @@ static void build_rhct(GArray *table_data, + size_t len, aligned_len; + uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0; + RISCVCPU *cpu = &s->soc[0].harts[0]; ++ uint32_t mmu_offset = 0; ++ uint8_t satp_mode_max; + char *isa; + + AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, +@@ -171,6 +173,10 @@ static void build_rhct(GArray *table_data, + num_rhct_nodes++; + } + ++ if (cpu->cfg.satp_mode.supported != 0) { ++ num_rhct_nodes++; ++ } ++ + /* Number of RHCT nodes*/ + build_append_int_noprefix(table_data, num_rhct_nodes, 4); + +@@ -226,6 +232,26 @@ static void build_rhct(GArray *table_data, + } + } + ++ /* MMU node structure */ ++ if (cpu->cfg.satp_mode.supported != 0) { ++ satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); ++ mmu_offset = table_data->len - table.table_offset; ++ build_append_int_noprefix(table_data, 2, 2); /* Type */ ++ build_append_int_noprefix(table_data, 8, 2); /* Length */ ++ build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ ++ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ ++ /* MMU Type */ ++ if (satp_mode_max == VM_1_10_SV57) { ++ build_append_int_noprefix(table_data, 2, 1); /* Sv57 */ ++ } else if (satp_mode_max == VM_1_10_SV48) { ++ build_append_int_noprefix(table_data, 1, 1); /* Sv48 */ ++ } else if (satp_mode_max == VM_1_10_SV39) { ++ build_append_int_noprefix(table_data, 0, 1); /* Sv39 */ ++ } else { ++ assert(1); ++ } ++ } ++ + /* Hart Info Node */ + for (int i = 0; i < arch_ids->len; i++) { + len = 16; +@@ -238,17 +264,25 @@ static void build_rhct(GArray *table_data, + num_offsets++; + } + ++ if (mmu_offset) { ++ len += 4; ++ num_offsets++; ++ } ++ + build_append_int_noprefix(table_data, len, 2); + build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ + /* Number of offsets */ + build_append_int_noprefix(table_data, num_offsets, 2); + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ +- + /* Offsets */ + build_append_int_noprefix(table_data, isa_offset, 4); + if (cmo_offset) { + build_append_int_noprefix(table_data, cmo_offset, 4); + } ++ ++ if (mmu_offset) { ++ build_append_int_noprefix(table_data, mmu_offset, 4); ++ } + } + + acpi_table_end(linker, &table); +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-PLIC-in-MADT.patch b/hw-riscv-virt-acpi-build.c-Add-PLIC-in-MADT.patch new file mode 100644 index 00000000..5c89086e --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-PLIC-in-MADT.patch @@ -0,0 +1,72 @@ +From 37a9be92a26b78341aa2ab03126590b9d9fa18b6 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:37 +0800 +Subject: [PATCH 13/18] hw/riscv/virt-acpi-build.c: Add PLIC in MADT + +commit d641da6ed431f497b763a6e6bf30e0b4dc00e0d9 upstream + +Add PLIC structures for each socket in the MADT when system is +configured with PLIC as the external interrupt controller. + +Signed-off-by: Haibo Xu +Signed-off-by: Sunil V L +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Andrew Jones +Acked-by: Alistair Francis +Acked-by: Michael S. Tsirkin +Message-ID: <20231218150247.466427-14-sunilvl@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 4d03a27efd..d4a02579d6 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -94,6 +94,12 @@ static void riscv_acpi_madt_add_rintc(uint32_t uid, + arch_ids->cpus[uid].props.node_id, + local_cpu_id), + 4); ++ } else if (s->aia_type == VIRT_AIA_TYPE_NONE) { ++ build_append_int_noprefix(entry, ++ ACPI_BUILD_INTC_ID( ++ arch_ids->cpus[uid].props.node_id, ++ 2 * local_cpu_id + 1), ++ 4); + } else { + build_append_int_noprefix(entry, 0, 4); + } +@@ -494,6 +500,29 @@ static void build_madt(GArray *table_data, + build_append_int_noprefix(table_data, + s->memmap[VIRT_APLIC_S].size, 4); + } ++ } else { ++ /* PLICs */ ++ for (socket = 0; socket < riscv_socket_count(ms); socket++) { ++ aplic_addr = s->memmap[VIRT_PLIC].base + ++ s->memmap[VIRT_PLIC].size * socket; ++ gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket; ++ build_append_int_noprefix(table_data, 0x1B, 1); /* Type */ ++ build_append_int_noprefix(table_data, 36, 1); /* Length */ ++ build_append_int_noprefix(table_data, 1, 1); /* Version */ ++ build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */ ++ build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */ ++ /* Total External Interrupt Sources Supported */ ++ build_append_int_noprefix(table_data, ++ VIRT_IRQCHIP_NUM_SOURCES - 1, 2); ++ build_append_int_noprefix(table_data, 0, 2); /* Max Priority */ ++ build_append_int_noprefix(table_data, 0, 4); /* Flags */ ++ /* PLIC Size */ ++ build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4); ++ /* PLIC Address */ ++ build_append_int_noprefix(table_data, aplic_addr, 8); ++ /* Global System Interrupt Vector Base */ ++ build_append_int_noprefix(table_data, gsi_base, 4); ++ } + } + + acpi_table_end(linker, &table); +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch b/hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch new file mode 100644 index 00000000..bec635f5 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch @@ -0,0 +1,112 @@ +From 6d52123c9c8a0c6e9d7560f9c4e4b641e568e0c6 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:42 +0800 +Subject: [PATCH 18/18] hw/riscv/virt-acpi-build.c: Add SRAT and SLIT ACPI + tables + +commit a29f5b957644dd0f14a43c8719b18c134875195c upstream + +Enable ACPI NUMA support by adding the following 2 ACPI tables: +SRAT: provides the association for memory/Harts and Proximity Domains +SLIT: provides the relative distance between Proximity Domains + +The SRAT RINTC Affinity Structure definition[1] was based on the recently +approved ACPI CodeFirst ECR[2]. + +[1] https://github.com/riscv-non-isa/riscv-acpi/issues/25 +[2] https://mantis.uefi.org/mantis/view.php?id=2433 + +Signed-off-by: Haibo Xu +Reviewed-by: Andrew Jones +Message-ID: <20240129094200.3581037-1-haibo1.xu@intel.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 60 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index d69c25d2c9..69e9646683 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -596,11 +596,61 @@ static void build_madt(GArray *table_data, + acpi_table_end(linker, &table); + } + ++/* ++ * ACPI spec, Revision 6.5+ ++ * 5.2.16 System Resource Affinity Table (SRAT) ++ * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25 ++ * https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view ++ */ ++static void ++build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms) ++{ ++ int i; ++ uint64_t mem_base; ++ MachineClass *mc = MACHINE_GET_CLASS(vms); ++ MachineState *ms = MACHINE(vms); ++ const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms); ++ AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id, ++ .oem_table_id = vms->oem_table_id }; ++ ++ acpi_table_begin(&table, table_data); ++ build_append_int_noprefix(table_data, 1, 4); /* Reserved */ ++ build_append_int_noprefix(table_data, 0, 8); /* Reserved */ ++ ++ for (i = 0; i < cpu_list->len; ++i) { ++ uint32_t nodeid = cpu_list->cpus[i].props.node_id; ++ /* ++ * 5.2.16.8 RINTC Affinity Structure ++ */ ++ build_append_int_noprefix(table_data, 7, 1); /* Type */ ++ build_append_int_noprefix(table_data, 20, 1); /* Length */ ++ build_append_int_noprefix(table_data, 0, 2); /* Reserved */ ++ build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */ ++ build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ ++ /* Flags, Table 5-70 */ ++ build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4); ++ build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */ ++ } ++ ++ mem_base = vms->memmap[VIRT_DRAM].base; ++ for (i = 0; i < ms->numa_state->num_nodes; ++i) { ++ if (ms->numa_state->nodes[i].node_mem > 0) { ++ build_srat_memory(table_data, mem_base, ++ ms->numa_state->nodes[i].node_mem, i, ++ MEM_AFFINITY_ENABLED); ++ mem_base += ms->numa_state->nodes[i].node_mem; ++ } ++ } ++ ++ acpi_table_end(linker, &table); ++} ++ + static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) + { + GArray *table_offsets; + unsigned dsdt, xsdt; + GArray *tables_blob = tables->table_data; ++ MachineState *ms = MACHINE(s); + + table_offsets = g_array_new(false, true, + sizeof(uint32_t)); +@@ -636,6 +686,16 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) + s->oem_table_id); + } + ++ if (ms->numa_state->num_nodes > 0) { ++ acpi_add_table(table_offsets, tables_blob); ++ build_srat(tables_blob, tables->linker, s); ++ if (ms->numa_state->have_numa_distance) { ++ acpi_add_table(table_offsets, tables_blob); ++ build_slit(tables_blob, tables->linker, ms, s->oem_id, ++ s->oem_table_id); ++ } ++ } ++ + /* XSDT is pointed to by RSDP */ + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id, +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Add-namespace-devices-for.patch b/hw-riscv-virt-acpi-build.c-Add-namespace-devices-for.patch new file mode 100644 index 00000000..231a6ae5 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Add-namespace-devices-for.patch @@ -0,0 +1,78 @@ +From 27190f7b6b48ba4684e9f352d0adda63bca814fe Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:39 +0800 +Subject: [PATCH 15/18] hw/riscv/virt-acpi-build.c: Add namespace devices for + PLIC and APLIC + +commit a54dd0cd6b9119c44d52547f51a529122f0ec1f1 upstream + +As per the requirement ACPI_080 in the RISC-V Boot and Runtime Services +(BRS) specification [1], PLIC and APLIC should be in namespace as well. +So, add them using the defined HID. + +[1] - https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.0.2/riscv-brs-spec.pdf + (Chapter 6) + +Signed-off-by: Sunil V L +Acked-by: Alistair Francis +Acked-by: Igor Mammedov +Message-Id: <20240716144306.2432257-2-sunilvl@ventanamicro.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/riscv/virt-acpi-build.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index d4a02579d6..2189579d53 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -141,6 +141,30 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) + } + } + ++static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count, ++ uint64_t mmio_base, uint64_t mmio_size, ++ const char *hid) ++{ ++ uint64_t plic_aplic_addr; ++ uint32_t gsi_base; ++ uint8_t socket; ++ ++ for (socket = 0; socket < socket_count; socket++) { ++ plic_aplic_addr = mmio_base + mmio_size * socket; ++ gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket; ++ Aml *dev = aml_device("IC%.02X", socket); ++ aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid))); ++ aml_append(dev, aml_name_decl("_UID", aml_int(socket))); ++ aml_append(dev, aml_name_decl("_GSB", aml_int(gsi_base))); ++ ++ Aml *crs = aml_resource_template(); ++ aml_append(crs, aml_memory32_fixed(plic_aplic_addr, mmio_size, ++ AML_READ_WRITE)); ++ aml_append(dev, aml_name_decl("_CRS", crs)); ++ aml_append(scope, dev); ++ } ++} ++ + static void + acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + uint32_t uart_irq) +@@ -375,6 +399,14 @@ static void build_dsdt(GArray *table_data, + + socket_count = riscv_socket_count(ms); + ++ if (s->aia_type == VIRT_AIA_TYPE_NONE) { ++ acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base, ++ memmap[VIRT_PLIC].size, "RSCV0001"); ++ } else { ++ acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base, ++ memmap[VIRT_APLIC_S].size, "RSCV0002"); ++ } ++ + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + + if (socket_count == 1) { +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch b/hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch new file mode 100644 index 00000000..d29531b4 --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch @@ -0,0 +1,78 @@ +From 612c2ba1c1b0377318bf9a8ed421a505bafc3311 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:41 +0800 +Subject: [PATCH 17/18] hw/riscv/virt-acpi-build.c: Generate SPCR table + +commit 3e6f1e61b4bc0facd13967580feed47d96a2c28c upstream + +Generate Serial Port Console Redirection Table (SPCR) for RISC-V +virtual machine. + +Signed-off-by: Sia Jee Heng +Reviewed-by: Daniel Henrique Barboza +Message-ID: <20240129021440.17640-3-jeeheng.sia@starfivetech.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt-acpi-build.c | 39 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 6230ab02c6..d69c25d2c9 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -198,6 +198,42 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + aml_append(scope, dev); + } + ++/* ++ * Serial Port Console Redirection Table (SPCR) ++ * Rev: 1.07 ++ */ ++ ++static void ++spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s) ++{ ++ AcpiSpcrData serial = { ++ .interface_type = 0, /* 16550 compatible */ ++ .base_addr.id = AML_AS_SYSTEM_MEMORY, ++ .base_addr.width = 32, ++ .base_addr.offset = 0, ++ .base_addr.size = 1, ++ .base_addr.addr = s->memmap[VIRT_UART0].base, ++ .interrupt_type = (1 << 4),/* Bit[4] RISC-V PLIC/APLIC */ ++ .pc_interrupt = 0, ++ .interrupt = UART0_IRQ, ++ .baud_rate = 7, /* 15200 */ ++ .parity = 0, ++ .stop_bits = 1, ++ .flow_control = 0, ++ .terminal_type = 3, /* ANSI */ ++ .language = 0, /* Language */ ++ .pci_device_id = 0xffff, /* not a PCI device*/ ++ .pci_vendor_id = 0xffff, /* not a PCI device*/ ++ .pci_bus = 0, ++ .pci_device = 0, ++ .pci_function = 0, ++ .pci_flags = 0, ++ .pci_segment = 0, ++ }; ++ ++ build_spcr(table_data, linker, &serial, 2, s->oem_id, s->oem_table_id); ++} ++ + /* RHCT Node[N] starts at offset 56 */ + #define RHCT_NODE_ARRAY_OFFSET 56 + +@@ -587,6 +623,9 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) + acpi_add_table(table_offsets, tables_blob); + build_rhct(tables_blob, tables->linker, s); + ++ acpi_add_table(table_offsets, tables_blob); ++ spcr_setup(tables_blob, tables->linker, s); ++ + acpi_add_table(table_offsets, tables_blob); + { + AcpiMcfgInfo mcfg = { +-- +2.33.0 + diff --git a/hw-riscv-virt-acpi-build.c-Update-the-HID-of-RISC-V-.patch b/hw-riscv-virt-acpi-build.c-Update-the-HID-of-RISC-V-.patch new file mode 100644 index 00000000..460d7fca --- /dev/null +++ b/hw-riscv-virt-acpi-build.c-Update-the-HID-of-RISC-V-.patch @@ -0,0 +1,41 @@ +From 0fb0bf77d7a956e36975c8cfcac83c2e972a5fe3 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:40 +0800 +Subject: [PATCH 16/18] hw/riscv/virt-acpi-build.c: Update the HID of RISC-V + UART + +commit faacd2e6b6a85a5eee2472e5a7f50bf69c4ad44a upstream + +The requirement ACPI_060 in the RISC-V BRS specification [1], requires +NS16550 compatible UART to have the HID RSCV0003. So, update the HID for +the UART. + +[1] - https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.0.2/riscv-brs-spec.pdf + (Chapter 6) + +Signed-off-by: Sunil V L +Acked-by: Alistair Francis +Reviewed-by: Igor Mammedov +Message-Id: <20240716144306.2432257-3-sunilvl@ventanamicro.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/riscv/virt-acpi-build.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c +index 2189579d53..6230ab02c6 100644 +--- a/hw/riscv/virt-acpi-build.c ++++ b/hw/riscv/virt-acpi-build.c +@@ -170,7 +170,7 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + uint32_t uart_irq) + { + Aml *dev = aml_device("COM0"); +- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); ++ aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); +-- +2.33.0 + diff --git a/hw-riscv-virt.c-fix-the-interrupts-extended-property.patch b/hw-riscv-virt.c-fix-the-interrupts-extended-property.patch new file mode 100644 index 00000000..51020157 --- /dev/null +++ b/hw-riscv-virt.c-fix-the-interrupts-extended-property.patch @@ -0,0 +1,92 @@ +From 127e3dfe8ed67aa0f763e03c5424e6f23b8aafb3 Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Mon, 4 Aug 2025 20:59:38 +0800 +Subject: [PATCH 14/18] hw/riscv/virt.c: fix the interrupts-extended property + format of PLIC + +commit ca334e10dcd1f0f3a3c08f8dc3f9945d574d0e6b upstream + +The interrupts-extended property of PLIC only has 2 * hart number +fields when KVM enabled, copy 4 * hart number fields to fdt will +expose some uninitialized value. + +In this patch, I also refactor the code about the setting of +interrupts-extended property of PLIC for improved readability. + +Signed-off-by: Yong-Xuan Wang +Reviewed-by: Jim Shu +Reviewed-by: Daniel Henrique Barboza +Message-ID: <20231218090543.22353-1-yongxuan.wang@sifive.com> +Signed-off-by: Alistair Francis +--- + hw/riscv/virt.c | 47 +++++++++++++++++++++++++++-------------------- + 1 file changed, 27 insertions(+), 20 deletions(-) + +diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c +index c47df46bfc..8f01ec7f61 100644 +--- a/hw/riscv/virt.c ++++ b/hw/riscv/virt.c +@@ -438,24 +438,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s, + "sifive,plic-1.0.0", "riscv,plic0" + }; + +- if (kvm_enabled()) { +- plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); +- } else { +- plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); +- } +- +- for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { +- if (kvm_enabled()) { +- plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); +- plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); +- } else { +- plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); +- plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); +- plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); +- plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); +- } +- } +- + plic_phandles[socket] = (*phandle)++; + plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); + plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); +@@ -468,8 +450,33 @@ static void create_fdt_socket_plic(RISCVVirtState *s, + (char **)&plic_compat, + ARRAY_SIZE(plic_compat)); + qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0); +- qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", +- plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); ++ ++ if (kvm_enabled()) { ++ plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); ++ ++ for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { ++ plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); ++ plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); ++ } ++ ++ qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", ++ plic_cells, ++ s->soc[socket].num_harts * sizeof(uint32_t) * 2); ++ } else { ++ plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); ++ ++ for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { ++ plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); ++ plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); ++ plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); ++ plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); ++ } ++ ++ qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", ++ plic_cells, ++ s->soc[socket].num_harts * sizeof(uint32_t) * 4); ++ } ++ + qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", + 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); + qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", +-- +2.33.0 + diff --git a/plugins-loader-fix-deadlock-when-resetting-uninstall.patch b/plugins-loader-fix-deadlock-when-resetting-uninstall.patch new file mode 100644 index 00000000..433a1416 --- /dev/null +++ b/plugins-loader-fix-deadlock-when-resetting-uninstall.patch @@ -0,0 +1,39 @@ +From 105b30f3406bb968b1eb87a6127a988cfb0a3022 Mon Sep 17 00:00:00 2001 +From: songjie +Date: Wed, 13 Aug 2025 14:46:12 +0800 +Subject: [PATCH] plugins/loader: fix deadlock when resetting/uninstalling a + plugin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported and fixed by Dmitry Kurakin. + +Fixes: #2901 + +Signed-off-by: default avatarPierrick Bouvier +Message-Id: <20250404032027.430575-2-pierrick.bouvier@linaro.org> +Signed-off-by: default avatarAlex Bennée +Reviewed-by: default avatarPhilippe Mathieu-Daudé +(cherry picked from commit c07cd110) +Signed-off-by: default avatarMichael Tokarev +--- + plugins/loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/plugins/loader.c b/plugins/loader.c +index 734c11cae0..1f06dfa970 100644 +--- a/plugins/loader.c ++++ b/plugins/loader.c +@@ -374,7 +374,7 @@ static void plugin_reset_destroy(struct qemu_plugin_reset_data *data) + { + qemu_rec_mutex_lock(&plugin.lock); + plugin_reset_destroy__locked(data); +- qemu_rec_mutex_lock(&plugin.lock); ++ qemu_rec_mutex_unlock(&plugin.lock); + } + + static void plugin_flush_destroy(CPUState *cpu, run_on_cpu_data arg) +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index d6e86575..7cd67a39 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 39 +Release: 40 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -997,6 +997,29 @@ Patch0980: target-arm-kvm-rme-Add-measurement-log.patch Patch0981: hw-arm-virt-Add-measurement-log-for-confidential-boo.patch Patch0982: On-the-Adaptation-of-CCA-and-virtCCA.patch Patch0983: Bugfix-Fix-compile-error-in-aarch32.patch +Patch0984: target-i386-kvm-Refine-VMX-controls-setting-for-back.patch +Patch0985: Bugfix-Correctly-set-vms-bootinfo.confidential-in-vi.patch +Patch0986: hw-arm-virt-acpi-build.c-Migrate-fw_cfg-creation-to-.patch +Patch0987: hw-arm-virt-acpi-build.c-Migrate-virtio-creation-to-.patch +Patch0988: hw-i386-acpi-microvm.c-Use-common-function-to-add-vi.patch +Patch0989: hw-riscv-virt-Make-few-IMSIC-macros-and-functions-pu.patch +Patch0990: hw-riscv-virt-acpi-build.c-Add-AIA-support-in-RINTC.patch +Patch0991: hw-riscv-virt-acpi-build.c-Add-IMSIC-in-the-MADT.patch +Patch0992: hw-riscv-virt-acpi-build.c-Add-APLIC-in-the-MADT.patch +Patch0993: hw-riscv-virt-acpi-build.c-Add-CMO-information-in-RH.patch +Patch0994: hw-riscv-virt-acpi-build.c-Add-MMU-node-in-RHCT.patch +Patch0995: hw-pci-host-gpex-Define-properties-for-MMIO-ranges.patch +Patch0996: hw-riscv-virt-Update-GPEX-MMIO-related-properties.patch +Patch0997: hw-riscv-virt-acpi-build.c-Add-IO-controllers-and-de.patch +Patch0998: hw-riscv-virt-acpi-build.c-Add-PLIC-in-MADT.patch +Patch0999: hw-riscv-virt.c-fix-the-interrupts-extended-property.patch +Patch1000: hw-riscv-virt-acpi-build.c-Add-namespace-devices-for.patch +Patch1001: hw-riscv-virt-acpi-build.c-Update-the-HID-of-RISC-V-.patch +Patch1002: hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch +Patch1003: hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch +Patch1004: plugins-loader-fix-deadlock-when-resetting-uninstall.patch +Patch1005: smbios-Fix-buffer-overrun-when-using-path-option.patch + BuildRequires: flex BuildRequires: gcc @@ -1595,6 +1618,30 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Tue Aug 26 2025 Pengrui Zhang - 11:8.2.0-40 +- target/i386/kvm: Refine VMX controls setting for backward compatibility +- Bugfix: Correctly set vms->bootinfo.confidential in virtCCA senarios. +- hw/arm/virt-acpi-build.c: Migrate fw_cfg creation to common location +- hw/arm/virt-acpi-build.c: Migrate virtio creation to common location +- hw/i386/acpi-microvm.c: Use common function to add virtio in DSDT +- hw/riscv: virt: Make few IMSIC macros and functions public +- hw/riscv/virt-acpi-build.c: Add AIA support in RINTC +- hw/riscv/virt-acpi-build.c: Add IMSIC in the MADT +- hw/riscv/virt-acpi-build.c: Add APLIC in the MADT +- hw/riscv/virt-acpi-build.c: Add CMO information in RHCT +- hw/riscv/virt-acpi-build.c: Add MMU node in RHCT +- hw/pci-host/gpex: Define properties for MMIO ranges +- hw/riscv/virt: Update GPEX MMIO related properties +- hw/riscv/virt-acpi-build.c: Add IO controllers and devices +- hw/riscv/virt-acpi-build.c: Add PLIC in MADT +- hw/riscv/virt.c: fix the interrupts-extended property format of PLIC +- hw/riscv/virt-acpi-build.c: Add namespace devices for PLIC and APLIC +- hw/riscv/virt-acpi-build.c: Update the HID of RISC-V UART +- hw/riscv/virt-acpi-build.c: Generate SPCR table +- hw/riscv/virt-acpi-build.c: Add SRAT and SLIT ACPI tables +- plugins/loader: fix deadlock when resetting/uninstalling a plugin +- smbios: Fix buffer overrun when using path= option + * Tue Aug 26 2025 Pengrui Zhang - 11:8.2.0-39 - hw/acpi: Fix the memory leak issue - virtio-net: Fix num_buffers for version 1 diff --git a/smbios-Fix-buffer-overrun-when-using-path-option.patch b/smbios-Fix-buffer-overrun-when-using-path-option.patch new file mode 100644 index 00000000..b96a186b --- /dev/null +++ b/smbios-Fix-buffer-overrun-when-using-path-option.patch @@ -0,0 +1,42 @@ +From 7c76516fee790add2ba308b38999e5cebbd24523 Mon Sep 17 00:00:00 2001 +From: jiesong +Date: Wed, 13 Aug 2025 23:11:18 +0800 +Subject: [PATCH] smbios: Fix buffer overrun when using path= option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We have to make sure the array of bytes read from the path= file +is null-terminated, otherwise we run into a buffer overrun later on. + +Fixes: bb99f477 ("hw/smbios: support loading OEM strings values from a file") +Resolves: #2879 + +Signed-off-by: default avatarDaan De Meyer +Reviewed-by: default avatarDaniel P. Berrangé +Tested-by: default avatarValentin David +Message-ID: <20250323213622.2581013-1-daan.j.demeyer@gmail.com> +Signed-off-by: default avatarPhilippe Mathieu-Daudé +(cherry picked from commit a7a05f5f) +Signed-off-by: default avatarMichael Tokarev +--- + hw/smbios/smbios.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c +index c0c5a81e66..be726ce4ac 100644 +--- a/hw/smbios/smbios.c ++++ b/hw/smbios/smbios.c +@@ -1223,6 +1223,9 @@ static int save_opt_one(void *opaque, + g_byte_array_append(data, (guint8 *)buf, ret); + } + ++ buf[0] = '\0'; ++ g_byte_array_append(data, (guint8 *)buf, 1); ++ + qemu_close(fd); + + *opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1); +-- +2.33.0 + diff --git a/target-i386-kvm-Refine-VMX-controls-setting-for-back.patch b/target-i386-kvm-Refine-VMX-controls-setting-for-back.patch new file mode 100644 index 00000000..47b72687 --- /dev/null +++ b/target-i386-kvm-Refine-VMX-controls-setting-for-back.patch @@ -0,0 +1,68 @@ +From ef76ea9ce99c8158a09f243a9a7f5c9819a2b97b Mon Sep 17 00:00:00 2001 +From: EwanHai +Date: Thu, 5 Jun 2025 03:44:26 -0400 +Subject: [PATCH] target/i386/kvm: Refine VMX controls setting for backward + compatibility + +Upstream qemu commit 4a910e1 ("target/i386: do not set unsupported VMX secondary +execution controls") implemented a workaround for hosts that have +specific CPUID features but do not support the corresponding VMX +controls, e.g., hosts support RDSEED but do not support RDSEED-Exiting. + +In detail, commit 4a910e1 introduced a flag `has_msr_vmx_procbased_clts2`. +If KVM has `MSR_IA32_VMX_PROCBASED_CTLS2` in its msr list, QEMU would +use KVM's settings, avoiding any modifications to this MSR. + +However, this commit (4a910e1) didn't account for cases in older Linux +kernels(4.17~5.2) where `MSR_IA32_VMX_PROCBASED_CTLS2` is in +`kvm_feature_msrs`-obtained by ioctl(KVM_GET_MSR_FEATURE_INDEX_LIST), +but not in `kvm_msr_list`-obtained by ioctl(KVM_GET_MSR_INDEX_LIST). +As a result,it did not set the `has_msr_vmx_procbased_clts2` flag based +on `kvm_msr_list` alone, even though KVM does maintain the value of +this MSR. + +This patch supplements the above logic, ensuring that +`has_msr_vmx_procbased_clts2` is correctly set by checking both MSR +lists, thus maintaining compatibility with older kernels. + +Signed-off-by: EwanHai +--- + target/i386/kvm/kvm.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 3a88e65635..2f379876e6 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -2314,6 +2314,7 @@ void kvm_arch_do_init_vcpu(X86CPU *cpu) + static int kvm_get_supported_feature_msrs(KVMState *s) + { + int ret = 0; ++ int i; + + if (kvm_feature_msrs != NULL) { + return 0; +@@ -2348,6 +2349,20 @@ static int kvm_get_supported_feature_msrs(KVMState *s) + return ret; + } + ++ /* ++ * Compatibility fix: ++ * Older Linux kernels (4.17~5.2) report MSR_IA32_VMX_PROCBASED_CTLS2 ++ * in KVM_GET_MSR_FEATURE_INDEX_LIST but not in KVM_GET_MSR_INDEX_LIST. ++ * This leads to an issue in older kernel versions where QEMU, ++ * through the KVM_GET_MSR_INDEX_LIST check, assumes the kernel ++ * doesn't maintain MSR_IA32_VMX_PROCBASED_CTLS2, resulting in ++ * incorrect settings by QEMU for this MSR. ++ */ ++ for (i = 0; i < kvm_feature_msrs->nmsrs; i++) { ++ if (kvm_feature_msrs->indices[i] == MSR_IA32_VMX_PROCBASED_CTLS2) { ++ has_msr_vmx_procbased_ctls2 = true; ++ } ++ } + return 0; + } + +-- +2.33.0 + -- Gitee From b8882494b95775e34772b977d9e28227991bd385 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Wed, 27 Aug 2025 16:11:04 +0800 Subject: [PATCH 05/14] QEMU update to version 8.2.0-41 Signed-off-by: zhangpengrui --- ...rrect-DTE-field-for-interrupt-passth.patch | 46 ++++++++++++++ ...orrect-bitmask-to-set-capability-BAR.patch | 54 ++++++++++++++++ docs-about-emulation-Fix-broken-link.patch | 36 +++++++++++ ...ender-fix-qxl_unpack_chunks-chunk-si.patch | 61 +++++++++++++++++++ ...u-Assign-pci-id-0x1419-for-the-AMD-I.patch | 48 +++++++++++++++ ...irtio-fix-Werror-maybe-uninitialized.patch | 44 +++++++++++++ ...ow-error-message-when-postcopy-fails.patch | 43 +++++++++++++ qemu.spec | 23 ++++++- tcg-Reset-data_gen_ptr-correctly.patch | 46 ++++++++++++++ update-include-hw-xen-arch_hvm.h.patch | 37 +++++++++++ 10 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch create mode 100644 amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch create mode 100644 docs-about-emulation-Fix-broken-link.patch create mode 100644 hw-display-qxl-render-fix-qxl_unpack_chunks-chunk-si.patch create mode 100644 hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch create mode 100644 hw-virtio-fix-Werror-maybe-uninitialized.patch create mode 100644 migration-show-error-message-when-postcopy-fails.patch create mode 100644 tcg-Reset-data_gen_ptr-correctly.patch create mode 100644 update-include-hw-xen-arch_hvm.h.patch diff --git a/amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch b/amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch new file mode 100644 index 00000000..16e6a1de --- /dev/null +++ b/amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch @@ -0,0 +1,46 @@ +From 7f7a8b4cc084998f658def7697a17f4aa40eabcf Mon Sep 17 00:00:00 2001 +From: jiesong +Date: Tue, 19 Aug 2025 23:18:00 +0800 +Subject: [PATCH] amd_iommu: Use correct DTE field for interrupt passthrough + +Interrupt passthrough is determine by the bits 191,190,187-184. +These bits are part of the 3rd quad word (i.e. index 2) in DTE. Hence +replace dte[3] by dte[2]. + +Fixes: b44159fe ("x86_iommu/amd: Add interrupt remap support when VAPIC is not enabled") +Signed-off-by: default avatarSairaj Kodilkar +Reviewed-by: default avatarVasant Hegde +Message-Id: <20250207045354.27329-2-sarunkod@amd.com> +Reviewed-by: MST's avatarMichael S. Tsirkin +Signed-off-by: MST's avatarMichael S. Tsirkin +(cherry picked from commit 63dc0b86) +--- + hw/i386/amd_iommu.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c +index 12742b1433..4697864123 100644 +--- a/hw/i386/amd_iommu.c ++++ b/hw/i386/amd_iommu.c +@@ -1279,15 +1279,15 @@ static int amdvi_int_remap_msi(AMDVIState *iommu, + ret = -AMDVI_IR_ERR; + break; + case AMDVI_IOAPIC_INT_TYPE_NMI: +- pass = dte[3] & AMDVI_DEV_NMI_PASS_MASK; ++ pass = dte[2] & AMDVI_DEV_NMI_PASS_MASK; + trace_amdvi_ir_delivery_mode("nmi"); + break; + case AMDVI_IOAPIC_INT_TYPE_INIT: +- pass = dte[3] & AMDVI_DEV_INT_PASS_MASK; ++ pass = dte[2] & AMDVI_DEV_INT_PASS_MASK; + trace_amdvi_ir_delivery_mode("init"); + break; + case AMDVI_IOAPIC_INT_TYPE_EINT: +- pass = dte[3] & AMDVI_DEV_EINT_PASS_MASK; ++ pass = dte[2] & AMDVI_DEV_EINT_PASS_MASK; + trace_amdvi_ir_delivery_mode("eint"); + break; + default: +-- +2.33.0 + diff --git a/amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch b/amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch new file mode 100644 index 00000000..12449947 --- /dev/null +++ b/amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch @@ -0,0 +1,54 @@ +From 2566994410ffb38a754aa91619cc8533284e5f60 Mon Sep 17 00:00:00 2001 +From: jiesong +Date: Tue, 19 Aug 2025 23:04:21 +0800 +Subject: [PATCH] amd_iommu: Use correct bitmask to set capability BAR + +AMD IOMMU provides the base address of control registers through +IVRS table and PCI capability. Since this base address is of 64 bit, +use 32 bits mask (instead of 16 bits) to set BAR low and high. + +Fixes: d29a09ca ("hw/i386: Introduce AMD IOMMU") +Signed-off-by: default avatarSairaj Kodilkar +Reviewed-by: default avatarVasant Hegde +Message-Id: <20250207045354.27329-3-sarunkod@amd.com> +Reviewed-by: MST's avatarMichael S. Tsirkin +Signed-off-by: MST's avatarMichael S. Tsirkin +(cherry picked from commit 3684717b) +Signed-off-by: default avatarMichael Tokarev +--- + hw/i386/amd_iommu.c | 4 ++-- + hw/i386/amd_iommu.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c +index 12742b1433..77aee33b01 100644 +--- a/hw/i386/amd_iommu.c ++++ b/hw/i386/amd_iommu.c +@@ -1543,9 +1543,9 @@ static void amdvi_pci_realize(PCIDevice *pdev, Error **errp) + /* reset AMDVI specific capabilities, all r/o */ + pci_set_long(pdev->config + s->capab_offset, AMDVI_CAPAB_FEATURES); + pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_LOW, +- AMDVI_BASE_ADDR & ~(0xffff0000)); ++ AMDVI_BASE_ADDR & MAKE_64BIT_MASK(14, 18)); + pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_HIGH, +- (AMDVI_BASE_ADDR & ~(0xffff)) >> 16); ++ AMDVI_BASE_ADDR >> 32); + pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_RANGE, + 0xff000000); + pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_MISC, 0); +diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h +index c5065a3e27..555a7a5162 100644 +--- a/hw/i386/amd_iommu.h ++++ b/hw/i386/amd_iommu.h +@@ -185,7 +185,7 @@ + AMDVI_CAPAB_FLAG_HTTUNNEL | AMDVI_CAPAB_EFR_SUP) + + /* AMDVI default address */ +-#define AMDVI_BASE_ADDR 0xfed80000 ++#define AMDVI_BASE_ADDR 0xfed80000ULL + + /* page management constants */ + #define AMDVI_PAGE_SHIFT 12 +-- +2.33.0 + diff --git a/docs-about-emulation-Fix-broken-link.patch b/docs-about-emulation-Fix-broken-link.patch new file mode 100644 index 00000000..8563b743 --- /dev/null +++ b/docs-about-emulation-Fix-broken-link.patch @@ -0,0 +1,36 @@ +From 61af0f4d976a04fe8a334a99d2fd9c81a4ae28cf Mon Sep 17 00:00:00 2001 +From: houhaole_yewu +Date: Wed, 13 Aug 2025 14:39:16 +0800 +Subject: [PATCH] docs/about/emulation: Fix broken link semihosting link to + risc-v changed + +Signed-off-by: Santiago Monserrat Campanello +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2717 +Reviewed-by: Alistair Francis +Reviewed-by: Thomas Huth +Message-ID: <20250305102632.91376-1-santimonserr@gmail.com> +Signed-off-by: Alistair Francis +(cherry picked from commit 672cb29) +Signed-off-by: Michael Tokarev + +Signed-off-by: houhaole_yewu +--- + docs/about/emulation.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst +index a2eefe3f3f..cfe9379ef2 100644 +--- a/docs/about/emulation.rst ++++ b/docs/about/emulation.rst +@@ -185,7 +185,7 @@ for that architecture. + - https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD + * - RISC-V + - System and User-mode +- - https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc ++ - https://github.com/riscv-non-isa/riscv-semihosting/blob/main/riscv-semihosting.adoc + * - Xtensa + - System + - Tensilica ISS SIMCALL +-- +2.33.0 + diff --git a/hw-display-qxl-render-fix-qxl_unpack_chunks-chunk-si.patch b/hw-display-qxl-render-fix-qxl_unpack_chunks-chunk-si.patch new file mode 100644 index 00000000..02aa2fe1 --- /dev/null +++ b/hw-display-qxl-render-fix-qxl_unpack_chunks-chunk-si.patch @@ -0,0 +1,61 @@ +From 32c63cddf6865e0fd0ac981e013f378183fbcb2a Mon Sep 17 00:00:00 2001 +From: guping +Date: Fri, 1 Aug 2025 06:36:34 +0000 +Subject: [PATCH] hw/display/qxl-render: fix qxl_unpack_chunks() chunk size + calculation cherry-pick from 8e8cb3b5722babe7e7b597b3805bf09f24ed6979 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In case of multiple chunks, code in qxl_unpack_chunks() takes size of the +wrong (next in the chain) chunk, instead of using current chunk size. +This leads to wrong number of bytes being copied, and to crashes if next +chunk size is larger than the current one. + +Based on the code by Gao Yong. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1628 +Tested-by: Thaddeus Hogan thaddeus@thogan.com +Tested-by: Vadim Zeitlin vadim@wxwidgets.org +Signed-off-by: Michael Tokarev mjt@tls.msk.ru +Reviewed-by: Thomas Huth thuth@redhat.com +Message-ID: 20250221134856.478806-1-mjt@tls.msk.ru +Signed-off-by: Philippe Mathieu-Daudé philmd@linaro.org + +Signed-off-by: guping +--- + hw/display/qxl-render.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c +index ec99ec887a..7df961fcdb 100644 +--- a/hw/display/qxl-render.c ++++ b/hw/display/qxl-render.c +@@ -222,6 +222,7 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, + uint32_t max_chunks = 32; + size_t offset = 0; + size_t bytes; ++ QXLPHYSICAL next_chunk_phys = 0; + + for (;;) { + bytes = MIN(size - offset, chunk->data_size); +@@ -230,7 +231,15 @@ static void qxl_unpack_chunks(void *dest, size_t size, PCIQXLDevice *qxl, + if (offset == size) { + return; + } +- chunk = qxl_phys2virt(qxl, chunk->next_chunk, group_id, ++ next_chunk_phys = chunk->next_chunk; ++ /* fist time, only get the next chunk's data size */ ++ chunk = qxl_phys2virt(qxl, next_chunk_phys, group_id, ++ sizeof(QXLDataChunk)); ++ if (!chunk) { ++ return; ++ } ++ /* second time, check data size and get data */ ++ chunk = qxl_phys2virt(qxl, next_chunk_phys, group_id, + sizeof(QXLDataChunk) + chunk->data_size); + if (!chunk) { + return; +-- +2.33.0 + diff --git a/hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch b/hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch new file mode 100644 index 00000000..63925401 --- /dev/null +++ b/hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch @@ -0,0 +1,48 @@ +From 6bff3e6be5041c8379238e605fa78ccab4f4267b Mon Sep 17 00:00:00 2001 +From: jiesong +Date: Tue, 19 Aug 2025 21:54:11 +0800 +Subject: [PATCH] hw/i386/amd_iommu: Assign pci-id 0x1419 for the AMD IOMMU + device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, the QEMU-emulated AMD IOMMU device use PCI vendor id 0x1022 +(AMD) with device id zero (undefined). Eventhough this does not cause any +functional issue for AMD IOMMU driver since it normally uses information +in the ACPI IVRS table to probe and initialize the device per +recommendation in the AMD IOMMU specification, the device id zero causes +the Windows Device Manager utility to show the device as an unknown device. + +Since Windows only recognizes AMD IOMMU device with device id 0x1419 as +listed in the machine.inf file, modify the QEMU AMD IOMMU model to use +the id 0x1419 to avoid the issue. This advertise the IOMMU as the AMD +IOMMU device for Family 15h (Models 10h-1fh). + +Signed-off-by: default avatarSuravee Suthikulpanit +Message-Id: <20250325021140.5676-1-suravee.suthikulpanit@amd.com> +Reviewed-by: default avatarDaniel P. Berrangé +Reviewed-by: default avatarYan Vugenfirer +Reviewed-by: MST's avatarMichael S. Tsirkin +Signed-off-by: MST's avatarMichael S. Tsirkin +(cherry picked from commit 71925548) +Signed-off-by: default avatarMichael Tokarev +--- + hw/i386/amd_iommu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c +index 12742b1433..d64d06ec63 100644 +--- a/hw/i386/amd_iommu.c ++++ b/hw/i386/amd_iommu.c +@@ -1631,6 +1631,7 @@ static void amdvi_pci_class_init(ObjectClass *klass, void *data) + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_AMD; ++ k->device_id = 0x1419; + k->class_id = 0x0806; + k->realize = amdvi_pci_realize; + +-- +2.33.0 + diff --git a/hw-virtio-fix-Werror-maybe-uninitialized.patch b/hw-virtio-fix-Werror-maybe-uninitialized.patch new file mode 100644 index 00000000..37b6e14a --- /dev/null +++ b/hw-virtio-fix-Werror-maybe-uninitialized.patch @@ -0,0 +1,44 @@ +From ce68e103d1b7624b2950b72a06bb63d1396905cd Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 06:31:36 +0000 +Subject: [PATCH] hw/virtio: fix -Werror=maybe-uninitialized +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 3073c6b99557042476add4ddbcc8c834ae70fce5 + +hw/virtio: fix -Werror=maybe-uninitialized + +../hw/virtio/vhost-shadow-virtqueue.c:545:13: error: ‘r’ may be used uninitialized [-Werror=maybe-uninitialized] + +Set `r` to 0 at every loop, since we don't check vhost_svq_get_buf() +return value. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Stefano Garzarella + +Signed-off-by: guping +--- + hw/virtio/vhost-shadow-virtqueue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index fc5f408f77..3b2beaea24 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -526,10 +526,10 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq, + size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num) + { + size_t len = 0; +- uint32_t r; + + while (num--) { + int64_t start_us = g_get_monotonic_time(); ++ uint32_t r = 0; + + do { + if (vhost_svq_more_used(svq)) { +-- +2.33.0 + diff --git a/migration-show-error-message-when-postcopy-fails.patch b/migration-show-error-message-when-postcopy-fails.patch new file mode 100644 index 00000000..ae1621f8 --- /dev/null +++ b/migration-show-error-message-when-postcopy-fails.patch @@ -0,0 +1,43 @@ +From a2b046a39482e26ac200fdc42af3be195fdc5193 Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Thu, 14 Aug 2025 15:03:47 +0800 +Subject: [PATCH] migration: show error message when postcopy fails + MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The 'info migrate' command only shows the error message when the +migration state is 'failed'. When postcopy is used, however, +the 'postcopy-paused' state is used instead of 'failed', so we +must show the error message there too. + +Signed-off-by: Daniel P. Berrangé +Reviewed-by: Fabiano Rosas +Link: https://lore.kernel.org/qemu-devel/20250721133913.2914669-1-berrange@redhat.com +[line break to satisfy checkpatch] +Signed-off-by: Fabiano Rosas +Signed-off-by: dinglimin +--- + migration/migration-hmp-cmds.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c +index d6d5f373a1..9abbb38690 100644 +--- a/migration/migration-hmp-cmds.c ++++ b/migration/migration-hmp-cmds.c +@@ -73,7 +73,9 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) + if (info->has_status) { + monitor_printf(mon, "Migration status: %s", + MigrationStatus_str(info->status)); +- if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) { ++ if ((info->status == MIGRATION_STATUS_FAILED || ++ info->status == MIGRATION_STATUS_POSTCOPY_PAUSED) && ++ info->error_desc) { + monitor_printf(mon, " (%s)\n", info->error_desc); + } else { + monitor_printf(mon, "\n"); +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 7cd67a39..66ca2a92 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 40 +Release: 41 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1019,7 +1019,15 @@ Patch1002: hw-riscv-virt-acpi-build.c-Generate-SPCR-table.patch Patch1003: hw-riscv-virt-acpi-build.c-Add-SRAT-and-SLIT-ACPI-ta.patch Patch1004: plugins-loader-fix-deadlock-when-resetting-uninstall.patch Patch1005: smbios-Fix-buffer-overrun-when-using-path-option.patch - +Patch1006: migration-show-error-message-when-postcopy-fails.patch +Patch1007: docs-about-emulation-Fix-broken-link.patch +Patch1008: update-include-hw-xen-arch_hvm.h.patch +Patch1009: hw-display-qxl-render-fix-qxl_unpack_chunks-chunk-si.patch +Patch1010: hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch +Patch1011: amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch +Patch1012: amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch +Patch1013: tcg-Reset-data_gen_ptr-correctly.patch +Patch1014: hw-virtio-fix-Werror-maybe-uninitialized.patch BuildRequires: flex BuildRequires: gcc @@ -1618,6 +1626,17 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Wed Aug 27 2025 Pengrui Zhang - 11:8.2.0-41 +- migration: show error message when postcopy fails +- docs/about/emulation: Fix broken link +- update include/hw/xen/arch_hvm.h. +- hw/display/qxl-render: fix qxl_unpack_chunks() chunk size calculation +- hw/i386/amd_iommu: Assign pci-id 0x1419 for the AMD IOMMU device +- amd_iommu: Use correct bitmask to set capability BAR +- amd_iommu: Use correct DTE field for interrupt passthrough +- tcg: Reset data_gen_ptr correctly +- hw/virtio: fix -Werror=maybe-uninitialized + * Tue Aug 26 2025 Pengrui Zhang - 11:8.2.0-40 - target/i386/kvm: Refine VMX controls setting for backward compatibility - Bugfix: Correctly set vms->bootinfo.confidential in virtCCA senarios. diff --git a/tcg-Reset-data_gen_ptr-correctly.patch b/tcg-Reset-data_gen_ptr-correctly.patch new file mode 100644 index 00000000..bbde41c4 --- /dev/null +++ b/tcg-Reset-data_gen_ptr-correctly.patch @@ -0,0 +1,46 @@ +From e02a44d575158f46b05ba5e1bac463da2e5a1822 Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 06:08:28 +0000 +Subject: [PATCH] tcg: Reset data_gen_ptr correctly cherry-pick from + fbe5afdd30cdf428ee3f65d9bb8f9fdbbe4387bf + +This pointer needs to be reset after overflow just like +code_buf and code_ptr. + +Cc: qemu-stable@nongnu.org +Fixes: 57a269469db ("tcg: Infrastructure for managing constant pools") +Acked-by: Alistair Francis +Reviewed-by: Pierrick Bouvier +Reviewed-by: LIU Zhiwei +Signed-off-by: Richard Henderson +(cherry picked from commit a7cfd751fb269de4a93bf1658cb13911c7ac77cc) +Signed-off-by: Michael Tokarev + +Signed-off-by: guping +--- + tcg/tcg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 61fcf8597d..d4616b81e0 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -1428,7 +1428,6 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s) + goto retry; + } + qatomic_set(&s->code_gen_ptr, next); +- s->data_gen_ptr = NULL; + return tb; + } + +@@ -6126,6 +6125,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) + */ + s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr); + s->code_ptr = s->code_buf; ++ s->data_gen_ptr = NULL; + + #ifdef TCG_TARGET_NEED_LDST_LABELS + QSIMPLEQ_INIT(&s->ldst_labels); +-- +2.33.0 + diff --git a/update-include-hw-xen-arch_hvm.h.patch b/update-include-hw-xen-arch_hvm.h.patch new file mode 100644 index 00000000..6318eab8 --- /dev/null +++ b/update-include-hw-xen-arch_hvm.h.patch @@ -0,0 +1,37 @@ +From 33cd1fa9235fcf0f773e4c9db2f323d773d6af08 Mon Sep 17 00:00:00 2001 +From: houhaole_yewu +Date: Wed, 13 Aug 2025 07:51:45 +0000 +Subject: [PATCH] update include/hw/xen/arch_hvm.h. hw/xen/hvm: Fix Aarch64 + typo There is no TARGET_ARM_64 definition. Luckily enough, when + TARGET_AARCH64 is defined, TARGET_ARM also is. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 733766c ("hw/arm: introduce xenpvh machine") +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Pierrick Bouvier +Reviewed-by: Richard Henderson +Message-Id: <20250305153929.43687-2-philmd@linaro.org> +(cherry picked from commit 3a11b65) +Signed-off-by: Michael Tokarev + +Signed-off-by: houhaole_yewu +--- + include/hw/xen/arch_hvm.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/hw/xen/arch_hvm.h b/include/hw/xen/arch_hvm.h +index c7c515220d..df39c819c8 100644 +--- a/include/hw/xen/arch_hvm.h ++++ b/include/hw/xen/arch_hvm.h +@@ -1,5 +1,5 @@ + #if defined(TARGET_I386) || defined(TARGET_X86_64) + #include "hw/i386/xen_arch_hvm.h" +-#elif defined(TARGET_ARM) || defined(TARGET_ARM_64) ++#elif defined(TARGET_ARM) || defined(TARGET_AARCH64) + #include "hw/arm/xen_arch_hvm.h" + #endif +-- +2.33.0 + -- Gitee From 71b26c136c4d672296bdff05614793e6adc86eca Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Thu, 28 Aug 2025 20:51:42 +0800 Subject: [PATCH 06/14] QEMU update to version 8.2.0-42 Signed-off-by: zhangpengrui --- ...-Werror-maybe-uninitialized-false-po.patch | 35 ++++++++++++ ...or-maybe-uninitialized-false-positiv.patch | 42 +++++++++++++++ ...r-maybe-uninitialized-false-positive.patch | 38 +++++++++++++ ...ror-maybe-uninitialized-false-positi.patch | 37 +++++++++++++ ...rror-maybe-uninitialized-false-posit.patch | 37 +++++++++++++ ...r-maybe-uninitialized-false-positive.patch | 35 ++++++++++++ ...-queue-depth-validation-in-img_bench.patch | 35 ++++++++++++ qemu.spec | 21 +++++++- ...error-maybe-uninitialized-false-posi.patch | 54 +++++++++++++++++++ 9 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 block-mirror-fix-Werror-maybe-uninitialized-false-po.patch create mode 100644 hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch create mode 100644 hw-qxl-fix-Werror-maybe-uninitialized-false-positive.patch create mode 100644 hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch create mode 100644 migration-fix-Werror-maybe-uninitialized-false-posit.patch create mode 100644 nbd-fix-Werror-maybe-uninitialized-false-positive.patch create mode 100644 qemu-img-improve-queue-depth-validation-in-img_bench.patch create mode 100644 util-timer-fix-Werror-maybe-uninitialized-false-posi.patch diff --git a/block-mirror-fix-Werror-maybe-uninitialized-false-po.patch b/block-mirror-fix-Werror-maybe-uninitialized-false-po.patch new file mode 100644 index 00000000..b6554bd0 --- /dev/null +++ b/block-mirror-fix-Werror-maybe-uninitialized-false-po.patch @@ -0,0 +1,35 @@ +From 452589397a664fb216fb527140a140d88f23191a Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 07:07:53 +0000 +Subject: [PATCH] block/mirror: fix -Werror=maybe-uninitialized false-positive + cherry-pick from ba11c88d7a3b7c4d40afec4b84e0660815b2e2d7 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../block/mirror.c:1066:22: error: ‘iostatus’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Reviewed-by: Vladimir Sementsov-Ogievskiy + +Signed-off-by: guping +--- + block/mirror.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/mirror.c b/block/mirror.c +index 20b3e8e5d8..2b48e6b09d 100644 +--- a/block/mirror.c ++++ b/block/mirror.c +@@ -934,7 +934,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) + MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque; + BlockDriverState *target_bs = blk_bs(s->target); + bool need_drain = true; +- BlockDeviceIoStatus iostatus; ++ BlockDeviceIoStatus iostatus = BLOCK_DEVICE_IO_STATUS__MAX; + int64_t length; + int64_t target_length; + BlockDriverInfo bdi; +-- +2.33.0 + diff --git a/hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch b/hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch new file mode 100644 index 00000000..25435ee3 --- /dev/null +++ b/hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch @@ -0,0 +1,42 @@ +From 4d8c015cbe58fca5f562d3d94f14ba132a4c5d17 Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 07:30:59 +0000 +Subject: [PATCH] hw/ahci: fix -Werror=maybe-uninitialized false-positive + cherry-pick from 7d6e63d982004abac0690e0ca57946fb330d2e70 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../hw/ide/ahci.c:989:58: error: ‘tbl_entry_size’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Reviewed-by: Manos Pitsidianakis + +Signed-off-by: guping +--- + 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 8062e1743c..45b947bcfe 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -946,7 +946,6 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, + uint64_t sum = 0; + int off_idx = -1; + int64_t off_pos = -1; +- int tbl_entry_size; + IDEBus *bus = &ad->port; + BusState *qbus = BUS(bus); + +@@ -974,6 +973,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, + /* Get entries in the PRDT, init a qemu sglist accordingly */ + if (prdtl > 0) { + AHCI_SG *tbl = (AHCI_SG *)prdt; ++ int tbl_entry_size = 0; + sum = 0; + for (i = 0; i < prdtl; i++) { + tbl_entry_size = prdt_tbl_entry_size(&tbl[i]); +-- +2.33.0 + diff --git a/hw-qxl-fix-Werror-maybe-uninitialized-false-positive.patch b/hw-qxl-fix-Werror-maybe-uninitialized-false-positive.patch new file mode 100644 index 00000000..45c20772 --- /dev/null +++ b/hw-qxl-fix-Werror-maybe-uninitialized-false-positive.patch @@ -0,0 +1,38 @@ +From 04c25fbea849944f8062963ab18e4e97c30bca99 Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 06:49:09 +0000 +Subject: [PATCH] hw/qxl: fix -Werror=maybe-uninitialized false-positives + cherry-pick from 0a0744f6d868fc2d809d8fac7d25dea2272a1105 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../hw/display/qxl.c:1352:5: error: ‘pci_region’ may be used uninitialized [-Werror=maybe-uninitialized] +../hw/display/qxl.c:1365:22: error: ‘pci_start’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Reviewed-by: Manos Pitsidianakis + +Signed-off-by: guping +--- + hw/display/qxl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 7bb00d68f5..ea028a27f7 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1301,8 +1301,8 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + }; + uint64_t guest_start; + uint64_t guest_end; +- int pci_region; +- pcibus_t pci_start; ++ int pci_region = -1; ++ pcibus_t pci_start = PCI_BAR_UNMAPPED; + pcibus_t pci_end; + MemoryRegion *mr; + intptr_t virt_start; +-- +2.33.0 + diff --git a/hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch b/hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch new file mode 100644 index 00000000..cf69b1d4 --- /dev/null +++ b/hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch @@ -0,0 +1,37 @@ +From 96f08733674735bc4017f8aee4bb4ad45e8d8bbb Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 07:36:55 +0000 +Subject: [PATCH] hw/sdhci: fix -Werror=maybe-uninitialized false-positive + cherry-pick from ea34d1dd968956ec418c4278b39b6c44bb606d9c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../hw/sd/sdhci.c:846:16: error: ‘res’ may be used uninitialized [-Werror=maybe-uninitialized] + +False-positive, because "length" is non-null. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Alex Bennée + +Signed-off-by: guping +--- + hw/sd/sdhci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c +index e95ea34895..b55dbbb414 100644 +--- a/hw/sd/sdhci.c ++++ b/hw/sd/sdhci.c +@@ -747,7 +747,7 @@ static void sdhci_do_adma(SDHCIState *s) + const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK; + const MemTxAttrs attrs = { .memory = true }; + ADMADescr dscr = {}; +- MemTxResult res; ++ MemTxResult res = MEMTX_ERROR; + int i; + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) { +-- +2.33.0 + diff --git a/migration-fix-Werror-maybe-uninitialized-false-posit.patch b/migration-fix-Werror-maybe-uninitialized-false-posit.patch new file mode 100644 index 00000000..ad567b51 --- /dev/null +++ b/migration-fix-Werror-maybe-uninitialized-false-posit.patch @@ -0,0 +1,37 @@ +From 44c3dc67e16e6e5d814fb50e3f1056f8784d69fc Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 07:52:59 +0000 +Subject: [PATCH] migration: fix -Werror=maybe-uninitialized false-positive + cherry-pick from 85f99eb2cb9100dcabb43e9380811040e88642d8 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../migration/ram.c:1873:23: error: ‘dirty’ may be used uninitialized [-Werror=maybe-uninitialized] + +When 'block' != NULL, 'dirty' is initialized. + +Signed-off-by: Marc-André Lureau +Acked-by: Peter Xu + +Signed-off-by: guping +--- + migration/ram.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/ram.c b/migration/ram.c +index e6baecf143..028b1ebb6e 100644 +--- a/migration/ram.c ++++ b/migration/ram.c +@@ -1956,7 +1956,7 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) + { + RAMBlock *block; + ram_addr_t offset; +- bool dirty; ++ bool dirty = false; + + do { + block = unqueue_page(rs, &offset); +-- +2.33.0 + diff --git a/nbd-fix-Werror-maybe-uninitialized-false-positive.patch b/nbd-fix-Werror-maybe-uninitialized-false-positive.patch new file mode 100644 index 00000000..89ac9e5a --- /dev/null +++ b/nbd-fix-Werror-maybe-uninitialized-false-positive.patch @@ -0,0 +1,35 @@ +From 9db2be4f194626aef533e7050d7fe7151cda175e Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 06:51:33 +0000 +Subject: [PATCH] nbd: fix -Werror=maybe-uninitialized false-positive + cherry-pick from 73ce9bbf8a5242e2d1da76cca7ef031315cad721 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../nbd/client-connection.c:419:8: error: ‘wait_co’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Reviewed-by: Eric Blake + +Signed-off-by: guping +--- + nbd/client-connection.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nbd/client-connection.c b/nbd/client-connection.c +index f9da67c87e..b11e266807 100644 +--- a/nbd/client-connection.c ++++ b/nbd/client-connection.c +@@ -410,7 +410,7 @@ nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info, + */ + void nbd_co_establish_connection_cancel(NBDClientConnection *conn) + { +- Coroutine *wait_co; ++ Coroutine *wait_co = NULL; + + WITH_QEMU_LOCK_GUARD(&conn->mutex) { + wait_co = g_steal_pointer(&conn->wait_co); +-- +2.33.0 + diff --git a/qemu-img-improve-queue-depth-validation-in-img_bench.patch b/qemu-img-improve-queue-depth-validation-in-img_bench.patch new file mode 100644 index 00000000..718751c5 --- /dev/null +++ b/qemu-img-improve-queue-depth-validation-in-img_bench.patch @@ -0,0 +1,35 @@ +From 7fe8276cb06131266495f0a7bebbcfa1d295283b Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Thu, 21 Aug 2025 11:17:35 +0800 +Subject: [PATCH] qemu-img: improve queue depth validation in img_bench + +This error was discovered by fuzzing qemu-img. + +Currently, running `qemu-img bench -d 0` in img_bench is allowed, +which is a pointless operation and causes qemu-img to hang. + +Signed-off-by: Denis Rastyogin +Message-ID: <20250327162423.25154-5-gerben@altlinux.org> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +Signed-off-by: dinglimin +--- + qemu-img.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 49d914c9c4..ca202e2b6f 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -4601,7 +4601,7 @@ static int img_bench(int argc, char **argv) + { + unsigned long res; + +- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) { ++ if (qemu_strtoul(optarg, NULL, 0, &res) <= 0 || res > INT_MAX) { + error_report("Invalid queue depth specified"); + return 1; + } +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 66ca2a92..2198ece5 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 41 +Release: 42 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1028,6 +1028,14 @@ Patch1011: amd_iommu-Use-correct-bitmask-to-set-capability-BAR.patch Patch1012: amd_iommu-Use-correct-DTE-field-for-interrupt-passth.patch Patch1013: tcg-Reset-data_gen_ptr-correctly.patch Patch1014: hw-virtio-fix-Werror-maybe-uninitialized.patch +Patch1015: util-timer-fix-Werror-maybe-uninitialized-false-posi.patch +Patch1016: hw-qxl-fix-Werror-maybe-uninitialized-false-positive.patch +Patch1017: nbd-fix-Werror-maybe-uninitialized-false-positive.patch +Patch1018: block-mirror-fix-Werror-maybe-uninitialized-false-po.patch +Patch1019: hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch +Patch1020: hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch +Patch1021: migration-fix-Werror-maybe-uninitialized-false-posit.patch +Patch1022: qemu-img-improve-queue-depth-validation-in-img_bench.patch BuildRequires: flex BuildRequires: gcc @@ -1626,6 +1634,16 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Thu Aug 28 2025 Pengrui Zhang - 11:8.2.0-42 +- util/timer: fix -Werror=maybe-uninitialized false-positive +- hw/qxl: fix -Werror=maybe-uninitialized false-positives +- nbd: fix -Werror=maybe-uninitialized false-positive +- block/mirror: fix -Werror=maybe-uninitialized false-positive +- hw/ahci: fix -Werror=maybe-uninitialized false-positive +- hw/sdhci: fix -Werror=maybe-uninitialized false-positive +- migration: fix -Werror=maybe-uninitialized false-positive +- qemu-img: improve queue depth validation in img_bench + * Wed Aug 27 2025 Pengrui Zhang - 11:8.2.0-41 - migration: show error message when postcopy fails - docs/about/emulation: Fix broken link @@ -1766,6 +1784,7 @@ getent passwd qemu >/dev/null || \ - linux-headers: Add KVM Arm RME definitions to Linux headers - Bugfix: Fix compile error in aarch32. +<<<<<<< HEAD * Fri Jul 25 2025 Pengrui Zhang - 11:8.2.0-38 - hw/audio/cs4231a: fix assertion error in isa_bus_get_irq - block/blkio: Make s->mem_region_alignment be 64 bits diff --git a/util-timer-fix-Werror-maybe-uninitialized-false-posi.patch b/util-timer-fix-Werror-maybe-uninitialized-false-posi.patch new file mode 100644 index 00000000..127cbbd6 --- /dev/null +++ b/util-timer-fix-Werror-maybe-uninitialized-false-posi.patch @@ -0,0 +1,54 @@ +From 44e5ec047afd9dd12b843e76075222f2be9666f9 Mon Sep 17 00:00:00 2001 +From: guping +Date: Thu, 21 Aug 2025 06:41:19 +0000 +Subject: [PATCH] util/timer: fix -Werror=maybe-uninitialized false-positive + cherry-pick from 5491295fa5da5e424f0972ddf709412197020747 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../util/qemu-timer.c:198:24: error: ‘expire_time’ may be used uninitialized [-Werror=maybe-uninitialized] +../util/qemu-timer.c:476:8: error: ‘rearm’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Reviewed-by: Manos Pitsidianakis + +Signed-off-by: guping +--- + util/qemu-timer.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/util/qemu-timer.c b/util/qemu-timer.c +index dc891cc557..cd1b3b83f4 100644 +--- a/util/qemu-timer.c ++++ b/util/qemu-timer.c +@@ -251,7 +251,7 @@ bool qemu_clock_has_timers(QEMUClockType type) + + bool timerlist_expired(QEMUTimerList *timer_list) + { +- int64_t expire_time; ++ int64_t expire_time = 0; + + if (!qatomic_read(&timer_list->active_timers)) { + return false; +@@ -281,7 +281,7 @@ bool qemu_clock_expired(QEMUClockType type) + int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) + { + int64_t delta; +- int64_t expire_time; ++ int64_t expire_time = 0; + + if (!qatomic_read(&timer_list->active_timers)) { + return -1; +@@ -530,7 +530,7 @@ void timer_mod_ns(QEMUTimer *ts, int64_t expire_time) + void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time) + { + QEMUTimerList *timer_list = ts->timer_list; +- bool rearm; ++ bool rearm = false; + + WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) { + if (ts->expire_time == -1 || ts->expire_time > expire_time) { +-- +2.33.0 + -- Gitee From 8950daa0248ae76428a764285e8e9edfd0d92edc Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Sat, 30 Aug 2025 10:35:36 +0800 Subject: [PATCH 07/14] QEMU update to version 8.2.0-43 Signed-off-by: zhangpengrui --- ...-kvm-Make-kvm_has_guest_debug-static.patch | 37 +++ ...-Werror-maybe-uninitialized-false-po.patch | 49 ++++ ...p-MDTS-value-for-internal-limitation.patch | 43 ++++ ...ips-Fix-flash-erase-assert-in-dual-p.patch | 41 ++++ ...x10_version-filtered-when-prefix-is-.patch | 50 ++++ ...ror-maybe-uninitialized-false-posit2.patch | 61 +++++ ...ision-by-zero-in-bench_cb-for-zero-s.patch | 45 ++++ ...rify-handling-of-commas-in-options-p.patch | 76 ++++++ qemu.spec | 42 +++- ...Include-missing-hw-core-cpu.h-header.patch | 40 ++++ ...ncluding-missing-exec-exec-all.h-hea.patch | 41 ++++ ...AVX512-state-when-AVX10-is-supported.patch | 54 +++++ ...6-Add-feature-dependencies-for-AVX10.patch | 87 +++++++ ...386-Introduce-GraniteRapids-v2-model.patch | 57 +++++ ...AVX10-feature-and-AVX10-version-prop.patch | 222 ++++++++++++++++++ ...i386-add-CPUID.24-features-for-AVX10.patch | 89 +++++++ target-i386-add-avx-vnni-int16-feature.patch | 37 +++ ...set-correct-supported-XCR0-features-.patch | 48 ++++ ...ot-rely-on-ExtSaveArea-for-accelerat.patch | 115 +++++++++ ...rn-bool-from-x86_cpu_filter_features.patch | 81 +++++++ 20 files changed, 1314 insertions(+), 1 deletion(-) create mode 100644 accel-kvm-Make-kvm_has_guest_debug-static.patch create mode 100644 block-stream-fix-Werror-maybe-uninitialized-false-po.patch create mode 100644 hw-nvme-cap-MDTS-value-for-internal-limitation.patch create mode 100644 hw-ssi-xilinx_spips-Fix-flash-erase-assert-in-dual-p.patch create mode 100644 i386-cpu-Mark-avx10_version-filtered-when-prefix-is-.patch create mode 100644 migration-fix-Werror-maybe-uninitialized-false-posit2.patch create mode 100644 qemu-img-fix-division-by-zero-in-bench_cb-for-zero-s.patch create mode 100644 qemu-options-Clarify-handling-of-commas-in-options-p.patch create mode 100644 system-qtest-Include-missing-hw-core-cpu.h-header.patch create mode 100644 target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch create mode 100644 target-i386-Add-AVX512-state-when-AVX10-is-supported.patch create mode 100644 target-i386-Add-feature-dependencies-for-AVX10.patch create mode 100644 target-i386-Introduce-GraniteRapids-v2-model.patch create mode 100644 target-i386-add-AVX10-feature-and-AVX10-version-prop.patch create mode 100644 target-i386-add-CPUID.24-features-for-AVX10.patch create mode 100644 target-i386-add-avx-vnni-int16-feature.patch create mode 100644 target-i386-cpu-set-correct-supported-XCR0-features-.patch create mode 100644 target-i386-do-not-rely-on-ExtSaveArea-for-accelerat.patch create mode 100644 target-i386-return-bool-from-x86_cpu_filter_features.patch diff --git a/accel-kvm-Make-kvm_has_guest_debug-static.patch b/accel-kvm-Make-kvm_has_guest_debug-static.patch new file mode 100644 index 00000000..38fb3510 --- /dev/null +++ b/accel-kvm-Make-kvm_has_guest_debug-static.patch @@ -0,0 +1,37 @@ +From ead624df30b907caceef76e55f891d262fd1e8b3 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Tue, 19 Dec 2023 17:57:38 +0000 +Subject: [PATCH] accel/kvm: Make kvm_has_guest_debug static +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This variable is not used or declared outside kvm-all.c. + +Backport from QEMU official community: 16617c3cba55 + +Signed-off-by: Richard Henderson +Reviewed-by: Gavin Shan +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Philippe Mathieu-Daudé +Signed-off-by: Peter Maydell +--- + accel/kvm/kvm-all.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index f472fc4f69..6e3a3f14a1 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -104,7 +104,7 @@ bool kvm_readonly_mem_allowed; + bool kvm_vm_attributes_allowed; + bool kvm_msi_use_devid; + bool kvm_csv3_allowed; +-bool kvm_has_guest_debug; ++static bool kvm_has_guest_debug; + static int kvm_sstep_flags; + static bool kvm_immediate_exit; + static hwaddr kvm_max_slot_size = ~0; +-- +2.33.0 + diff --git a/block-stream-fix-Werror-maybe-uninitialized-false-po.patch b/block-stream-fix-Werror-maybe-uninitialized-false-po.patch new file mode 100644 index 00000000..75c83321 --- /dev/null +++ b/block-stream-fix-Werror-maybe-uninitialized-false-po.patch @@ -0,0 +1,49 @@ +From b1c05b06211be42f97b506beacc7b347cd600e23 Mon Sep 17 00:00:00 2001 +From: guping +Date: Mon, 25 Aug 2025 10:20:30 +0000 +Subject: [PATCH] block/stream: fix -Werror=maybe-uninitialized false-positives + cherry-pick from ce2a0ef65c3bb857985cd4b9c1f2145c81f2cdec +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +../block/stream.c:193:19: error: ‘unfiltered_bs’ may be used uninitialized [-Werror=maybe-uninitialized] +../block/stream.c:176:5: error: ‘len’ may be used uninitialized [-Werror=maybe-uninitialized] +trace/trace-block.h:906:9: error: ‘ret’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Acked-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Manos Pitsidianakis + +Signed-off-by: guping +--- + block/stream.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/block/stream.c b/block/stream.c +index 01fe7c0f16..421ef5c729 100644 +--- a/block/stream.c ++++ b/block/stream.c +@@ -149,8 +149,8 @@ static void stream_clean(Job *job) + static int coroutine_fn stream_run(Job *job, Error **errp) + { + StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); +- BlockDriverState *unfiltered_bs; +- int64_t len; ++ BlockDriverState *unfiltered_bs = NULL; ++ int64_t len = -1; + int64_t offset = 0; + int error = 0; + int64_t n = 0; /* bytes */ +@@ -171,7 +171,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp) + + for ( ; offset < len; offset += n) { + bool copy; +- int ret; ++ int ret = -1; + + /* Note that even when no rate limit is applied we need to yield + * with no pending I/O here so that bdrv_drain_all() returns. +-- +2.33.0 + diff --git a/hw-nvme-cap-MDTS-value-for-internal-limitation.patch b/hw-nvme-cap-MDTS-value-for-internal-limitation.patch new file mode 100644 index 00000000..08d41cfd --- /dev/null +++ b/hw-nvme-cap-MDTS-value-for-internal-limitation.patch @@ -0,0 +1,43 @@ +From 312cbe919b94565dc54c9c6189cea4d72797d514 Mon Sep 17 00:00:00 2001 +From: guping +Date: Tue, 26 Aug 2025 02:13:17 +0000 +Subject: [PATCH] hw/nvme: cap MDTS value for internal limitation cherry-pick + from 53493c1f836f4dda90a6b5f2fb3d9264918c6871 + +The emulated device had let the user set whatever max transfers size +they wanted, including no limit. However the device does have an +internal limit of 1024 segments. NVMe doesn't report max segments, +though. This is implicitly inferred based on the MDTS and MPSMIN values. + +IOV_MAX is currently 1024 which 4k PRPs can exceed with 2MB transfers. +Don't allow MDTS values that can exceed this, otherwise users risk +seeing "internal error" status to their otherwise protocol compliant +commands. + +Signed-off-by: Keith Busch +Signed-off-by: Klaus Jensen + +Signed-off-by: guping +--- + hw/nvme/ctrl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c +index 6fc2a64b0e..e293496ac7 100644 +--- a/hw/nvme/ctrl.c ++++ b/hw/nvme/ctrl.c +@@ -7816,6 +7816,11 @@ static bool nvme_check_params(NvmeCtrl *n, Error **errp) + host_memory_backend_set_mapped(n->pmr.dev, true); + } + ++ if (!n->params.mdts || ((1 << n->params.mdts) + 1) > IOV_MAX) { ++ error_setg(errp, "mdts exceeds IOV_MAX"); ++ return false; ++ } ++ + if (n->params.zasl > n->params.mdts) { + error_setg(errp, "zoned.zasl (Zone Append Size Limit) must be less " + "than or equal to mdts (Maximum Data Transfer Size)"); +-- +2.33.0 + diff --git a/hw-ssi-xilinx_spips-Fix-flash-erase-assert-in-dual-p.patch b/hw-ssi-xilinx_spips-Fix-flash-erase-assert-in-dual-p.patch new file mode 100644 index 00000000..18b31668 --- /dev/null +++ b/hw-ssi-xilinx_spips-Fix-flash-erase-assert-in-dual-p.patch @@ -0,0 +1,41 @@ +From cb2311054c27a95460267a69140606194840b51b Mon Sep 17 00:00:00 2001 +From: guping +Date: Mon, 25 Aug 2025 10:44:05 +0000 +Subject: [PATCH] hw/ssi/xilinx_spips: Fix flash erase assert in dual parallel + configuration cherry-pick from a8cc14435e675e86cba9afce8aa5e098b2e43ff4 + +Ensure that the FIFO is checked for emptiness before popping data +from it. Previously, the code directly popped the data from the FIFO +without checking, which could cause an assertion failure: + +../util/fifo8.c:67: fifo8_pop: Assertion `fifo->num > 0' failed. + +Signed-off-by: Shiva sagar Myana +Message-id: 20240924112035.1320865-1-Shivasagar.Myana@amd.com +Reviewed-by: Francisco Iglesias +[PMM: tweaked commit message] +Signed-off-by: Peter Maydell + +Signed-off-by: guping +--- + hw/ssi/xilinx_spips.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c +index 0bdfad7e2e..67dd00b434 100644 +--- a/hw/ssi/xilinx_spips.c ++++ b/hw/ssi/xilinx_spips.c +@@ -620,7 +620,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) + } else if (s->snoop_state == SNOOP_STRIPING || + s->snoop_state == SNOOP_NONE) { + for (i = 0; i < num_effective_busses(s); ++i) { +- tx_rx[i] = fifo8_pop(&s->tx_fifo); ++ if (!fifo8_is_empty(&s->tx_fifo)) { ++ tx_rx[i] = fifo8_pop(&s->tx_fifo); ++ } + } + stripe8(tx_rx, num_effective_busses(s), false); + } else if (s->snoop_state >= SNOOP_ADDR) { +-- +2.33.0 + diff --git a/i386-cpu-Mark-avx10_version-filtered-when-prefix-is-.patch b/i386-cpu-Mark-avx10_version-filtered-when-prefix-is-.patch new file mode 100644 index 00000000..ca4632ac --- /dev/null +++ b/i386-cpu-Mark-avx10_version-filtered-when-prefix-is-.patch @@ -0,0 +1,50 @@ +From 02b85f8f47e8670bd4b105c23912ea911d009ec5 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 6 Nov 2024 11:07:18 +0800 +Subject: [PATCH 09/10] i386/cpu: Mark avx10_version filtered when prefix is + NULL + +commit cf4c263551886964c5d58bd7b675b13fd497b402 upstream. + +In x86_cpu_filter_features(), if host doesn't support AVX10, the +configured avx10_version should be marked as filtered regardless of +whether prefix is NULL or not. + +Check prefix before warn_report() instead of checking for +have_filtered_features. + +Intel-SIG: commit cf4c26355188 i386/cpu: Mark avx10_version filtered when prefix is NULL. +GNR AVX10.1 backporting + +Cc: qemu-stable@nongnu.org +Fixes: commit bccfb846fd52 ("target/i386: add AVX10 feature and AVX10 version property") +Signed-off-by: Zhao Liu +Reviewed-by: Tao Su +Link: https://lore.kernel.org/r/20241106030728.553238-2-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 7b969a4447..eff23af452 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7816,8 +7816,10 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) + env->avx10_version = version; + have_filtered_features = true; + } +- } else if (env->avx10_version && prefix) { +- warn_report("%s: avx10.%d.", prefix, env->avx10_version); ++ } else if (env->avx10_version) { ++ if (prefix) { ++ warn_report("%s: avx10.%d.", prefix, env->avx10_version); ++ } + have_filtered_features = true; + } + +-- +2.33.0 + diff --git a/migration-fix-Werror-maybe-uninitialized-false-posit2.patch b/migration-fix-Werror-maybe-uninitialized-false-posit2.patch new file mode 100644 index 00000000..9145f5d6 --- /dev/null +++ b/migration-fix-Werror-maybe-uninitialized-false-posit2.patch @@ -0,0 +1,61 @@ +From 6f166f000e6913a8926ab03e9a4e0a05457d6963 Mon Sep 17 00:00:00 2001 +From: guping +Date: Mon, 25 Aug 2025 18:28:37 +0800 +Subject: [PATCH] migration: fix -Werror=maybe-uninitialized false-positives +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 7cea863719f83b2489e939e9f5a9acce060ec21d + +migration: fix -Werror=maybe-uninitialized false-positives + +../migration/dirtyrate.c:186:5: error: ‘records’ may be used uninitialized [-Werror=maybe-uninitialized] +../migration/dirtyrate.c:168:12: error: ‘gen_id’ may be used uninitialized [-Werror=maybe-uninitialized] +../migration/migration.c:2273:5: error: ‘file’ may be used uninitialized [-Werror=maybe-uninitialized] + +Signed-off-by: Marc-André Lureau +Acked-by: Peter Xu +Reviewed-by: Hyman Huang + +Signed-off-by: guping +--- + migration/dirtyrate.c | 4 ++-- + migration/migration.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c +index 036ac017fc..ffb1ed868d 100644 +--- a/migration/dirtyrate.c ++++ b/migration/dirtyrate.c +@@ -145,12 +145,12 @@ int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms, + unsigned int flag, + bool one_shot) + { +- DirtyPageRecord *records; ++ DirtyPageRecord *records = NULL; + int64_t init_time_ms; + int64_t duration; + int64_t dirtyrate; + int i = 0; +- unsigned int gen_id; ++ unsigned int gen_id = 0; + + retry: + init_time_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); +diff --git a/migration/migration.c b/migration/migration.c +index 526f926b79..eba3f9d17d 100644 +--- a/migration/migration.c ++++ b/migration/migration.c +@@ -2181,7 +2181,7 @@ static bool migrate_handle_rp_resume_ack(MigrationState *s, + */ + static void migration_release_dst_files(MigrationState *ms) + { +- QEMUFile *file; ++ QEMUFile *file = NULL; + + WITH_QEMU_LOCK_GUARD(&ms->qemu_file_lock) { + /* +-- +2.33.0 + diff --git a/qemu-img-fix-division-by-zero-in-bench_cb-for-zero-s.patch b/qemu-img-fix-division-by-zero-in-bench_cb-for-zero-s.patch new file mode 100644 index 00000000..d9bbb08c --- /dev/null +++ b/qemu-img-fix-division-by-zero-in-bench_cb-for-zero-s.patch @@ -0,0 +1,45 @@ +From d745a8f1717b9c666a67ea299a48050b70605780 Mon Sep 17 00:00:00 2001 +From: dinglimin +Date: Thu, 21 Aug 2025 12:20:47 +0800 +Subject: [PATCH] qemu-img: fix division by zero in bench_cb() for zero-sized + images + +This error was discovered by fuzzing qemu-img. + +This commit fixes a division by zero error in the bench_cb() function +that occurs when using the bench command with a zero-sized image. + +The issue arises because b->image_size can be zero, leading to a +division by zero in the modulo operation (b->offset %= b->image_size). +This patch adds a check for b->image_size == 0 and resets b->offset +to 0 in such cases, preventing the error. + +Signed-off-by: Denis Rastyogin +Message-ID: <20250318101933.255617-1-gerben@altlinux.org> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +Signed-off-by: dinglimin +--- + qemu-img.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 49d914c9c4..685beee06b 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -4522,7 +4522,11 @@ static void bench_cb(void *opaque, int ret) + */ + b->in_flight++; + b->offset += b->step; +- b->offset %= b->image_size; ++ if (b->image_size == 0) { ++ b->offset = 0; ++ } else { ++ b->offset %= b->image_size; ++ } + if (b->write) { + acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b); + } else { +-- +2.33.0 + diff --git a/qemu-options-Clarify-handling-of-commas-in-options-p.patch b/qemu-options-Clarify-handling-of-commas-in-options-p.patch new file mode 100644 index 00000000..59662923 --- /dev/null +++ b/qemu-options-Clarify-handling-of-commas-in-options-p.patch @@ -0,0 +1,76 @@ +From 7223363e347095fc124e7bc1a78a25fc5711bce9 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 13 Dec 2023 22:17:07 +0800 +Subject: [PATCH] qemu-options: Clarify handling of commas in options + parameters + +Provide explicit guidance on dealing with option parameters as arbitrary +strings containing commas, such as in "file=my,file" and "string=a,b". The +updated documentation emphasizes the need to double commas when they +appear within such parameters. + +Backport from QEMU official community: fd49b2153ed2 + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1839 +Signed-off-by: Yihuan Pan +Message-ID: <20231213141706.629833-2-xun794@gmail.com> +Signed-off-by: Thomas Huth +--- + docs/system/invocation.rst | 5 +++++ + docs/system/qemu-manpage.rst | 5 +++++ + qemu-options.hx | 4 ++++ + 3 files changed, 14 insertions(+) + +diff --git a/docs/system/invocation.rst b/docs/system/invocation.rst +index 4ba38fc23d..14b7db1c10 100644 +--- a/docs/system/invocation.rst ++++ b/docs/system/invocation.rst +@@ -10,6 +10,11 @@ Invocation + disk_image is a raw hard disk image for IDE hard disk 0. Some targets do + not need a disk image. + ++When dealing with options parameters as arbitrary strings containing ++commas, such as in "file=my,file" and "string=a,b", it's necessary to ++double the commas. For instance,"-fw_cfg name=z,string=a,,b" will be ++parsed as "-fw_cfg name=z,string=a,b". ++ + .. hxtool-doc:: qemu-options.hx + + Device URL Syntax +diff --git a/docs/system/qemu-manpage.rst b/docs/system/qemu-manpage.rst +index c47a412758..3ade4ee45b 100644 +--- a/docs/system/qemu-manpage.rst ++++ b/docs/system/qemu-manpage.rst +@@ -31,6 +31,11 @@ Options + disk_image is a raw hard disk image for IDE hard disk 0. Some targets do + not need a disk image. + ++When dealing with options parameters as arbitrary strings containing ++commas, such as in "file=my,file" and "string=a,b", it's necessary to ++double the commas. For instance,"-fw_cfg name=z,string=a,,b" will be ++parsed as "-fw_cfg name=z,string=a,b". ++ + .. hxtool-doc:: qemu-options.hx + + .. include:: keys.rst.inc +diff --git a/qemu-options.hx b/qemu-options.hx +index b09d692d5b..523438e908 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -4086,9 +4086,13 @@ DEF("fw_cfg", HAS_ARG, QEMU_OPTION_fwcfg, + SRST + ``-fw_cfg [name=]name,file=file`` + Add named fw\_cfg entry with contents from file file. ++ If the filename contains comma, you must double it (for instance, ++ "file=my,,file" to use file "my,file"). + + ``-fw_cfg [name=]name,string=str`` + Add named fw\_cfg entry with contents from string str. ++ If the string contains comma, you must double it (for instance, ++ "string=my,,string" to use file "my,string"). + + The terminating NUL character of the contents of str will not be + included as part of the fw\_cfg item data. To insert contents with +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index 2198ece5..b2c7fb33 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 42 +Release: 43 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1036,6 +1036,25 @@ Patch1019: hw-ahci-fix-Werror-maybe-uninitialized-false-positiv.patch Patch1020: hw-sdhci-fix-Werror-maybe-uninitialized-false-positi.patch Patch1021: migration-fix-Werror-maybe-uninitialized-false-posit.patch Patch1022: qemu-img-improve-queue-depth-validation-in-img_bench.patch +Patch1023: qemu-img-fix-division-by-zero-in-bench_cb-for-zero-s.patch +Patch1024: target-i386-cpu-set-correct-supported-XCR0-features-.patch +Patch1025: target-i386-do-not-rely-on-ExtSaveArea-for-accelerat.patch +Patch1026: target-i386-return-bool-from-x86_cpu_filter_features.patch +Patch1027: target-i386-add-AVX10-feature-and-AVX10-version-prop.patch +Patch1028: target-i386-add-CPUID.24-features-for-AVX10.patch +Patch1029: target-i386-Add-feature-dependencies-for-AVX10.patch +Patch1030: target-i386-Add-AVX512-state-when-AVX10-is-supported.patch +Patch1031: target-i386-Introduce-GraniteRapids-v2-model.patch +Patch1032: i386-cpu-Mark-avx10_version-filtered-when-prefix-is-.patch +Patch1033: target-i386-add-avx-vnni-int16-feature.patch +Patch1034: block-stream-fix-Werror-maybe-uninitialized-false-po.patch +Patch1035: migration-fix-Werror-maybe-uninitialized-false-posit2.patch +Patch1036: hw-ssi-xilinx_spips-Fix-flash-erase-assert-in-dual-p.patch +Patch1037: hw-nvme-cap-MDTS-value-for-internal-limitation.patch +Patch1038: accel-kvm-Make-kvm_has_guest_debug-static.patch +Patch1039: target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch +Patch1040: system-qtest-Include-missing-hw-core-cpu.h-header.patch +Patch1041: qemu-options-Clarify-handling-of-commas-in-options-p.patch BuildRequires: flex BuildRequires: gcc @@ -1634,6 +1653,27 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Sat Aug 30 2025 Pengrui Zhang - 11:8.2.0-43 +- qemu-img: fix division by zero in bench_cb() for zero-sized images +- target/i386: cpu: set correct supported XCR0 features for TCG +- target/i386: do not rely on ExtSaveArea for accelerator-supported XCR0 bits +- target/i386: return bool from x86_cpu_filter_features +- target/i386: add AVX10 feature and AVX10 version property +- target/i386: add CPUID.24 features for AVX10 +- target/i386: Add feature dependencies for AVX10 +- target/i386: Add AVX512 state when AVX10 is supported +- target/i386: Introduce GraniteRapids-v2 model +- i386/cpu: Mark avx10_version filtered when prefix is NULL +- target/i386: add avx-vnni-int16 feature +- block/stream: fix -Werror=maybe-uninitialized false-positives +- migration: fix -Werror=maybe-uninitialized false-positives +- hw/ssi/xilinx_spips: Fix flash erase assert in dual parallel configuration +- hw/nvme: cap MDTS value for internal limitation +- accel/kvm: Make kvm_has_guest_debug static +- vtarget/arm/tcg: Including missing 'exec/exec-all.h' header +- system/qtest: Include missing 'hw/core/cpu.h' header +- qemu-options: Clarify handling of commas in options parameters + * Thu Aug 28 2025 Pengrui Zhang - 11:8.2.0-42 - util/timer: fix -Werror=maybe-uninitialized false-positive - hw/qxl: fix -Werror=maybe-uninitialized false-positives diff --git a/system-qtest-Include-missing-hw-core-cpu.h-header.patch b/system-qtest-Include-missing-hw-core-cpu.h-header.patch new file mode 100644 index 00000000..f469a5e9 --- /dev/null +++ b/system-qtest-Include-missing-hw-core-cpu.h-header.patch @@ -0,0 +1,40 @@ +From eda8a258895a5ec550434ae967052aac9d767ec2 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Tue, 12 Dec 2023 12:30:15 +0100 +Subject: [PATCH] system/qtest: Include missing 'hw/core/cpu.h' header +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +"hw/core/cpu.h" declares 'first_cpu'. Include it to avoid +when unrelated headers are refactored: + + system/qtest.c:548:33: error: use of undeclared identifier 'first_cpu' + address_space_write(first_cpu->as, addr, MEMTXATTRS_UNSPECIFIED, + ^ + +Backport from QEMU official community: 65eac5bd547f + +Signed-off-by: Philippe Mathieu-Daudé +Message-ID: <20231212113016.29808-2-philmd@linaro.org> +Reviewed-by: Thomas Huth +Signed-off-by: Thomas Huth +--- + system/qtest.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/system/qtest.c b/system/qtest.c +index 7964f0b248..6da58b3874 100644 +--- a/system/qtest.c ++++ b/system/qtest.c +@@ -21,6 +21,7 @@ + #include "exec/tswap.h" + #include "hw/qdev-core.h" + #include "hw/irq.h" ++#include "hw/core/cpu.h" + #include "qemu/accel.h" + #include "sysemu/cpu-timers.h" + #include "qemu/config-file.h" +-- +2.33.0 + diff --git a/target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch b/target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch new file mode 100644 index 00000000..d6845e99 --- /dev/null +++ b/target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch @@ -0,0 +1,41 @@ +From 5137f72204d34c8e9721e0f9c36a7cb70f04ea4b Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Tue, 19 Dec 2023 17:57:49 +0000 +Subject: [PATCH] target/arm/tcg: Including missing 'exec/exec-all.h' header +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +translate_insn() ends up calling probe_access_full(), itself +declared in "exec/exec-all.h": + + TranslatorOps::translate_insn + -> aarch64_tr_translate_insn() + -> is_guarded_page() + -> probe_access_full() + +Backport from QEMU official community: 47eac5d4237f + +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-id: 20231130142519.28417-4-philmd@linaro.org +Signed-off-by: Peter Maydell +--- + target/arm/tcg/translate-a64.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c +index 5beac07b60..5db42c8083 100644 +--- a/target/arm/tcg/translate-a64.c ++++ b/target/arm/tcg/translate-a64.c +@@ -18,6 +18,7 @@ + */ + #include "qemu/osdep.h" + ++#include "exec/exec-all.h" + #include "translate.h" + #include "translate-a64.h" + #include "qemu/log.h" +-- +2.33.0 + diff --git a/target-i386-Add-AVX512-state-when-AVX10-is-supported.patch b/target-i386-Add-AVX512-state-when-AVX10-is-supported.patch new file mode 100644 index 00000000..f3484ecc --- /dev/null +++ b/target-i386-Add-AVX512-state-when-AVX10-is-supported.patch @@ -0,0 +1,54 @@ +From e7779ff69ad91af1ed5a31cb0e7fe054ab700b1a Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 31 Oct 2024 16:52:32 +0800 +Subject: [PATCH 07/10] target/i386: Add AVX512 state when AVX10 is supported + +commit 0d7475be3b402c25d74c5a4573cbeb733c8f3559 upstream. + +AVX10 state enumeration in CPUID leaf D and enabling in XCR0 register +are identical to AVX512 state regardless of the supported vector lengths. + +Given that some E-cores will support AVX10 but not support AVX512, add +AVX512 state components to guest when AVX10 is enabled. + +Based on a patch by Tao Su + +Intel-SIG: commit 0d7475be3b40 target/i386: Add AVX512 state when AVX10 is supported. +GNR AVX10.1 backporting + +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Tested-by: Xuelian Guo +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241031085233.425388-8-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e93468a79e..e9244ab6b9 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7265,7 +7265,15 @@ static bool cpuid_has_xsave_feature(CPUX86State *env, const ExtSaveArea *esa) + return false; + } + +- return (env->features[esa->feature] & esa->bits); ++ if (env->features[esa->feature] & esa->bits) { ++ return true; ++ } ++ if (esa->feature == FEAT_7_0_EBX && esa->bits == CPUID_7_0_EBX_AVX512F ++ && (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10)) { ++ return true; ++ } ++ ++ return false; + } + + static void x86_cpu_reset_hold(Object *obj) +-- +2.33.0 + diff --git a/target-i386-Add-feature-dependencies-for-AVX10.patch b/target-i386-Add-feature-dependencies-for-AVX10.patch new file mode 100644 index 00000000..59fad164 --- /dev/null +++ b/target-i386-Add-feature-dependencies-for-AVX10.patch @@ -0,0 +1,87 @@ +From deb91de74ee55a37847336a3866beb24bed86188 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 31 Oct 2024 16:52:31 +0800 +Subject: [PATCH 06/10] target/i386: Add feature dependencies for AVX10 + +commit 150ab84b2d0083e6af344cca70290614d4fe568d upstream. + +Since the highest supported vector length for a processor implies that +all lesser vector lengths are also supported, add the dependencies of +the supported vector lengths. If all vector lengths aren't supported, +clear AVX10 enable bit as well. + +Note that the order of AVX10 related dependencies should be kept as: + CPUID_24_0_EBX_AVX10_128 -> CPUID_24_0_EBX_AVX10_256, + CPUID_24_0_EBX_AVX10_256 -> CPUID_24_0_EBX_AVX10_512, + CPUID_24_0_EBX_AVX10_VL_MASK -> CPUID_7_1_EDX_AVX10, + CPUID_7_1_EDX_AVX10 -> CPUID_24_0_EBX, +so that prevent user from setting weird CPUID combinations, e.g. 256-bits +and 512-bits are supported but 128-bits is not, no vector lengths are +supported but AVX10 enable bit is still set. + +Since AVX10_128 will be reserved as 1, adding these dependencies has the +bonus that when user sets -cpu host,-avx10-128, CPUID_7_1_EDX_AVX10 and +CPUID_24_0_EBX will be disabled automatically. + +Intel-SIG: commit 150ab84b2d00 target/i386: Add feature dependencies for AVX10. +GNR AVX10.1 backporting + +Tested-by: Xuelian Guo +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241028024512.156724-5-tao1.su@linux.intel.com +Reviewed-by: Zhao Liu +Signed-off-by: Paolo Bonzini +Link: https://lore.kernel.org/r/20241031085233.425388-7-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 16 ++++++++++++++++ + target/i386/cpu.h | 4 ++++ + 2 files changed, 20 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index fed2ad058c..e93468a79e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1586,6 +1586,22 @@ static FeatureDep feature_dependencies[] = { + .from = { FEAT_7_1_EAX, CPUID_7_1_EAX_WRMSRNS }, + .to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED }, + }, ++ { ++ .from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_128 }, ++ .to = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_256 }, ++ }, ++ { ++ .from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_256 }, ++ .to = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_512 }, ++ }, ++ { ++ .from = { FEAT_24_0_EBX, CPUID_24_0_EBX_AVX10_VL_MASK }, ++ .to = { FEAT_7_1_EDX, CPUID_7_1_EDX_AVX10 }, ++ }, ++ { ++ .from = { FEAT_7_1_EDX, CPUID_7_1_EDX_AVX10 }, ++ .to = { FEAT_24_0_EBX, ~0ull }, ++ }, + }; + + typedef struct X86RegisterInfo32 { +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 7a1dfe004c..95fd226e49 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1006,6 +1006,10 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + #define CPUID_24_0_EBX_AVX10_256 (1U << 17) + /* AVX10 512-bit vector support is present */ + #define CPUID_24_0_EBX_AVX10_512 (1U << 18) ++/* AVX10 vector length support mask */ ++#define CPUID_24_0_EBX_AVX10_VL_MASK (CPUID_24_0_EBX_AVX10_128 | \ ++ CPUID_24_0_EBX_AVX10_256 | \ ++ CPUID_24_0_EBX_AVX10_512) + + /* CLZERO instruction */ + #define CPUID_8000_0008_EBX_CLZERO (1U << 0) +-- +2.33.0 + diff --git a/target-i386-Introduce-GraniteRapids-v2-model.patch b/target-i386-Introduce-GraniteRapids-v2-model.patch new file mode 100644 index 00000000..90e167c8 --- /dev/null +++ b/target-i386-Introduce-GraniteRapids-v2-model.patch @@ -0,0 +1,57 @@ +From 49c9c29ae87ffc8a16c313d21eaf20c5949fa4f4 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 31 Oct 2024 16:52:33 +0800 +Subject: [PATCH 08/10] target/i386: Introduce GraniteRapids-v2 model + +commit 1a519388a882fbb352e49cbebb0ed8f62d05842d upstream. + +Update GraniteRapids CPU model to add AVX10 and the missing features(ss, +tsc-adjust, cldemote, movdiri, movdir64b). + +Intel-SIG: commit 1a519388a882 target/i386: Introduce GraniteRapids-v2 model. +GNR AVX10.1 backporting + +Tested-by: Xuelian Guo +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241028024512.156724-7-tao1.su@linux.intel.com +Reviewed-by: Zhao Liu +Signed-off-by: Paolo Bonzini +Link: https://lore.kernel.org/r/20241031085233.425388-9-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e9244ab6b9..7b969a4447 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4226,6 +4226,23 @@ static const X86CPUDefinition builtin_x86_defs[] = { + .model_id = "Intel Xeon Processor (GraniteRapids)", + .versions = (X86CPUVersionDefinition[]) { + { .version = 1 }, ++ { ++ .version = 2, ++ .props = (PropValue[]) { ++ { "ss", "on" }, ++ { "tsc-adjust", "on" }, ++ { "cldemote", "on" }, ++ { "movdiri", "on" }, ++ { "movdir64b", "on" }, ++ { "avx10", "on" }, ++ { "avx10-128", "on" }, ++ { "avx10-256", "on" }, ++ { "avx10-512", "on" }, ++ { "avx10-version", "1" }, ++ { "stepping", "1" }, ++ { /* end of list */ } ++ } ++ }, + { /* end of list */ }, + }, + }, +-- +2.33.0 + diff --git a/target-i386-add-AVX10-feature-and-AVX10-version-prop.patch b/target-i386-add-AVX10-feature-and-AVX10-version-prop.patch new file mode 100644 index 00000000..81d7715e --- /dev/null +++ b/target-i386-add-AVX10-feature-and-AVX10-version-prop.patch @@ -0,0 +1,222 @@ +From 5d4c2e488ec5fc36bd0b9d53f6b60ccd9f613edc Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 31 Oct 2024 16:52:29 +0800 +Subject: [PATCH 04/10] target/i386: add AVX10 feature and AVX10 version + property + +commit bccfb846fd52d6f20704ecfa4d01b60b43c6f640 upstream. + +When AVX10 enable bit is set, the 0x24 leaf will be present as "AVX10 +Converged Vector ISA leaf" containing fields for the version number and +the supported vector bit lengths. + +Introduce avx10-version property so that avx10 version can be controlled +by user and cpu model. Per spec, avx10 version can never be 0, the default +value of avx10-version is set to 0 to determine whether it is specified by +user. The default can come from the device model or, for the max model, +from KVM's reported value. + +Intel-SIG: commit bccfb846fd52 target/i386: add AVX10 feature and AVX10 version property. +GNR AVX10.1 backporting + +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241028024512.156724-3-tao1.su@linux.intel.com +Link: https://lore.kernel.org/r/20241028024512.156724-4-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +Tested-by: Xuelian Guo +Link: https://lore.kernel.org/r/20241031085233.425388-5-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 63 ++++++++++++++++++++++++++++++++++++++----- + target/i386/cpu.h | 4 +++ + target/i386/kvm/kvm.c | 3 ++- + 3 files changed, 63 insertions(+), 7 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 1313201f67..5b0d123e42 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -48,6 +48,9 @@ + #include "cpu-internal.h" + + static void x86_cpu_realizefn(DeviceState *dev, Error **errp); ++static void x86_cpu_get_supported_cpuid(uint32_t func, uint32_t index, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx); + + /* Helpers for building CPUID[2] descriptors: */ + +@@ -985,7 +988,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + "avx-vnni-int8", "avx-ne-convert", NULL, NULL, + "amx-complex", NULL, NULL, NULL, + NULL, NULL, "prefetchiti", NULL, +- NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, "avx10", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +@@ -1789,6 +1792,7 @@ typedef struct X86CPUDefinition { + int family; + int model; + int stepping; ++ uint8_t avx10_version; + FeatureWordArray features; + const char *model_id; + const CPUCaches *const cache_info; +@@ -6406,6 +6410,9 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) + */ + object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort); + ++ object_property_set_uint(OBJECT(cpu), "avx10-version", def->avx10_version, ++ &error_abort); ++ + x86_cpu_apply_version_props(cpu, model); + + /* +@@ -6960,6 +6967,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + } ++ case 0x24: { ++ *eax = 0; ++ *ebx = 0; ++ *ecx = 0; ++ *edx = 0; ++ if ((env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) && count == 0) { ++ *ebx = env->features[FEAT_24_0_EBX] | env->avx10_version; ++ } ++ break; ++ } + case 0x40000000: + /* + * CPUID code in kvm_arch_init_vcpu() ignores stuff +@@ -7559,6 +7576,12 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + ~env->user_features[w] & + ~feature_word_info[w].no_autoenable_flags; + } ++ ++ if ((env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) && !env->avx10_version) { ++ uint32_t eax, ebx, ecx, edx; ++ x86_cpu_get_supported_cpuid(0x24, 0, &eax, &ebx, &ecx, &edx); ++ env->avx10_version = ebx & 0xff; ++ } + } + + for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { +@@ -7622,6 +7645,11 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F); + } + ++ /* Advanced Vector Extensions 10 (AVX10) requires CPUID[0x24] */ ++ if (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) { ++ x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x24); ++ } ++ + /* SVM requires CPUID[0x8000000A] */ + if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { + x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A); +@@ -7672,6 +7700,10 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) + CPUX86State *env = &cpu->env; + FeatureWord w; + const char *prefix = NULL; ++ bool have_filtered_features; ++ ++ uint32_t eax_0, ebx_0, ecx_0, edx_0; ++ uint32_t eax_1, ebx_1, ecx_1, edx_1; + + if (verbose) { + prefix = accel_uses_host_cpuid() +@@ -7688,13 +7720,11 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) + } + + if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) { +- uint32_t eax_0, ebx_0, ecx_0, edx_0_unused; +- uint32_t eax_1, ebx_1, ecx_1_unused, edx_1_unused; + + x86_cpu_get_supported_cpuid(0x14, 0, +- &eax_0, &ebx_0, &ecx_0, &edx_0_unused); ++ &eax_0, &ebx_0, &ecx_0, &edx_0); + x86_cpu_get_supported_cpuid(0x14, 1, +- &eax_1, &ebx_1, &ecx_1_unused, &edx_1_unused); ++ &eax_1, &ebx_1, &ecx_1, &edx_1); + + if (!eax_0 || + ((ebx_0 & INTEL_PT_MINIMAL_EBX) != INTEL_PT_MINIMAL_EBX) || +@@ -7715,7 +7745,27 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) + } + } + +- return x86_cpu_have_filtered_features(cpu); ++ have_filtered_features = x86_cpu_have_filtered_features(cpu); ++ ++ if (env->features[FEAT_7_1_EDX] & CPUID_7_1_EDX_AVX10) { ++ x86_cpu_get_supported_cpuid(0x24, 0, ++ &eax_0, &ebx_0, &ecx_0, &edx_0); ++ uint8_t version = ebx_0 & 0xff; ++ ++ if (version < env->avx10_version) { ++ if (prefix) { ++ warn_report("%s: avx10.%d. Adjust to avx10.%d", ++ prefix, env->avx10_version, version); ++ } ++ env->avx10_version = version; ++ have_filtered_features = true; ++ } ++ } else if (env->avx10_version && prefix) { ++ warn_report("%s: avx10.%d.", prefix, env->avx10_version); ++ have_filtered_features = true; ++ } ++ ++ return have_filtered_features; + } + + static void x86_cpu_hyperv_realize(X86CPU *cpu) +@@ -8469,6 +8519,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_UINT32("min-level", X86CPU, env.cpuid_min_level, 0), + DEFINE_PROP_UINT32("min-xlevel", X86CPU, env.cpuid_min_xlevel, 0), + DEFINE_PROP_UINT32("min-xlevel2", X86CPU, env.cpuid_min_xlevel2, 0), ++ DEFINE_PROP_UINT8("avx10-version", X86CPU, env.avx10_version, 0), + DEFINE_PROP_UINT64("ucode-rev", X86CPU, ucode_rev, 0), + DEFINE_PROP_BOOL("full-cpuid-auto-level", X86CPU, full_cpuid_auto_level, true), + DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor), +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 4424e58d1b..fd048f9bda 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -977,6 +977,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + #define CPUID_7_1_EDX_AMX_COMPLEX (1U << 8) + /* PREFETCHIT0/1 Instructions */ + #define CPUID_7_1_EDX_PREFETCHITI (1U << 14) ++/* Support for Advanced Vector Extensions 10 */ ++#define CPUID_7_1_EDX_AVX10 (1U << 19) + + /* Indicate bit 7 of the IA32_SPEC_CTRL MSR is supported */ + #define CPUID_7_2_EDX_PSFD (1U << 0) +@@ -1877,6 +1879,8 @@ typedef struct CPUArchState { + uint32_t cpuid_vendor3; + uint32_t cpuid_version; + FeatureWordArray features; ++ /* AVX10 version */ ++ uint8_t avx10_version; + /* Features that were explicitly enabled/disabled */ + FeatureWordArray user_features; + uint32_t cpuid_model[12]; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 2f379876e6..37e30d0194 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -1978,7 +1978,8 @@ int kvm_arch_init_vcpu(CPUState *cs) + case 0x7: + case 0x14: + case 0x1d: +- case 0x1e: { ++ case 0x1e: ++ case 0x24: { + uint32_t times; + + c->function = i; +-- +2.33.0 + diff --git a/target-i386-add-CPUID.24-features-for-AVX10.patch b/target-i386-add-CPUID.24-features-for-AVX10.patch new file mode 100644 index 00000000..73aa9869 --- /dev/null +++ b/target-i386-add-CPUID.24-features-for-AVX10.patch @@ -0,0 +1,89 @@ +From 7e080e529d9e3b2954053a9826494be4e13847a1 Mon Sep 17 00:00:00 2001 +From: Tao Su +Date: Thu, 31 Oct 2024 16:52:30 +0800 +Subject: [PATCH 05/10] target/i386: add CPUID.24 features for AVX10 + +commit 2d055b8fe11ee567c2ae8047311fd83697e494b6 upstream. + +Introduce features for the supported vector bit lengths. + +Intel-SIG: commit 2d055b8fe11e target/i386: add CPUID.24 features for AVX10. +GNR AVX10.1 backporting + +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241028024512.156724-3-tao1.su@linux.intel.com +Link: https://lore.kernel.org/r/20241028024512.156724-4-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Tested-by: Xuelian Guo +Link: https://lore.kernel.org/r/20241031085233.425388-6-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 15 +++++++++++++++ + target/i386/cpu.h | 8 ++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5b0d123e42..fed2ad058c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -754,6 +754,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + #define TCG_SGX_12_0_EAX_FEATURES 0 + #define TCG_SGX_12_0_EBX_FEATURES 0 + #define TCG_SGX_12_1_EAX_FEATURES 0 ++#define TCG_24_0_EBX_FEATURES 0 + + #if defined CONFIG_USER_ONLY + #define CPUID_8000_0008_EBX_KERNEL_FEATURES (CPUID_8000_0008_EBX_IBPB | \ +@@ -1019,6 +1020,20 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + }, + .tcg_features = TCG_7_2_EDX_FEATURES, + }, ++ [FEAT_24_0_EBX] = { ++ .type = CPUID_FEATURE_WORD, ++ .feat_names = { ++ [16] = "avx10-128", ++ [17] = "avx10-256", ++ [18] = "avx10-512", ++ }, ++ .cpuid = { ++ .eax = 0x24, ++ .needs_ecx = true, .ecx = 0, ++ .reg = R_EBX, ++ }, ++ .tcg_features = TCG_24_0_EBX_FEATURES, ++ }, + [FEAT_8000_0007_EDX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index fd048f9bda..7a1dfe004c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -651,6 +651,7 @@ typedef enum FeatureWord { + FEAT_XSAVE_XSS_HI, /* CPUID[EAX=0xd,ECX=1].EDX */ + FEAT_7_1_EDX, /* CPUID[EAX=7,ECX=1].EDX */ + FEAT_7_2_EDX, /* CPUID[EAX=7,ECX=2].EDX */ ++ FEAT_24_0_EBX, /* CPUID[EAX=0x24,ECX=0].EBX */ + FEATURE_WORDS, + } FeatureWord; + +@@ -999,6 +1000,13 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + /* Packets which contain IP payload have LIP values */ + #define CPUID_14_0_ECX_LIP (1U << 31) + ++/* AVX10 128-bit vector support is present */ ++#define CPUID_24_0_EBX_AVX10_128 (1U << 16) ++/* AVX10 256-bit vector support is present */ ++#define CPUID_24_0_EBX_AVX10_256 (1U << 17) ++/* AVX10 512-bit vector support is present */ ++#define CPUID_24_0_EBX_AVX10_512 (1U << 18) ++ + /* CLZERO instruction */ + #define CPUID_8000_0008_EBX_CLZERO (1U << 0) + /* Always save/restore FP error pointers */ +-- +2.33.0 + diff --git a/target-i386-add-avx-vnni-int16-feature.patch b/target-i386-add-avx-vnni-int16-feature.patch new file mode 100644 index 00000000..3432fe5a --- /dev/null +++ b/target-i386-add-avx-vnni-int16-feature.patch @@ -0,0 +1,37 @@ +From e711253e77b249686e5a4d3c15d474303de0cc99 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 3 Jul 2024 13:42:49 +0200 +Subject: [PATCH 10/10] target/i386: add avx-vnni-int16 feature + +commit 138c3377a9b27accec516b2c0da90dedef98a780 upstream. + +AVX-VNNI-INT16 (CPUID[EAX=7,ECX=1).EDX[10]) is supported by Clearwater +Forest processor, add it to QEMU as it does not need any specific +enablement. + +Intel-SIG: commit 138c3377a9b2 target/i386: add avx-vnni-int16 feature. +CWF ISA AVX_VNNI_INT16 backporting + +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + 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 eff23af452..1e704558cd 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -987,7 +987,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .feat_names = { + NULL, NULL, NULL, NULL, + "avx-vnni-int8", "avx-ne-convert", NULL, NULL, +- "amx-complex", NULL, NULL, NULL, ++ "amx-complex", NULL, "avx-vnni-int16", NULL, + NULL, NULL, "prefetchiti", NULL, + NULL, NULL, NULL, "avx10", + NULL, NULL, NULL, NULL, +-- +2.33.0 + diff --git a/target-i386-cpu-set-correct-supported-XCR0-features-.patch b/target-i386-cpu-set-correct-supported-XCR0-features-.patch new file mode 100644 index 00000000..b461fefb --- /dev/null +++ b/target-i386-cpu-set-correct-supported-XCR0-features-.patch @@ -0,0 +1,48 @@ +From f795645ecbabcfe0f1edb9b80853f39572d8f2de Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 31 Oct 2024 16:52:26 +0800 +Subject: [PATCH 01/10] target/i386: cpu: set correct supported XCR0 features + for TCG + +commit 33098002a838a0450f243f5e17463aca700e923d upstream. + +Intel-SIG: commit 33098002a838 target/i386: cpu: set correct supported XCR0 features for TCG. +GNR AVX10.1 backporting + +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241031085233.425388-2-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 8360ea3d61..239629277e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1133,7 +1133,9 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .needs_ecx = true, .ecx = 0, + .reg = R_EAX, + }, +- .tcg_features = ~0U, ++ .tcg_features = XSTATE_FP_MASK | XSTATE_SSE_MASK | ++ XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK | ++ XSTATE_PKRU_MASK, + .migratable_flags = XSTATE_FP_MASK | XSTATE_SSE_MASK | + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK | + XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK | +@@ -1146,7 +1148,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .needs_ecx = true, .ecx = 0, + .reg = R_EDX, + }, +- .tcg_features = ~0U, ++ .tcg_features = 0U, + }, + /*Below are MSR exposed features*/ + [FEAT_ARCH_CAPABILITIES] = { +-- +2.33.0 + diff --git a/target-i386-do-not-rely-on-ExtSaveArea-for-accelerat.patch b/target-i386-do-not-rely-on-ExtSaveArea-for-accelerat.patch new file mode 100644 index 00000000..a76ea972 --- /dev/null +++ b/target-i386-do-not-rely-on-ExtSaveArea-for-accelerat.patch @@ -0,0 +1,115 @@ +From 034614cc369a463619d609106594d8d4a9402cf1 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 31 Oct 2024 16:52:27 +0800 +Subject: [PATCH 02/10] target/i386: do not rely on ExtSaveArea for + accelerator-supported XCR0 bits + +commit b888c7807049cc044d10d70139cb945202fb7cd2 upstream. + +Right now, QEMU is using the "feature" and "bits" fields of ExtSaveArea +to query the accelerator for the support status of extended save areas. +This is a problem for AVX10, which attaches two feature bits (AVX512F +and AVX10) to the same extended save states. + +To keep the AVX10 hacks to the minimum, limit usage of esa->features +and esa->bits. Instead, just query the accelerator for the 0xD leaf. +Do it in common code and clear esa->size if an extended save state is +unsupported. + +Intel-SIG: commit b888c7807049 target/i386: do not rely on ExtSaveArea for accelerator-supported XCR0 bits. +GNR AVX10.1 backporting + +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241031085233.425388-3-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 33 +++++++++++++++++++++++++++++++-- + target/i386/kvm/kvm-cpu.c | 4 ---- + 2 files changed, 31 insertions(+), 6 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 239629277e..5b89643319 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7211,6 +7211,15 @@ static void x86_cpu_set_sgxlepubkeyhash(CPUX86State *env) + #endif + } + ++static bool cpuid_has_xsave_feature(CPUX86State *env, const ExtSaveArea *esa) ++{ ++ if (!esa->size) { ++ return false; ++ } ++ ++ return (env->features[esa->feature] & esa->bits); ++} ++ + static void x86_cpu_reset_hold(Object *obj) + { + CPUState *s = CPU(obj); +@@ -7319,7 +7328,7 @@ static void x86_cpu_reset_hold(Object *obj) + if (!((1 << i) & CPUID_XSTATE_XCR0_MASK)) { + continue; + } +- if (env->features[esa->feature] & esa->bits) { ++ if (cpuid_has_xsave_feature(env, esa)) { + xcr0 |= 1ull << i; + } + } +@@ -7457,7 +7466,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) + mask = 0; + for (i = 0; i < ARRAY_SIZE(x86_ext_save_areas); i++) { + const ExtSaveArea *esa = &x86_ext_save_areas[i]; +- if (env->features[esa->feature] & esa->bits) { ++ if (cpuid_has_xsave_feature(env, esa)) { + mask |= (1ULL << i); + } + } +@@ -8126,6 +8135,26 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc, + + static void x86_cpu_post_initfn(Object *obj) + { ++ static bool first = true; ++ uint64_t supported_xcr0; ++ int i; ++ ++ if (first) { ++ first = false; ++ ++ supported_xcr0 = ++ ((uint64_t) x86_cpu_get_supported_feature_word(NULL, FEAT_XSAVE_XCR0_HI) << 32) | ++ x86_cpu_get_supported_feature_word(NULL, FEAT_XSAVE_XCR0_LO); ++ ++ for (i = XSTATE_SSE_BIT + 1; i < XSAVE_STATE_AREA_COUNT; i++) { ++ ExtSaveArea *esa = &x86_ext_save_areas[i]; ++ ++ if (!(supported_xcr0 & (1 << i))) { ++ esa->size = 0; ++ } ++ } ++ } ++ + accel_cpu_instance_init(CPU(obj)); + } + +diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c +index a3bc8d8f83..5df8a01313 100644 +--- a/target/i386/kvm/kvm-cpu.c ++++ b/target/i386/kvm/kvm-cpu.c +@@ -137,10 +137,6 @@ static void kvm_cpu_xsave_init(void) + if (!esa->size) { + continue; + } +- if ((x86_cpu_get_supported_feature_word(NULL, esa->feature) & esa->bits) +- != esa->bits) { +- continue; +- } + host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); + if (eax != 0) { + assert(esa->size == eax); +-- +2.33.0 + diff --git a/target-i386-return-bool-from-x86_cpu_filter_features.patch b/target-i386-return-bool-from-x86_cpu_filter_features.patch new file mode 100644 index 00000000..419b1d45 --- /dev/null +++ b/target-i386-return-bool-from-x86_cpu_filter_features.patch @@ -0,0 +1,81 @@ +From 89d9a44a5c792c548ffcf0b8ae96a6af37286cf8 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 31 Oct 2024 16:52:28 +0800 +Subject: [PATCH 03/10] target/i386: return bool from x86_cpu_filter_features + +commit 3507c6f04606593711408a6d26141bdbceff9377 upstream. + +Prepare for filtering non-boolean features such as AVX10 version. + +Intel-SIG: commit 3507c6f04606 target/i386: return bool from x86_cpu_filter_features. +GNR AVX10.1 backporting + +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Signed-off-by: Tao Su +Link: https://lore.kernel.org/r/20241031085233.425388-4-tao1.su@linux.intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5b89643319..1313201f67 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5944,7 +5944,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, + } + } + +-static void x86_cpu_filter_features(X86CPU *cpu, bool verbose); ++static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose); + + /* Build a list with the name of all features on a feature word array */ + static void x86_cpu_list_feature_names(FeatureWordArray features, +@@ -7665,9 +7665,9 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + * Finishes initialization of CPUID data, filters CPU feature + * words based on host availability of each feature. + * +- * Returns: 0 if all flags are supported by the host, non-zero otherwise. ++ * Returns: true if any flag is not supported by the host, false otherwise. + */ +-static void x86_cpu_filter_features(X86CPU *cpu, bool verbose) ++static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) + { + CPUX86State *env = &cpu->env; + FeatureWord w; +@@ -7714,6 +7714,8 @@ static void x86_cpu_filter_features(X86CPU *cpu, bool verbose) + mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix); + } + } ++ ++ return x86_cpu_have_filtered_features(cpu); + } + + static void x86_cpu_hyperv_realize(X86CPU *cpu) +@@ -7812,14 +7814,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + } + } + +- x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); +- +- if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { +- error_setg(&local_err, +- accel_uses_host_cpuid() ? ++ if (x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid)) { ++ if (cpu->enforce_cpuid) { ++ error_setg(&local_err, ++ accel_uses_host_cpuid() ? + "Host doesn't support requested features" : + "TCG doesn't support requested features"); +- goto out; ++ goto out; ++ } + } + + /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on +-- +2.33.0 + -- Gitee From 8e91ab599e9dfc540b656561b4b211e512c272d5 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Sat, 30 Aug 2025 14:53:06 +0800 Subject: [PATCH 08/14] QEMU update to version 8.2.0-44 Signed-off-by: zhangpengrui --- ...ix-abstract-device-type-error-messag.patch | 37 +++++++++ ...native-non-cross-compiler-for-linux-.patch | 39 ++++++++++ ...or-NULL-result-from-scsi_device_find.patch | 44 +++++++++++ ...ve-final-vestiges-of-dynamic-state-t.patch | 37 +++++++++ ...t-cadence_gem-Fix-MDIO_OP_xxx-values.patch | 47 ++++++++++++ ...on-fix-coverity-migrate_mode-finding.patch | 48 ++++++++++++ ...ons-Unify-the-help-entries-for-cocoa.patch | 45 +++++++++++ qemu.spec | 28 ++++++- ...x-mcycle-minstret-increment-behavior.patch | 58 ++++++++++++++ ...-do-not-use-non-portable-strerrornam.patch | 75 +++++++++++++++++++ ...est-qmp-event-Drop-superfluous-mutex.patch | 54 +++++++++++++ ...-scsi-fix-usage-of-error_reportf_err.patch | 68 +++++++++++++++++ ...-notifier-helpers-for-VIRTIO_CONFIG_.patch | 63 ++++++++++++++++ 13 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 chardev-char.c-fix-abstract-device-type-error-messag.patch create mode 100644 configure-use-a-native-non-cross-compiler-for-linux-.patch create mode 100644 esp-check-for-NULL-result-from-scsi_device_find.patch create mode 100644 hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch create mode 100644 hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch create mode 100644 migration-fix-coverity-migrate_mode-finding.patch create mode 100644 qemu-options-Unify-the-help-entries-for-cocoa.patch create mode 100644 target-riscv-Fix-mcycle-minstret-increment-behavior.patch create mode 100644 target-riscv-kvm-do-not-use-non-portable-strerrornam.patch create mode 100644 tests-unit-test-qmp-event-Drop-superfluous-mutex.patch create mode 100644 vhost-scsi-fix-usage-of-error_reportf_err.patch create mode 100644 virtio-rng-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch diff --git a/chardev-char.c-fix-abstract-device-type-error-messag.patch b/chardev-char.c-fix-abstract-device-type-error-messag.patch new file mode 100644 index 00000000..6c7df852 --- /dev/null +++ b/chardev-char.c-fix-abstract-device-type-error-messag.patch @@ -0,0 +1,37 @@ +From 1bfac15dc5a3e4ef2ef0a6df96ad5775de5cb9c1 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 3 Jan 2024 14:37:39 +0300 +Subject: [PATCH] chardev/char.c: fix "abstract device type" error message + +Current error message: + + qemu-system-x86_64: -chardev spice,id=foo: Parameter 'driver' expects an abstract device type + +while in fact the meaning is in reverse, -chardev expects +a non-abstract device type. + +Backport from QEMU official community: 4ad87cd4b225 + +Fixes: 777357d758d9 ("chardev: qom-ify" 2016-12-07) +Signed-off-by: Michael Tokarev +Reviewed-by: Zhao Liu +--- + chardev/char.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/chardev/char.c b/chardev/char.c +index 996a024c7a..119b548784 100644 +--- a/chardev/char.c ++++ b/chardev/char.c +@@ -518,7 +518,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp) + + if (object_class_is_abstract(oc)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", +- "an abstract device type"); ++ "a non-abstract device type"); + return NULL; + } + +-- +2.33.0 + diff --git a/configure-use-a-native-non-cross-compiler-for-linux-.patch b/configure-use-a-native-non-cross-compiler-for-linux-.patch new file mode 100644 index 00000000..44f4e551 --- /dev/null +++ b/configure-use-a-native-non-cross-compiler-for-linux-.patch @@ -0,0 +1,39 @@ +From 7d0a5a5345e2acf77770033cff2b746a20942aff Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Fri, 22 Dec 2023 10:55:43 +0100 +Subject: [PATCH] configure: use a native non-cross compiler for linux-user + +Commit c2118e9e1ab ("configure: don't try a "native" cross for linux-user", +2023-11-23) sought to avoid issues with using the native compiler with a +cross-endian or cross-bitness setup. However, in doing so it ended up +requiring a cross compiler setup (and most likely a slow compiler setup) +even when building TCG tests that are native to the host architecture. +Always allow the host compiler in that case. + +Backport from QEMU official community: 007531586aa8 + +Cc: qemu-stable@nongnu.org +Fixes: c2118e9e1ab ("configure: don't try a "native" cross for linux-user", 2023-11-23) +Signed-off-by: Paolo Bonzini +--- + configure | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure b/configure +index 6036de83a4..67468e9918 100755 +--- a/configure ++++ b/configure +@@ -1388,8 +1388,8 @@ probe_target_compiler() { + done + + try=cross +- # For softmmu/roms we might be able to use the host compiler +- if [ "${1%softmmu}" != "$1" ]; then ++ # For softmmu/roms also look for a bi-endian or multilib-enabled host compiler ++ if [ "${1%softmmu}" != "$1" ] || test "$target_arch" = "$cpu"; then + case "$target_arch:$cpu" in + aarch64_be:aarch64 | \ + armeb:arm | \ +-- +2.33.0 + diff --git a/esp-check-for-NULL-result-from-scsi_device_find.patch b/esp-check-for-NULL-result-from-scsi_device_find.patch new file mode 100644 index 00000000..6b199534 --- /dev/null +++ b/esp-check-for-NULL-result-from-scsi_device_find.patch @@ -0,0 +1,44 @@ +From a9a1ea20a5a9b6f4e5bad70d876155704cecefac Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Fri, 29 Dec 2023 18:26:47 +0300 +Subject: [PATCH] esp: check for NULL result from scsi_device_find() + +Add a 'current_lun' check for a null value +to avoid null pointer dereferencing and +recover host if NULL return + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Backport from QEMU official community: b22f83d8df48 + +Fixes: 4eb8606560 (esp: store lun coming from the MESSAGE OUT phase) +Signed-off-by: Alexandra Diupina +Message-ID: <20231229152647.19699-1-adiupina@astralinux.ru> +Signed-off-by: Paolo Bonzini +--- + hw/scsi/esp.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index 9b11d8c573..d2cae79194 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -292,6 +292,15 @@ static void do_command_phase(ESPState *s) + esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen); + + current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun); ++ if (!current_lun) { ++ /* No such drive */ ++ s->rregs[ESP_RSTAT] = 0; ++ s->rregs[ESP_RINTR] = INTR_DC; ++ s->rregs[ESP_RSEQ] = SEQ_0; ++ esp_raise_irq(s); ++ return; ++ } ++ + s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s); + datalen = scsi_req_enqueue(s->current_req); + s->ti_size = datalen; +-- +2.33.0 + diff --git a/hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch b/hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch new file mode 100644 index 00000000..4d8e9c11 --- /dev/null +++ b/hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch @@ -0,0 +1,37 @@ +From e40b2c3f39dc3a4dd62bb347820f0df285876b47 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 29 Nov 2023 17:07:38 +0100 +Subject: [PATCH] hw/core/cpu: Remove final vestiges of dynamic state tracing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The dynamic state tracing was removed in commit d0aaf08bb9. + +Backport from QEMU official community: e9f760f27a45 + +Fixes: d0aaf08bb9 ("tcg: remove the final vestiges of dstate") +Signed-off-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Message-Id: <20231129182734.15565-1-philmd@linaro.org> +--- + include/hw/core/cpu.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index 37f3a469c8..ee7eb2a0ca 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -437,9 +437,6 @@ struct qemu_work_item; + * @kvm_fd: vCPU file descriptor for KVM. + * @work_mutex: Lock to prevent multiple access to @work_list. + * @work_list: List of pending asynchronous work. +- * @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes +- * to @trace_dstate). +- * @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask). + * @plugin_mask: Plugin event bitmap. Modified only via async work. + * @ignore_memory_transaction_failures: Cached copy of the MachineState + * flag of the same name: allows the board to suppress calling of the +-- +2.33.0 + diff --git a/hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch b/hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch new file mode 100644 index 00000000..1c7ed03d --- /dev/null +++ b/hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch @@ -0,0 +1,47 @@ +From 5cff939cf515350936219d01d22f72a40930f69e Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Tue, 2 Jan 2024 22:18:03 +0800 +Subject: [PATCH] hw/net: cadence_gem: Fix MDIO_OP_xxx values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Testing upstream U-Boot with 'sifive_u' machine we see: + + => dhcp + ethernet@10090000: PHY present at 0 + Could not get PHY for ethernet@10090000: addr 0 + phy_connect failed + +This has been working till QEMU 8.1 but broken since QEMU 8.2. + +Backport from QEMU official community: 0c7ffc977195c + +Fixes: 1b09eeb122aa ("hw/net/cadence_gem: use FIELD to describe PHYMNTNC register fields") +Reported-by: Heinrich Schuchardt +Signed-off-by: Bin Meng +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Heinrich Schuchardt +Signed-off-by: Michael Tokarev +--- + hw/net/cadence_gem.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c +index c7f793c560..5330608c6c 100644 +--- a/hw/net/cadence_gem.c ++++ b/hw/net/cadence_gem.c +@@ -199,8 +199,8 @@ REG32(PHYMNTNC, 0x34) /* Phy Maintenance reg */ + FIELD(PHYMNTNC, PHY_ADDR, 23, 5) + FIELD(PHYMNTNC, OP, 28, 2) + FIELD(PHYMNTNC, ST, 30, 2) +-#define MDIO_OP_READ 0x3 +-#define MDIO_OP_WRITE 0x2 ++#define MDIO_OP_READ 0x2 ++#define MDIO_OP_WRITE 0x1 + + REG32(RXPAUSE, 0x38) /* RX Pause Time reg */ + REG32(TXPAUSE, 0x3c) /* TX Pause Time reg */ +-- +2.33.0 + diff --git a/migration-fix-coverity-migrate_mode-finding.patch b/migration-fix-coverity-migrate_mode-finding.patch new file mode 100644 index 00000000..c678cdce --- /dev/null +++ b/migration-fix-coverity-migrate_mode-finding.patch @@ -0,0 +1,48 @@ +From d8d68637d6528e200b6af1efe3939891b8abd3a3 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Mon, 13 Nov 2023 12:23:45 -0800 +Subject: [PATCH] migration: fix coverity migrate_mode finding + +Coverity diagnoses a possible out-of-range array index here ... + + static GSList *migration_blockers[MIG_MODE__MAX]; + + fill_source_migration_info() { + GSList *cur_blocker = migration_blockers[migrate_mode()]; + +... because it does not know that MIG_MODE__MAX will never be returned as +a migration mode. To fix, assert so in migrate_mode(). + +Fixes: fa3673e497a1 ("migration: per-mode blockers") + +Backport from QEMU official community: b12635ff08ab + +Reported-by: Peter Maydell +Suggested-by: Peter Maydell +Signed-off-by: Steve Sistare +Reviewed-by: Fabiano Rosas +Link: https://lore.kernel.org/r/1699907025-215450-1-git-send-email-steven.sistare@oracle.com +Signed-off-by: Peter Xu +--- + migration/options.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/migration/options.c b/migration/options.c +index 6ba7ff65a3..136a8575df 100644 +--- a/migration/options.c ++++ b/migration/options.c +@@ -865,8 +865,10 @@ uint64_t migrate_max_postcopy_bandwidth(void) + MigMode migrate_mode(void) + { + MigrationState *s = migrate_get_current(); ++ MigMode mode = s->parameters.mode; + +- return s->parameters.mode; ++ assert(mode >= 0 && mode < MIG_MODE__MAX); ++ return mode; + } + + int migrate_hdbss_buffer_size(void) +-- +2.33.0 + diff --git a/qemu-options-Unify-the-help-entries-for-cocoa.patch b/qemu-options-Unify-the-help-entries-for-cocoa.patch new file mode 100644 index 00000000..d1ef9638 --- /dev/null +++ b/qemu-options-Unify-the-help-entries-for-cocoa.patch @@ -0,0 +1,45 @@ +From 26c6433e031af96ee0740d22ca225c3b355758a6 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Thu, 14 Dec 2023 15:31:35 +0900 +Subject: [PATCH] qemu-options: Unify the help entries for cocoa +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Apparently the help entries were not merged when the patches got in. + +Backport from QEMU official community: 9ab8715d86bf + +Fixes: f844cdb99714 ("ui/cocoa: capture all keys and combos when mouse is grabbed") +Signed-off-by: Akihiko Odaki +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Michael Tokarev +--- + qemu-options.hx | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index b09d692d5b..9fb0348747 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -2087,6 +2087,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, + #endif + #if defined(CONFIG_COCOA) + "-display cocoa[,full-grab=on|off][,swap-opt-cmd=on|off]\n" ++ " [,show-cursor=on|off][,left-command-key=on|off]\n" + #endif + #if defined(CONFIG_OPENGL) + "-display egl-headless[,rendernode=]\n" +@@ -2094,9 +2095,6 @@ DEF("display", HAS_ARG, QEMU_OPTION_display, + #if defined(CONFIG_DBUS_DISPLAY) + "-display dbus[,addr=]\n" + " [,gl=on|core|es|off][,rendernode=]\n" +-#endif +-#if defined(CONFIG_COCOA) +- "-display cocoa[,show-cursor=on|off][,left-command-key=on|off]\n" + #endif + "-display none\n" + " select display backend type\n" +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index b2c7fb33..cd6c74d9 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 43 +Release: 44 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1055,6 +1055,18 @@ Patch1038: accel-kvm-Make-kvm_has_guest_debug-static.patch Patch1039: target-arm-tcg-Including-missing-exec-exec-all.h-hea.patch Patch1040: system-qtest-Include-missing-hw-core-cpu.h-header.patch Patch1041: qemu-options-Clarify-handling-of-commas-in-options-p.patch +Patch1042: tests-unit-test-qmp-event-Drop-superfluous-mutex.patch +Patch1043: configure-use-a-native-non-cross-compiler-for-linux-.patch +Patch1044: target-riscv-kvm-do-not-use-non-portable-strerrornam.patch +Patch1045: qemu-options-Unify-the-help-entries-for-cocoa.patch +Patch1046: virtio-rng-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch +Patch1047: vhost-scsi-fix-usage-of-error_reportf_err.patch +Patch1048: esp-check-for-NULL-result-from-scsi_device_find.patch +Patch1049: migration-fix-coverity-migrate_mode-finding.patch +Patch1050: hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch +Patch1051: target-riscv-Fix-mcycle-minstret-increment-behavior.patch +Patch1052: chardev-char.c-fix-abstract-device-type-error-messag.patch +Patch1053: hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch BuildRequires: flex BuildRequires: gcc @@ -1653,6 +1665,20 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Sat Aug 30 2025 Pengrui Zhang - 11:8.2.0-44 +- tests/unit/test-qmp-event: Drop superfluous mutex +- configure: use a native non-cross compiler for linux-user +- target/riscv/kvm: do not use non-portable strerrorname_np() +- qemu-options: Unify the help entries for cocoa +- virtio: rng: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX +- vhost-scsi: fix usage of error_reportf_err() +- esp: check for NULL result from scsi_device_find() +- migration: fix coverity migrate_mode finding +- hw/core/cpu: Remove final vestiges of dynamic state tracing +- target/riscv: Fix mcycle/minstret increment behavior +- chardev/char.c: fix "abstract device type" error message +- hw/net: cadence_gem: Fix MDIO_OP_xxx values + * Sat Aug 30 2025 Pengrui Zhang - 11:8.2.0-43 - qemu-img: fix division by zero in bench_cb() for zero-sized images - target/i386: cpu: set correct supported XCR0 features for TCG diff --git a/target-riscv-Fix-mcycle-minstret-increment-behavior.patch b/target-riscv-Fix-mcycle-minstret-increment-behavior.patch new file mode 100644 index 00000000..3892b545 --- /dev/null +++ b/target-riscv-Fix-mcycle-minstret-increment-behavior.patch @@ -0,0 +1,58 @@ +From 57ac816f1896427cfc4843961a6db3a08bb04d78 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Tue, 26 Dec 2023 12:05:00 +0800 +Subject: [PATCH] target/riscv: Fix mcycle/minstret increment behavior + +The mcycle/minstret counter's stop flag is mistakenly updated on a copy +on stack. Thus the counter increments even when the CY/IR bit in the +mcountinhibit register is set. This commit corrects its behavior. + +Backport from QEMU official community: 5cb0e7abe163 + +Fixes: 3780e33732f88 (target/riscv: Support mcycle/minstret write operation) +Signed-off-by: Xu Lu +Reviewed-by: Daniel Henrique Barboza +Signed-off-by: Michael Tokarev +--- + target/riscv/csr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/target/riscv/csr.c b/target/riscv/csr.c +index d1bb7bc0d3..3d9ea0c316 100644 +--- a/target/riscv/csr.c ++++ b/target/riscv/csr.c +@@ -907,11 +907,11 @@ static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) + static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + bool upper_half, uint32_t ctr_idx) + { +- PMUCTRState counter = env->pmu_ctrs[ctr_idx]; +- target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev : +- counter.mhpmcounter_prev; +- target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val : +- counter.mhpmcounter_val; ++ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; ++ target_ulong ctr_prev = upper_half ? counter->mhpmcounterh_prev : ++ counter->mhpmcounter_prev; ++ target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val : ++ counter->mhpmcounter_val; + + if (get_field(env->mcountinhibit, BIT(ctr_idx))) { + /* +@@ -919,12 +919,12 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + * stop the icount counting. Just return the counter value written by + * the supervisor to indicate that counter was not incremented. + */ +- if (!counter.started) { ++ if (!counter->started) { + *val = ctr_val; + return RISCV_EXCP_NONE; + } else { + /* Mark that the counter has been stopped */ +- counter.started = false; ++ counter->started = false; + } + } + +-- +2.33.0 + diff --git a/target-riscv-kvm-do-not-use-non-portable-strerrornam.patch b/target-riscv-kvm-do-not-use-non-portable-strerrornam.patch new file mode 100644 index 00000000..9f10900b --- /dev/null +++ b/target-riscv-kvm-do-not-use-non-portable-strerrornam.patch @@ -0,0 +1,75 @@ +From b33e6b4d345b44bf8e92ae163446bbd125fbd18c Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Mon, 18 Dec 2023 17:22:44 +0100 +Subject: [PATCH] target/riscv/kvm: do not use non-portable strerrorname_np() + +strerrorname_np is non-portable and breaks building with musl libc. + +Use strerror(errno) instead, like we do other places. + +Backport from QEMU official community: d424db235434 + +Cc: qemu-stable@nongnu.org +Fixes: commit 082e9e4a58ba (target/riscv/kvm: improve 'init_multiext_cfg' error msg) +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2041 +Buglink: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15541 +Signed-off-by: Natanael Copa +Reviewed-by: Daniel Henrique Barboza +Signed-off-by: Michael Tokarev +--- + target/riscv/kvm/kvm-cpu.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c +index b3dc2070f9..9615e68ce4 100644 +--- a/target/riscv/kvm/kvm-cpu.c ++++ b/target/riscv/kvm/kvm-cpu.c +@@ -836,9 +836,8 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, + multi_ext_cfg->supported = false; + val = false; + } else { +- error_report("Unable to read ISA_EXT KVM register %s, " +- "error code: %s", multi_ext_cfg->name, +- strerrorname_np(errno)); ++ error_report("Unable to read ISA_EXT KVM register %s: %s", ++ multi_ext_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + } else { +@@ -899,8 +898,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + * + * Error out if we get any other errno. + */ +- error_report("Error when accessing get-reg-list, code: %s", +- strerrorname_np(errno)); ++ error_report("Error when accessing get-reg-list: %s", ++ strerror(errno)); + exit(EXIT_FAILURE); + } + +@@ -909,8 +908,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + reglist->n = rl_struct.n; + ret = ioctl(kvmcpu->cpufd, KVM_GET_REG_LIST, reglist); + if (ret) { +- error_report("Error when reading KVM_GET_REG_LIST, code %s ", +- strerrorname_np(errno)); ++ error_report("Error when reading KVM_GET_REG_LIST: %s", ++ strerror(errno)); + exit(EXIT_FAILURE); + } + +@@ -931,9 +930,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { +- error_report("Unable to read ISA_EXT KVM register %s, " +- "error code: %s", multi_ext_cfg->name, +- strerrorname_np(errno)); ++ error_report("Unable to read ISA_EXT KVM register %s: %s", ++ multi_ext_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + +-- +2.33.0 + diff --git a/tests-unit-test-qmp-event-Drop-superfluous-mutex.patch b/tests-unit-test-qmp-event-Drop-superfluous-mutex.patch new file mode 100644 index 00000000..0f0da8e0 --- /dev/null +++ b/tests-unit-test-qmp-event-Drop-superfluous-mutex.patch @@ -0,0 +1,54 @@ +From 4274e3fc0f9eaf1f5b2bd754bc8d3026ca34b59d Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 22 Nov 2023 08:24:54 +0100 +Subject: [PATCH] tests/unit/test-qmp-event: Drop superfluous mutex + +Mutex @test_event_lock is held from fixture setup to teardown, +protecting global variable @test_event_data. But tests always run one +after the other, so this is superfluous. It also confuses Coverity. +Drop the mutex. + +Backport from QEMU official community: c363764a6048 + +Fixes: CID 1527425 +Signed-off-by: Markus Armbruster +Reviewed-by: Thomas Huth +Message-ID: <20231122072456.2518816-2-armbru@redhat.com> +Signed-off-by: Thomas Huth +--- + tests/unit/test-qmp-event.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/tests/unit/test-qmp-event.c b/tests/unit/test-qmp-event.c +index 3626d2372f..c2c44687d5 100644 +--- a/tests/unit/test-qmp-event.c ++++ b/tests/unit/test-qmp-event.c +@@ -30,7 +30,6 @@ typedef struct TestEventData { + } TestEventData; + + TestEventData *test_event_data; +-static GMutex test_event_lock; + + void test_qapi_event_emit(test_QAPIEvent event, QDict *d) + { +@@ -59,9 +58,6 @@ void test_qapi_event_emit(test_QAPIEvent event, QDict *d) + static void event_prepare(TestEventData *data, + const void *unused) + { +- /* Global variable test_event_data was used to pass the expectation, so +- test cases can't be executed at same time. */ +- g_mutex_lock(&test_event_lock); + test_event_data = data; + } + +@@ -69,7 +65,6 @@ static void event_teardown(TestEventData *data, + const void *unused) + { + test_event_data = NULL; +- g_mutex_unlock(&test_event_lock); + } + + static void event_test_add(const char *testpath, +-- +2.33.0 + diff --git a/vhost-scsi-fix-usage-of-error_reportf_err.patch b/vhost-scsi-fix-usage-of-error_reportf_err.patch new file mode 100644 index 00000000..e97ed0cd --- /dev/null +++ b/vhost-scsi-fix-usage-of-error_reportf_err.patch @@ -0,0 +1,68 @@ +From 7be6e400d6986f37e70f3f8e2fe6c312409b6a0f Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 13 Dec 2023 16:31:17 -0800 +Subject: [PATCH] vhost-scsi: fix usage of error_reportf_err() + +It is required to use error_report() instead of error_reportf_err(), if the +prior function does not take local_err as the argument. As a result, the +local_err is always NULL and segment fault may happen. + +vhost_scsi_start() +-> vhost_scsi_set_endpoint(s) --> does not allocate local_err +-> error_reportf_err() + -> error_vprepend() + -> g_string_append(newmsg, (*errp)->msg) --> (*errp) is NULL + +In addition, add ": " at the end of other error_reportf_err() logs. + +Backport from QEMU official community: 551bf7b4c179 + +Fixes: 7962e432b4e4 ("vhost-user-scsi: support reconnect to backend") +Signed-off-by: Dongli Zhang +Message-Id: <20231214003117.43960-1-dongli.zhang@oracle.com> +Reviewed-by: Feng Li +Reviewed-by: Raphael Norwitz +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/scsi/vhost-scsi.c | 4 ++-- + hw/scsi/vhost-user-scsi.c | 3 ++- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c +index 3126df9e1d..9929c0d14b 100644 +--- a/hw/scsi/vhost-scsi.c ++++ b/hw/scsi/vhost-scsi.c +@@ -91,13 +91,13 @@ static int vhost_scsi_start(VHostSCSI *s) + + ret = vhost_scsi_common_start(vsc, &local_err); + if (ret < 0) { +- error_reportf_err(local_err, "Error starting vhost-scsi"); ++ error_reportf_err(local_err, "Error starting vhost-scsi: "); + return ret; + } + + ret = vhost_scsi_set_endpoint(s); + if (ret < 0) { +- error_reportf_err(local_err, "Error setting vhost-scsi endpoint"); ++ error_report("Error setting vhost-scsi endpoint"); + vhost_scsi_common_stop(vsc); + } + +diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c +index 780f10559d..af18c4f3d3 100644 +--- a/hw/scsi/vhost-user-scsi.c ++++ b/hw/scsi/vhost-user-scsi.c +@@ -83,7 +83,8 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) + if (should_start) { + ret = vhost_user_scsi_start(s, &local_err); + if (ret < 0) { +- error_reportf_err(local_err, "unable to start vhost-user-scsi: %s", ++ error_reportf_err(local_err, ++ "unable to start vhost-user-scsi: %s: ", + strerror(-ret)); + qemu_chr_fe_disconnect(&vs->conf.chardev); + } +-- +2.33.0 + diff --git a/virtio-rng-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch b/virtio-rng-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch new file mode 100644 index 00000000..2dfa4a7c --- /dev/null +++ b/virtio-rng-Check-notifier-helpers-for-VIRTIO_CONFIG_.patch @@ -0,0 +1,63 @@ +From 5999b0bb74b1b668c2398073ba8f767d051daac8 Mon Sep 17 00:00:00 2001 +From: Hao Chen +Date: Wed, 25 Oct 2023 11:18:41 -0600 +Subject: [PATCH] virtio: rng: Check notifier helpers for VIRTIO_CONFIG_IRQ_IDX +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since the driver doesn't support interrupts, we must return early when +index is set to VIRTIO_CONFIG_IRQ_IDX. Basically the same thing Viresh +did for "91208dd297f2 virtio: i2c: Check notifier helpers for +VIRTIO_CONFIG_IRQ_IDX". + +Backport from QEMU official community: df72f01104ae + +Fixes: 544f0278afca ("virtio: introduce macro VIRTIO_CONFIG_IRQ_IDX") +Signed-off-by: Mathieu Poirier +Message-Id: <20231025171841.3379663-1-mathieu.poirier@linaro.org> +Tested-by: Leo Yan +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/vhost-user-rng.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c +index efc54cd3fb..24ac1a22c8 100644 +--- a/hw/virtio/vhost-user-rng.c ++++ b/hw/virtio/vhost-user-rng.c +@@ -129,6 +129,14 @@ static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) + { + VHostUserRNG *rng = VHOST_USER_RNG(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return; ++ } ++ + vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); + } + +@@ -136,6 +144,14 @@ static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx) + { + VHostUserRNG *rng = VHOST_USER_RNG(vdev); + ++ /* ++ * We don't support interrupts, return early if index is set to ++ * VIRTIO_CONFIG_IRQ_IDX. ++ */ ++ if (idx == VIRTIO_CONFIG_IRQ_IDX) { ++ return false; ++ } ++ + return vhost_virtqueue_pending(&rng->vhost_dev, idx); + } + +-- +2.33.0 + -- Gitee From b67b8fe74bac1bacd158554bc39560251c6dbdf8 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Fri, 5 Sep 2025 15:09:56 +0800 Subject: [PATCH 09/14] QEMU update to version 8.2.0-45 Signed-off-by: zhangpengrui --- ...lash-objects-and-register-properties.patch | 93 +++++++++++++++++++ qemu.spec | 6 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 Always-create-pflash-objects-and-register-properties.patch diff --git a/Always-create-pflash-objects-and-register-properties.patch b/Always-create-pflash-objects-and-register-properties.patch new file mode 100644 index 00000000..78a909b4 --- /dev/null +++ b/Always-create-pflash-objects-and-register-properties.patch @@ -0,0 +1,93 @@ +From 77e90909b868a7e394903e9f0e990f212e896242 Mon Sep 17 00:00:00 2001 +From: houmingyong +Date: Thu, 4 Sep 2025 10:50:38 +0800 +Subject: [PATCH] Always create pflash objects and register properties for QOM + even in confidential mode, to satisfy qemu_apply_machine_options. This fixes + the "Property 'virt-8.2-machine.pflash0' not found" error. + +Revert "hw/arm/virt: Move virt_flash_create() to machvirt_init()" +This reverts commit ddf23b6f58d3c605a083ad3f09388dcb6edf729e. +--- + hw/arm/virt.c | 31 ++++++++++++------------------- + 1 file changed, 12 insertions(+), 19 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index cf4156ed49..f7a9ba9a58 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -1407,10 +1407,10 @@ static PFlashCFI01 *virt_flash_create1(VirtMachineState *vms, + + static void virt_flash_create(VirtMachineState *vms) + { +- if (virt_machine_is_confidential(vms)) { +- return; +- } +- ++ /* Always create pflash objects and register properties for QOM ++ * even in confidential mode, to satisfy qemu_apply_machine_options. ++ * This fixes the "Property 'virt-8.2-machine.pflash0' not found" error. ++ */ + vms->flash[0] = virt_flash_create1(vms, "virt.flash0", "pflash0"); + vms->flash[1] = virt_flash_create1(vms, "virt.flash1", "pflash1"); + } +@@ -1449,10 +1449,6 @@ static void virt_flash_map(VirtMachineState *vms, + hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vms->memmap[VIRT_FLASH].base; + +- if (virt_machine_is_confidential(vms)) { +- return; +- } +- + virt_flash_map1(vms->flash[0], flashbase, flashsize, + secure_sysmem); + virt_flash_map1(vms->flash[1], flashbase + flashsize, flashsize, +@@ -1532,15 +1528,6 @@ static bool virt_firmware_init(VirtMachineState *vms, + const char *bios_name; + BlockBackend *pflash_blk0; + +- /* +- * For a confidential VM, the firmware image and any boot information, +- * including EFI variables, are stored in RAM in order to be measurable and +- * private. Create a RAM region and load the firmware image there. +- */ +- if (virt_machine_is_confidential(vms)) { +- return virt_confidential_firmware_init(vms, sysmem); +- } +- + /* Map legacy -drive if=pflash to machine properties */ + for (i = 0; i < ARRAY_SIZE(vms->flash); i++) { + pflash_cfi01_legacy_drive(vms->flash[i], +@@ -1551,7 +1538,12 @@ static bool virt_firmware_init(VirtMachineState *vms, + + pflash_blk0 = pflash_cfi01_get_blk(vms->flash[0]); + +- if (virtcca_cvm_enabled()) { ++ /* ++ * For a confidential VM, the firmware image and any boot information, ++ * including EFI variables, are stored in RAM in order to be measurable and ++ * private. Create a RAM region and load the firmware image there. ++ */ ++ if (virtcca_cvm_enabled() || virt_machine_is_confidential(vms)) { + return virt_confidential_firmware_init(vms, sysmem); + } + +@@ -2609,7 +2601,6 @@ static void machvirt_init(MachineState *machine) + } + + finalize_gic_version(vms); +- virt_flash_create(vms); + + possible_cpus = mc->possible_cpu_arch_ids(machine); + +@@ -4163,6 +4154,8 @@ static void virt_instance_init(Object *obj) + + vms->irqmap = a15irqmap; + ++ virt_flash_create(vms); ++ + vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); + vms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); + +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index cd6c74d9..ebed0562 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 44 +Release: 45 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1067,6 +1067,7 @@ Patch1050: hw-core-cpu-Remove-final-vestiges-of-dynamic-state-t.patch Patch1051: target-riscv-Fix-mcycle-minstret-increment-behavior.patch Patch1052: chardev-char.c-fix-abstract-device-type-error-messag.patch Patch1053: hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch +Patch1054: Always-create-pflash-objects-and-register-properties.patch BuildRequires: flex BuildRequires: gcc @@ -1665,6 +1666,9 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Fri Sep 05 2025 Pengrui Zhang - 11:8.2.0-45 +- Always create pflash objects and register properties for QOM + * Sat Aug 30 2025 Pengrui Zhang - 11:8.2.0-44 - tests/unit/test-qmp-event: Drop superfluous mutex - configure: use a native non-cross compiler for linux-user -- Gitee From 93e80e5dc525bc769de5175cb5e13ed18004089d Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Mon, 20 Oct 2025 18:01:35 +0800 Subject: [PATCH 10/14] QEMU update to version 8.2.0-46 Signed-off-by: zhangpengrui --- ...e-after-free-by-nullifying-timer-poi.patch | 44 ++++++++++++ ...nment-when-unmapping-excess-reservat.patch | 45 ++++++++++++ ....c-Enforce-CCA-and-virtCCA-isolation.patch | 72 +++++++++++++++++++ ...o-npcm7xx-fixup-out-of-bounds-access.patch | 52 ++++++++++++++ ...x-pba-read-vector-poll-end-calculati.patch | 42 +++++++++++ ...u_ram_alloc_from_fd-size-calculation.patch | 61 ++++++++++++++++ qemu.spec | 32 ++++++++- ...o-ccw-don-t-crash-on-weird-RAM-sizes.patch | 59 +++++++++++++++ ...-switch-session-to-non-blocking-mode.patch | 57 +++++++++++++++ ...c-Fix-mtDPDES-targeting-SMT-siblings.patch | 42 +++++++++++ ...-non-maskable-interrupt-while-halted.patch | 61 ++++++++++++++++ ...w-vDPA-to-work-on-big-endian-machine.patch | 57 +++++++++++++++ ...eplace-basename-with-g_path_get_base.patch | 52 ++++++++++++++ ...eport-only-stop-copy-size-in-vfio_st.patch | 52 ++++++++++++++ vfio-pci-Clear-MSI-X-IRQ-index-always.patch | 55 ++++++++++++++ 15 files changed, 782 insertions(+), 1 deletion(-) create mode 100644 block-qed-fix-use-after-free-by-nullifying-timer-poi.patch create mode 100644 elfload-Fix-alignment-when-unmapping-excess-reservat.patch create mode 100644 hw-arm-boot.c-Enforce-CCA-and-virtCCA-isolation.patch create mode 100644 hw-gpio-npcm7xx-fixup-out-of-bounds-access.patch create mode 100644 pci-msix-Fix-msix-pba-read-vector-poll-end-calculati.patch create mode 100644 physmem-fix-qemu_ram_alloc_from_fd-size-calculation.patch create mode 100644 s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch create mode 100644 ssh-Do-not-switch-session-to-non-blocking-mode.patch create mode 100644 target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch create mode 100644 target-ppc-Fix-non-maskable-interrupt-while-halted.patch create mode 100644 vdpa-Allow-vDPA-to-work-on-big-endian-machine.patch create mode 100644 vfio-container-Replace-basename-with-g_path_get_base.patch create mode 100644 vfio-migration-Report-only-stop-copy-size-in-vfio_st.patch create mode 100644 vfio-pci-Clear-MSI-X-IRQ-index-always.patch diff --git a/block-qed-fix-use-after-free-by-nullifying-timer-poi.patch b/block-qed-fix-use-after-free-by-nullifying-timer-poi.patch new file mode 100644 index 00000000..47e84662 --- /dev/null +++ b/block-qed-fix-use-after-free-by-nullifying-timer-poi.patch @@ -0,0 +1,44 @@ +From 83d07b4feac945d8b483642d28c8eebcabc4fa12 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 21:40:03 -0400 +Subject: [PATCH] block/qed: fix use-after-free by nullifying timer pointer + after free + +cheery-pick from 9f1e501fb1cb83b46f49df8bb2fb0950ea5fa5a5 + +This error was discovered by fuzzing qemu-img. + +In the QED block driver, the need_check_timer timer is freed in +bdrv_qed_detach_aio_context, but the pointer to the timer is not +set to NULL. This can lead to a use-after-free scenario +in bdrv_qed_drain_begin(). + +The need_check_timer pointer is set to NULL after freeing the timer. +Which helps catch this condition when checking in bdrv_qed_drain_begin(). + +Closes: https://gitlab.com/qemu-project/qemu/-/issues/2852 +Signed-off-by: Denis Rastyogin +Message-ID: <20250304083927.37681-1-gerben@altlinux.org> +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 2ad638a3d160923ef3dbf87c73944e6e44bdc724) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + block/qed.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/block/qed.c b/block/qed.c +index bc2f0a61c0..b986353979 100644 +--- a/block/qed.c ++++ b/block/qed.c +@@ -353,6 +353,7 @@ static void bdrv_qed_detach_aio_context(BlockDriverState *bs) + + qed_cancel_need_check_timer(s); + timer_free(s->need_check_timer); ++ s->need_check_timer = NULL; + } + + static void bdrv_qed_attach_aio_context(BlockDriverState *bs, +-- +2.33.0 + diff --git a/elfload-Fix-alignment-when-unmapping-excess-reservat.patch b/elfload-Fix-alignment-when-unmapping-excess-reservat.patch new file mode 100644 index 00000000..6fbeae6d --- /dev/null +++ b/elfload-Fix-alignment-when-unmapping-excess-reservat.patch @@ -0,0 +1,45 @@ +From ecdd2a7388d57c88511e8d7ffc0ce0956253c0df Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 21:57:52 -0400 +Subject: [PATCH] elfload: Fix alignment when unmapping excess reservation + +cheery-pick from 2c837358c2f3b30524754ffebedb6c5d60ae3552 + +When complying with the alignment requested in the ELF and unmapping +the excess reservation, having align_end not aligned to the guest page +causes the unmap to be rejected by the alignment check at +target_munmap and later brk adjustments hit an EEXIST. + +Fix by aligning the start of region to be unmapped. + +Fixes: c81d1fafa6 ("linux-user: Honor elf alignment when placing images") +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1913 +Signed-off-by: Fabiano Rosas +[rth: Align load_end as well.] +Signed-off-by: Richard Henderson +Message-ID: <20250213143558.10504-1-farosas@suse.de> +(cherry picked from commit 4b7b20a3b72c5000ea71bef505c16e6e628268b6) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + linux-user/elfload.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/linux-user/elfload.c b/linux-user/elfload.c +index 87eb318b46..f0c9095d57 100644 +--- a/linux-user/elfload.c ++++ b/linux-user/elfload.c +@@ -3417,8 +3417,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src, + + if (align_size != reserve_size) { + abi_ulong align_addr = ROUND_UP(load_addr, align); +- abi_ulong align_end = align_addr + reserve_size; +- abi_ulong load_end = load_addr + align_size; ++ abi_ulong align_end = TARGET_PAGE_ALIGN(align_addr + reserve_size); ++ abi_ulong load_end = TARGET_PAGE_ALIGN(load_addr + align_size); + + if (align_addr != load_addr) { + target_munmap(load_addr, align_addr - load_addr); +-- +2.33.0 + diff --git a/hw-arm-boot.c-Enforce-CCA-and-virtCCA-isolation.patch b/hw-arm-boot.c-Enforce-CCA-and-virtCCA-isolation.patch new file mode 100644 index 00000000..3068dc23 --- /dev/null +++ b/hw-arm-boot.c-Enforce-CCA-and-virtCCA-isolation.patch @@ -0,0 +1,72 @@ +From 6c6e62479472fc67b92d7bce2d6e8c2b379b6fe1 Mon Sep 17 00:00:00 2001 +From: yxk +Date: Thu, 4 Sep 2025 22:47:10 +0800 +Subject: [PATCH] hw/arm boot.c: Enforce CCA and virtCCA isolation. + +Since both CCA and virtCCA utilize info->confidential in +arm_setup_firmware_boot, we must distinguish between them. + +Signed-off-by: yxk +--- + hw/arm/boot.c | 29 ++++++++++++++++------------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/hw/arm/boot.c b/hw/arm/boot.c +index 4f5bf6e77c..9e28199a68 100644 +--- a/hw/arm/boot.c ++++ b/hw/arm/boot.c +@@ -1228,17 +1228,18 @@ static void arm_setup_confidential_firmware_boot(ARMCPU *cpu, + uint64_t tmi_version = 0; + int ret = -1; + +- if (kvm_enabled()) { ++ if (kvm_enabled() && virtcca_cvm_enabled()) { + ret = kvm_ioctl(kvm_state, KVM_GET_TMI_VERSION, &tmi_version); ++ if (ret < 0) { ++ error_report("please check the kernel version!"); ++ exit(EXIT_FAILURE); ++ } ++ if (tmi_version < MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM) { ++ error_report("please check the tmi version!"); ++ exit(EXIT_FAILURE); ++ } + } +- if (ret < 0) { +- error_report("please check the kernel version!"); +- exit(EXIT_FAILURE); +- } +- if (tmi_version < MIN_TMI_VERSION_FOR_UEFI_BOOTED_CVM) { +- error_report("please check the tmi version!"); +- exit(EXIT_FAILURE); +- } ++ + ssize_t fw_size; + const char *fname; + AddressSpace *as = arm_boot_address_space(cpu, info); +@@ -1273,7 +1274,7 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info, con + * DTB to the base of RAM for the bootloader to pick up. + */ + info->dtb_start = info->loader_start; +- if (info->confidential) ++ if (info->confidential && virtcca_cvm_enabled()) + tmm_add_ram_region(UEFI_LOADER_START, UEFI_MAX_SIZE, info->dtb_start, DTB_MAX , true); + } + +@@ -1317,9 +1318,11 @@ static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info, con + + if (info->confidential) { + arm_setup_confidential_firmware_boot(cpu, info, firmware_filename); +- virtcca_kvm_get_mmio_addr(&mmio_start, &mmio_size); +- kvm_load_user_data(info->loader_start, DTB_MAX, mmio_start, mmio_size, info->ram_size, +- (struct kvm_numa_info *)info->numa_info); ++ if (virtcca_cvm_enabled()) { ++ virtcca_kvm_get_mmio_addr(&mmio_start, &mmio_size); ++ kvm_load_user_data(info->loader_start, DTB_MAX, mmio_start, mmio_size, info->ram_size, ++ (struct kvm_numa_info *)info->numa_info); ++ } + } + /* + * We will start from address 0 (typically a boot ROM image) in the +-- +2.33.0 + diff --git a/hw-gpio-npcm7xx-fixup-out-of-bounds-access.patch b/hw-gpio-npcm7xx-fixup-out-of-bounds-access.patch new file mode 100644 index 00000000..a214125e --- /dev/null +++ b/hw-gpio-npcm7xx-fixup-out-of-bounds-access.patch @@ -0,0 +1,52 @@ +From 419104f21e81d883f1a41540512e86750363600e Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 22:18:09 -0400 +Subject: [PATCH] hw/gpio: npcm7xx: fixup out-of-bounds access +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 27e3d81ffd81bb57b02816fc9cfe24f621d64c59 + +The reg isn't validated to be a possible register before +it's dereferenced for one case. The mmio space registered +for the gpio device is 4KiB but there aren't that many +registers in the struct. + +Cc: qemu-stable@nongnu.org +Fixes: 526dbbe0874 ("hw/gpio: Add GPIO model for Nuvoton NPCM7xx") +Signed-off-by: Patrick Venture +Reviewed-by: Philippe Mathieu-Daudé +Message-id: 20250226024603.493148-1-venture@google.com +Signed-off-by: Peter Maydell +(cherry picked from commit 3b2e22c0bbe2ce07123d93961d52f17644562cd7) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/gpio/npcm7xx_gpio.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c +index 3376901ab1..c75f9e073d 100644 +--- a/hw/gpio/npcm7xx_gpio.c ++++ b/hw/gpio/npcm7xx_gpio.c +@@ -220,8 +220,6 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v, + return; + } + +- diff = s->regs[reg] ^ value; +- + switch (reg) { + case NPCM7XX_GPIO_TLOCK1: + case NPCM7XX_GPIO_TLOCK2: +@@ -242,6 +240,7 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v, + case NPCM7XX_GPIO_PU: + case NPCM7XX_GPIO_PD: + case NPCM7XX_GPIO_IEM: ++ diff = s->regs[reg] ^ value; + s->regs[reg] = value; + npcm7xx_gpio_update_pins(s, diff); + break; +-- +2.33.0 + diff --git a/pci-msix-Fix-msix-pba-read-vector-poll-end-calculati.patch b/pci-msix-Fix-msix-pba-read-vector-poll-end-calculati.patch new file mode 100644 index 00000000..0915bef5 --- /dev/null +++ b/pci-msix-Fix-msix-pba-read-vector-poll-end-calculati.patch @@ -0,0 +1,42 @@ +From dea0186756336e64133f2613cbb9bda1d5fb6515 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 22:34:38 -0400 +Subject: [PATCH] pci/msix: Fix msix pba read vector poll end calculation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from 27c41db3f5bdfa40729ec749603e006e57c1e6ef + +The end vector calculation has a bug that results in polling fewer +than required vectors when reading at a non-zero offset in PBA memory. + +Fixes: bbef882cc193 ("msi: add API to get notified about pending bit poll") +Signed-off-by: Nicholas Piggin +Message-Id: <20241212120402.1475053-1-npiggin@gmail.com> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 42e2a7a0ab23784e44fcb18369e06067abc89305) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/pci/msix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/pci/msix.c b/hw/pci/msix.c +index cd817f4ca8..057a1305cd 100644 +--- a/hw/pci/msix.c ++++ b/hw/pci/msix.c +@@ -250,7 +250,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, + PCIDevice *dev = opaque; + if (dev->msix_vector_poll_notifier) { + unsigned vector_start = addr * 8; +- unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr); ++ unsigned vector_end = MIN((addr + size) * 8, dev->msix_entries_nr); + dev->msix_vector_poll_notifier(dev, vector_start, vector_end); + } + +-- +2.33.0 + diff --git a/physmem-fix-qemu_ram_alloc_from_fd-size-calculation.patch b/physmem-fix-qemu_ram_alloc_from_fd-size-calculation.patch new file mode 100644 index 00000000..bc9bfb21 --- /dev/null +++ b/physmem-fix-qemu_ram_alloc_from_fd-size-calculation.patch @@ -0,0 +1,61 @@ +From ec16a25f34ac8d2de561766e1d3ece6601ec9374 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 22:42:08 -0400 +Subject: [PATCH] physmem: fix qemu_ram_alloc_from_fd size calculation + +cheery-pick from 4afd17ebcc6a9412ba8009410e448a00af45f05b + +qemu_ram_alloc_from_fd allocates space if file_size == 0. If non-zero, +it uses the existing space and verifies it is large enough, but the +verification was broken when the offset parameter was introduced. As +a result, a file smaller than offset passes the verification and causes +errors later. Fix that, and update the error message to include offset. + +Peter provides this concise reproducer: + + $ touch ramfile + $ truncate -s 64M ramfile + $ ./qemu-system-x86_64 -object memory-backend-file,mem-path=./ramfile,offset=128M,size=128M,id=mem1,prealloc=on + qemu-system-x86_64: qemu_prealloc_mem: preallocating memory failed: Bad address + +With the fix, the error message is: + qemu-system-x86_64: mem1 backing store size 0x4000000 is too small for 'size' option 0x8000000 plus 'offset' option 0x8000000 + +Cc: qemu-stable@nongnu.org +Fixes: 4b870dc4d0c0 ("hostmem-file: add offset option") +Signed-off-by: Steve Sistare +Reviewed-by: Peter Xu +Acked-by: David Hildenbrand +Link: https://lore.kernel.org/r/1736967650-129648-3-git-send-email-steven.sistare@oracle.com +Signed-off-by: Fabiano Rosas +(cherry picked from commit 719168fba7c3215cc996dcfd32a6e5e9c7b8eee0) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + system/physmem.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/system/physmem.c b/system/physmem.c +index 8f4be2d131..e862f99ff6 100644 +--- a/system/physmem.c ++++ b/system/physmem.c +@@ -1945,10 +1945,12 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, + + size = HOST_PAGE_ALIGN(size); + file_size = get_file_size(fd); +- if (file_size > offset && file_size < (offset + size)) { +- error_setg(errp, "backing store size 0x%" PRIx64 +- " does not match 'size' option 0x" RAM_ADDR_FMT, +- file_size, size); ++ if (file_size && file_size < offset + size) { ++ error_setg(errp, "%s backing store size 0x%" PRIx64 ++ " is too small for 'size' option 0x" RAM_ADDR_FMT ++ " plus 'offset' option 0x%" PRIx64, ++ memory_region_name(mr), file_size, size, ++ (uint64_t)offset); + return NULL; + } + +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index ebed0562..d97d3a54 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 45 +Release: 46 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1068,6 +1068,20 @@ Patch1051: target-riscv-Fix-mcycle-minstret-increment-behavior.patch Patch1052: chardev-char.c-fix-abstract-device-type-error-messag.patch Patch1053: hw-net-cadence_gem-Fix-MDIO_OP_xxx-values.patch Patch1054: Always-create-pflash-objects-and-register-properties.patch +Patch1055: vdpa-Allow-vDPA-to-work-on-big-endian-machine.patch +Patch1056: vfio-container-Replace-basename-with-g_path_get_base.patch +Patch1057: vfio-migration-Report-only-stop-copy-size-in-vfio_st.patch +Patch1058: vfio-pci-Clear-MSI-X-IRQ-index-always.patch +Patch1059: hw-arm-boot.c-Enforce-CCA-and-virtCCA-isolation.patch +Patch1060: block-qed-fix-use-after-free-by-nullifying-timer-poi.patch +Patch1061: hw-gpio-npcm7xx-fixup-out-of-bounds-access.patch +Patch1062: pci-msix-Fix-msix-pba-read-vector-poll-end-calculati.patch +Patch1063: physmem-fix-qemu_ram_alloc_from_fd-size-calculation.patch +Patch1064: s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch +Patch1065: ssh-Do-not-switch-session-to-non-blocking-mode.patch +Patch1066: target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch +Patch1067: target-ppc-Fix-non-maskable-interrupt-while-halted.patch +Patch1068: elfload-Fix-alignment-when-unmapping-excess-reservat.patch BuildRequires: flex BuildRequires: gcc @@ -1666,6 +1680,22 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Mon Oct 20 2025 Pengrui Zhang - 11:8.2.0-46 +- vdpa: Allow vDPA to work on big-endian machine +- vfio/container: Replace basename with g_path_get_basename +- vfio/migration: Report only stop-copy size in vfio_state_pending_exact() +- vfio/pci: Clear MSI-X IRQ index always +- hw/arm boot.c: Enforce CCA and virtCCA isolation. +- block/qed: fix use-after-free by nullifying timer pointer after free +- hw/gpio: npcm7xx: fixup out-of-bounds access +- pci/msix: Fix msix pba read vector poll end calculation +- physmem: fix qemu_ram_alloc_from_fd size calculation +- s390x/s390-virtio-ccw: don't crash on weird RAM sizes +- ssh: Do not switch session to non-blocking mode +- target/ppc: Fix mtDPDES targeting SMT siblings +- target/ppc: Fix non-maskable interrupt while halted +- elfload: Fix alignment when unmapping excess reservation + * Fri Sep 05 2025 Pengrui Zhang - 11:8.2.0-45 - Always create pflash objects and register properties for QOM diff --git a/s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch b/s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch new file mode 100644 index 00000000..385897e5 --- /dev/null +++ b/s390x-s390-virtio-ccw-don-t-crash-on-weird-RAM-sizes.patch @@ -0,0 +1,59 @@ +From c380600ce0baf141bfd94c1dfec5a6b4ea29024a Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Thu, 31 Jul 2025 22:51:14 -0400 +Subject: [PATCH] s390x/s390-virtio-ccw: don't crash on weird RAM sizes + +cheery-pick from f19312d014633e9ae942b75ead53333a4b2ec0c2 + +KVM is not happy when starting a VM with weird RAM sizes: + + # qemu-system-s390x --enable-kvm --nographic -m 1234K + qemu-system-s390x: kvm_set_user_memory_region: KVM_SET_USER_MEMORY_REGION + failed, slot=0, start=0x0, size=0x244000: Invalid argument + kvm_set_phys_mem: error registering slot: Invalid argument + Aborted (core dumped) + +Let's handle that in a better way by rejecting such weird RAM sizes +right from the start: + + # qemu-system-s390x --enable-kvm --nographic -m 1234K + qemu-system-s390x: ram size must be multiples of 1 MiB + +Message-ID: <20241219144115.2820241-2-david@redhat.com> +Acked-by: Michael S. Tsirkin +Reviewed-by: Eric Farman +Reviewed-by: Thomas Huth +Acked-by: Janosch Frank +Signed-off-by: David Hildenbrand +(cherry picked from commit 14e568ab4836347481af2e334009c385f456a734) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/s390x/s390-virtio-ccw.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c +index 7262725d2e..6e44c1dd6a 100644 +--- a/hw/s390x/s390-virtio-ccw.c ++++ b/hw/s390x/s390-virtio-ccw.c +@@ -176,6 +176,17 @@ static void s390_memory_init(MemoryRegion *ram) + { + MemoryRegion *sysmem = get_system_memory(); + ++ if (!QEMU_IS_ALIGNED(memory_region_size(ram), 1 * MiB)) { ++ /* ++ * SCLP cannot possibly expose smaller granularity right now and KVM ++ * cannot handle smaller granularity. As we don't support NUMA, the ++ * region size directly corresponds to machine->ram_size, and the region ++ * is a single RAM memory region. ++ */ ++ error_report("ram size must be multiples of 1 MiB"); ++ exit(EXIT_FAILURE); ++ } ++ + /* allocate RAM for core */ + memory_region_add_subregion(sysmem, 0, ram); + +-- +2.33.0 + diff --git a/ssh-Do-not-switch-session-to-non-blocking-mode.patch b/ssh-Do-not-switch-session-to-non-blocking-mode.patch new file mode 100644 index 00000000..2049e64d --- /dev/null +++ b/ssh-Do-not-switch-session-to-non-blocking-mode.patch @@ -0,0 +1,57 @@ +From fdd0468f6da2e8bd7ac1414a0150efc471fa1291 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 01:49:10 -0400 +Subject: [PATCH] ssh: Do not switch session to non-blocking mode + +cheery-pick from 6d52a53e7bd886e7852a6be9694901a23752c88f + +The libssh does not handle non-blocking mode in SFTP correctly. The +driver code already changes the mode to blocking for the SFTP +initialization, but for some reason changes to non-blocking mode. +This used to work accidentally until libssh in 0.11 branch merged +the patch to avoid infinite looping in case of network errors: + +https://gitlab.com/libssh/libssh-mirror/-/merge_requests/498 + +Since then, the ssh driver in qemu fails to read files over SFTP +as the first SFTP messages exchanged after switching the session +to non-blocking mode return SSH_AGAIN, but that message is lost +int the SFTP internals and interpretted as SSH_ERROR, which is +returned to the caller: + +https://gitlab.com/libssh/libssh-mirror/-/issues/280 + +This is indeed an issue in libssh that we should address in the +long term, but it will require more work on the internals. For +now, the SFTP is not supported in non-blocking mode. + +Fixes: https://gitlab.com/libssh/libssh-mirror/-/issues/280 +Signed-off-by: Jakub Jelen +Signed-off-by: Richard W.M. Jones +Message-ID: <20241113125526.2495731-1-rjones@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit fbdea3d6c13d5a75895c287a004c6f1a6bf6c164) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + block/ssh.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/block/ssh.c b/block/ssh.c +index 2748253d4a..b2da9bb4c8 100644 +--- a/block/ssh.c ++++ b/block/ssh.c +@@ -860,9 +860,6 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags, + goto err; + } + +- /* Go non-blocking. */ +- ssh_set_blocking(s->session, 0); +- + if (s->attrs->type == SSH_FILEXFER_TYPE_REGULAR) { + bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; + } +-- +2.33.0 + diff --git a/target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch b/target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch new file mode 100644 index 00000000..abea3d4e --- /dev/null +++ b/target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch @@ -0,0 +1,42 @@ +From db48224bbd2364f557ad0b29adc52d7195f14411 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 02:17:53 -0400 +Subject: [PATCH] target/ppc: Fix mtDPDES targeting SMT siblings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from a0f6b02792a3332c6d108f6eef002b97e30e4ab5 + +A typo in the loop over SMT threads to set irq level for doorbells +when storing to DPDES meant everything was aimed at the CPU executing +the instruction. + +Cc: qemu-stable@nongnu.org +Fixes: d24e80b2ae ("target/ppc: Add msgsnd/p and DPDES SMT support") +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Richard Henderson +Signed-off-by: Nicholas Piggin +(cherry picked from commit 0324d236d2918c18a9ad4a1081b1083965a1433b) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + target/ppc/misc_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c +index a05bdf78c9..a8d0501996 100644 +--- a/target/ppc/misc_helper.c ++++ b/target/ppc/misc_helper.c +@@ -283,7 +283,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val) + PowerPCCPU *ccpu = POWERPC_CPU(ccs); + uint32_t thread_id = ppc_cpu_tir(ccpu); + +- ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id)); ++ ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id)); + } + qemu_mutex_unlock_iothread(); + } +-- +2.33.0 + diff --git a/target-ppc-Fix-non-maskable-interrupt-while-halted.patch b/target-ppc-Fix-non-maskable-interrupt-while-halted.patch new file mode 100644 index 00000000..d9ee57d6 --- /dev/null +++ b/target-ppc-Fix-non-maskable-interrupt-while-halted.patch @@ -0,0 +1,61 @@ +From fb3b1e10d05d62879e51d2221c199eb7b138eaa1 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 02:25:13 -0400 +Subject: [PATCH] target/ppc: Fix non-maskable interrupt while halted + +cheery-pick from dec1eee77fc548049c8cb443a1f8176fa0c2d3c4 + +The ppc (pnv and spapr) NMI injection code does not go through the +asynchronous interrupt path and set a bit in env->pending_interrupts +and raise an interrupt request that the cpu_exec() loop can see. +Instead it injects the exception directly into registers. + +This can lead to cpu_exec() missing that the thread has work to do, +if a NMI is injected while it was idle. + +Fix this by clearing halted when injecting the interrupt. Probably +NMI injection should be reworked to use the interrupt request interface, +but this seems to work as a minimal fix. + +Fixes: 3431648272d3 ("spapr: Add support for new NMI interface") +Reviewed-by: Glenn Miles +Signed-off-by: Nicholas Piggin +(cherry picked from commit fa416ae6157a933ad3f7106090684759baaaf3c9) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + target/ppc/excp_helper.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c +index a42743a3e0..6a822b5952 100644 +--- a/target/ppc/excp_helper.c ++++ b/target/ppc/excp_helper.c +@@ -2558,10 +2558,16 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) + } + } + ++/* ++ * system reset is not delivered via normal irq method, so have to set ++ * halted = 0 to resume CPU running if it was halted. Possibly we should ++ * move it over to using PPC_INTERRUPT_RESET rather than async_run_on_cpu. ++ */ + void ppc_cpu_do_system_reset(CPUState *cs) + { + PowerPCCPU *cpu = POWERPC_CPU(cs); + ++ cs->halted = 0; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + } + +@@ -2583,6 +2589,7 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) + + /* Anything for nested required here? MSR[HV] bit? */ + ++ cs->halted = 0; + powerpc_set_excp_state(cpu, vector, msr); + } + +-- +2.33.0 + diff --git a/vdpa-Allow-vDPA-to-work-on-big-endian-machine.patch b/vdpa-Allow-vDPA-to-work-on-big-endian-machine.patch new file mode 100644 index 00000000..495a3170 --- /dev/null +++ b/vdpa-Allow-vDPA-to-work-on-big-endian-machine.patch @@ -0,0 +1,57 @@ +From e9252f173b62ce2dac563249a200c3eabc028710 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 3 Sep 2025 17:08:37 +0800 +Subject: [PATCH] vdpa: Allow vDPA to work on big-endian machine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from b027f55a994af885a7a498a40373a2dcc2d8b15e + +Add .set_vnet_le() function that always returns success, assuming that +vDPA h/w always implements LE data format. Otherwise, QEMU disables vDPA and +outputs the message: +"backend does not support LE vnet headers; falling back on userspace virtio" + +Reviewed-by: Michael S. Tsirkin +Acked-by: Eugenio Pérez +Signed-off-by: Konstantin Shkolnyy +Signed-off-by: gubin +--- + net/vhost-vdpa.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c +index d0614d7954..68cabe2d40 100644 +--- a/net/vhost-vdpa.c ++++ b/net/vhost-vdpa.c +@@ -266,6 +266,18 @@ static bool vhost_vdpa_has_ufo(NetClientState *nc) + + } + ++/* ++ * FIXME: vhost_vdpa doesn't have an API to "set h/w endianness". But it's ++ * reasonable to assume that h/w is LE by default, because LE is what ++ * virtio 1.0 and later ask for. So, this function just says "yes, the h/w is ++ * LE". Otherwise, on a BE machine, higher-level code would mistakely think ++ * the h/w is BE and can't support VDPA for a virtio 1.0 client. ++ */ ++static int vhost_vdpa_set_vnet_le(NetClientState *nc, bool enable) ++{ ++ return 0; ++} ++ + static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc, + Error **errp) + { +@@ -429,6 +441,7 @@ static NetClientInfo net_vhost_vdpa_info = { + .cleanup = vhost_vdpa_cleanup, + .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, + .has_ufo = vhost_vdpa_has_ufo, ++ .set_vnet_le = vhost_vdpa_set_vnet_le, + .check_peer_type = vhost_vdpa_check_peer_type, + .set_steering_ebpf = vhost_vdpa_set_steering_ebpf, + }; +-- +2.33.0 + diff --git a/vfio-container-Replace-basename-with-g_path_get_base.patch b/vfio-container-Replace-basename-with-g_path_get_base.patch new file mode 100644 index 00000000..905aacb0 --- /dev/null +++ b/vfio-container-Replace-basename-with-g_path_get_base.patch @@ -0,0 +1,52 @@ +From bdfe852421d4b4e5da3e04931967223726fea9e2 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 3 Sep 2025 17:15:11 +0800 +Subject: [PATCH] vfio/container: Replace basename with g_path_get_basename +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 213ae3ffda463c0503e39e0cf827511b5298c314 + +g_path_get_basename() is a portable utility function that has the +advantage of not modifing the string argument. It also fixes a compile +breakage with the Musl C library reported in [1]. + +[1] https://lore.kernel.org/all/20231212010228.2701544-1-raj.khem@gmail.com/ + +Reported-by: Khem Raj +Reviewed-by: Eric Auger +Reviewed-by: Zhao Liu +Reviewed-by: Zhenzhong Duan +Signed-off-by: Cédric Le Goater +Signed-off-by: gubin +--- + hw/vfio/container.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/hw/vfio/container.c b/hw/vfio/container.c +index 539cf34b20..95b8cff33b 100644 +--- a/hw/vfio/container.c ++++ b/hw/vfio/container.c +@@ -987,7 +987,8 @@ static void vfio_put_base_device(VFIODevice *vbasedev) + + static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) + { +- char *tmp, group_path[PATH_MAX], *group_name; ++ char *tmp, group_path[PATH_MAX]; ++ g_autofree char *group_name = NULL; + int ret, groupid; + ssize_t len; + +@@ -1003,7 +1004,7 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) + + group_path[len] = 0; + +- group_name = basename(group_path); ++ group_name = g_path_get_basename(group_path); + if (sscanf(group_name, "%d", &groupid) != 1) { + error_setg_errno(errp, errno, "failed to read %s", group_path); + return -errno; +-- +2.33.0 + diff --git a/vfio-migration-Report-only-stop-copy-size-in-vfio_st.patch b/vfio-migration-Report-only-stop-copy-size-in-vfio_st.patch new file mode 100644 index 00000000..9a35846f --- /dev/null +++ b/vfio-migration-Report-only-stop-copy-size-in-vfio_st.patch @@ -0,0 +1,52 @@ +From ccb05dc51a8265b86b76a35cb291ee4990cf5019 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 3 Sep 2025 17:39:11 +0800 +Subject: [PATCH] vfio/migration: Report only stop-copy size in + vfio_state_pending_exact() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from 3b5948f808e3b99aedfa0aff45cffbe8b7ec07ed + +vfio_state_pending_exact() is used to update migration core how much +device data is left for the device migration. Currently, the sum of +pre-copy and stop-copy sizes of the VFIO device are reported. + +The pre-copy size is obtained via the VFIO_MIG_GET_PRECOPY_INFO ioctl, +which returns the amount of device data available to be transferred +while the device is in the PRE_COPY states. + +The stop-copy size is obtained via the VFIO_DEVICE_FEATURE_MIG_DATA_SIZE +ioctl, which returns the total amount of device data left to be +transferred in order to complete the device migration. + +According to the above, current implementation is wrong -- it reports +extra overlapping data because pre-copy size is already contained in +stop-copy size. Fix it by reporting only stop-copy size. + +Fixes: eda7362af959 ("vfio/migration: Add VFIO migration pre-copy support") +Signed-off-by: Avihai Horon +Reviewed-by: Cédric Le Goater +Signed-off-by: gubin +--- + hw/vfio/migration.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c +index 3924beb289..b81cb7e23b 100644 +--- a/hw/vfio/migration.c ++++ b/hw/vfio/migration.c +@@ -480,9 +480,6 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy, + + if (vfio_device_state_is_precopy(vbasedev)) { + vfio_query_precopy_size(migration); +- +- *must_precopy += +- migration->precopy_init_size + migration->precopy_dirty_size; + } + + trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy, +-- +2.33.0 + diff --git a/vfio-pci-Clear-MSI-X-IRQ-index-always.patch b/vfio-pci-Clear-MSI-X-IRQ-index-always.patch new file mode 100644 index 00000000..3b38556e --- /dev/null +++ b/vfio-pci-Clear-MSI-X-IRQ-index-always.patch @@ -0,0 +1,55 @@ +From 0e819d1b6e8391922dfa8bd66add74dd8f73f564 Mon Sep 17 00:00:00 2001 +From: gubin +Date: Wed, 3 Sep 2025 17:51:38 +0800 +Subject: [PATCH] vfio/pci: Clear MSI-X IRQ index always +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cherry-pick from d2b668fca5652760b435ce812a743bba03d2f316 + +When doing device assignment of a physical device, MSI-X can be +enabled with no vectors enabled and this sets the IRQ index to +VFIO_PCI_MSIX_IRQ_INDEX. However, when MSI-X is disabled, the IRQ +index is left untouched if no vectors are in use. Then, when INTx +is enabled, the IRQ index value is considered incompatible (set to +MSI-X) and VFIO_DEVICE_SET_IRQS fails. QEMU complains with : + +qemu-system-x86_64: vfio 0000:08:00.0: Failed to set up TRIGGER eventfd signaling for interrupt INTX-0: VFIO_DEVICE_SET_IRQS failure: Invalid argument + +To avoid that, unconditionaly clear the IRQ index when MSI-X is +disabled. + +Buglink: https://issues.redhat.com/browse/RHEL-21293 +Fixes: 5ebffa4e87e7 ("vfio/pci: use an invalid fd to enable MSI-X") +Cc: Jing Liu +Cc: Alex Williamson +Reviewed-by: Alex Williamson +Signed-off-by: Cédric Le Goater +Signed-off-by: gubin +--- + hw/vfio/pci.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c +index ce958848b6..7322c8be63 100644 +--- a/hw/vfio/pci.c ++++ b/hw/vfio/pci.c +@@ -828,9 +828,11 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) + } + } + +- if (vdev->nr_vectors) { +- vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); +- } ++ /* ++ * Always clear MSI-X IRQ index. A PF device could have enabled ++ * MSI-X with no vectors. See vfio_msix_enable(). ++ */ ++ vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + + vfio_msi_disable_common(vdev); + vfio_intx_enable(vdev, &err); +-- +2.33.0 + -- Gitee From 010f393d741ce1c53716c9a506704997293b6212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E4=BF=8A=E6=B7=87?= Date: Wed, 22 Oct 2025 20:02:39 +0800 Subject: [PATCH 11/14] QEMU update to version 8.2.0-47 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 马俊淇 (cherry picked from commit d4bc5c9ae173e3199c473608abe753522b416890) Signed-off-by: zhangpengrui --- ...virt-Introduce-a-IPIV-machine-option.patch | 105 +++++++ ...n-Fix-vfio-migration-isn-t-aborted-i.patch | 57 ++++ qemu.spec | 26 +- target-ppc-Fix-e200-duplicate-SPRs.patch | 46 ++++ target-riscv-kvm-Fix-exposure-of-Zkr.patch | 124 +++++++++ ...-update-the-KVM-regs-to-Linux-rvck-6.patch | 256 ++++++++++++++++++ ...-MVC-not-always-invalidating-transla.patch | 65 +++++ ...-gdbstub-incorrectly-handling-regist.patch | 69 +++++ ...-Fix-endian-bugs-in-shadow-virtqueue.patch | 98 +++++++ ...or-CSV3-VM-only-register-listener-to.patch | 42 +++ ...ix-size-check-in-dhclient-workaround.patch | 43 +++ x86-loader-only-patch-linux-kernels.patch | 46 ++++ 12 files changed, 976 insertions(+), 1 deletion(-) create mode 100644 hw-arm-virt-Introduce-a-IPIV-machine-option.patch create mode 100644 hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch create mode 100644 target-ppc-Fix-e200-duplicate-SPRs.patch create mode 100644 target-riscv-kvm-Fix-exposure-of-Zkr.patch create mode 100644 target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch create mode 100644 target-s390x-Fix-MVC-not-always-invalidating-transla.patch create mode 100644 target-sparc-Fix-gdbstub-incorrectly-handling-regist.patch create mode 100644 vdpa-Fix-endian-bugs-in-shadow-virtqueue.patch create mode 100644 vfio-container-For-CSV3-VM-only-register-listener-to.patch create mode 100644 virtio-net-Fix-size-check-in-dhclient-workaround.patch create mode 100644 x86-loader-only-patch-linux-kernels.patch diff --git a/hw-arm-virt-Introduce-a-IPIV-machine-option.patch b/hw-arm-virt-Introduce-a-IPIV-machine-option.patch new file mode 100644 index 00000000..7cf229cb --- /dev/null +++ b/hw-arm-virt-Introduce-a-IPIV-machine-option.patch @@ -0,0 +1,105 @@ +From 9db5487d84eef5ba38adefb70138644d1012f05f Mon Sep 17 00:00:00 2001 +From: Jinqian Yang +Date: Tue, 23 Sep 2025 12:09:39 +0800 +Subject: [PATCH] hw/arm/virt: Introduce a IPIV machine option + +Add the ipiv switch in the "-machine" to allow the guest to more +flexibly choose whether to enable ipiv. + +Signed-off-by: Jinqian Yang +--- + hw/arm/virt.c | 19 +++++++++++++++++++ + include/hw/arm/virt.h | 1 + + target/arm/kvm.c | 10 ++++++++-- + 3 files changed, 28 insertions(+), 2 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index f7a9ba9a58..db1b9715e0 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -3044,6 +3044,20 @@ static void virt_set_its(Object *obj, bool value, Error **errp) + vms->its = value; + } + ++static bool virt_get_ipiv(Object *obj, Error **errp) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(obj); ++ ++ return vms->ipiv; ++} ++ ++static void virt_set_ipiv(Object *obj, bool value, Error **errp) ++{ ++ VirtMachineState *vms = VIRT_MACHINE(obj); ++ ++ vms->ipiv = value; ++} ++ + static void virt_get_dtb_randomness(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +@@ -4086,6 +4100,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + "in ACPI table header." + "The string may be up to 8 bytes in size"); + ++ object_class_property_add_bool(oc, "ipiv", ++ virt_get_ipiv, ++ virt_set_ipiv); ++ object_class_property_set_description(oc, "ipiv", ++ "Set on/off to enable/disable IPIV"); + } + + static char *virt_get_kvm_type(Object *obj, Error **errp G_GNUC_UNUSED) +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index fee7c27e0c..a54b0057fb 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -225,6 +225,7 @@ struct VirtMachineState { + bool cpu_hotplug_enabled; + bool ras; + bool mte; ++ bool ipiv; + OnOffAuto dtb_randomness; + bool pmu; + int smmu_accel_count; +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index f45783a9da..7d443a967d 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -34,6 +34,7 @@ + #include "hw/irq.h" + #include "qapi/visitor.h" + #include "qemu/log.h" ++#include "hw/arm/virt.h" + + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +@@ -259,10 +260,15 @@ int kvm_arch_get_default_type(MachineState *ms) + return fixed_ipa ? 0 : size; + } + +-static void kvm_update_ipiv_cap(KVMState *s) ++static void kvm_update_ipiv_cap(MachineState *ms, KVMState *s) + { ++ VirtMachineState *vms = VIRT_MACHINE(ms); + int ret; + ++ if (!vms->ipiv) { ++ return; ++ } ++ + if (!kvm_check_extension(s, KVM_CAP_ARM_HISI_IPIV)) { + return; + } +@@ -349,7 +355,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + } + + kvm_arm_init_debug(s); +- kvm_update_ipiv_cap(s); ++ kvm_update_ipiv_cap(ms, s); + + ret = kvm_arm_rme_init(ms); + if (ret) { +-- +2.33.0 + diff --git a/hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch b/hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch new file mode 100644 index 00000000..7592c6e3 --- /dev/null +++ b/hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch @@ -0,0 +1,57 @@ +From 6bba3fc99e393c8bdec27ce671f124d18b5642ff Mon Sep 17 00:00:00 2001 +From: Kunkun Jiang +Date: Sun, 28 Sep 2025 15:43:12 +0800 +Subject: [PATCH] hw/vfio/migration: Fix vfio migration isn't aborted in a + corner case + +In the final stage of vfio migration, the destination VM will execute +vm_start + vfio_vmstate_change + vfio_migration_set_state +At this time, vfio_migration_set_state may return failure. For example, +the device is in the reset process due to some hardware problems. In +this case, the vfio migration should be aborted, but the current logic +does not abort. Instead, it continues to execute, which will cause +Unpredictable impact. This patch fixes this case. + +Signed-off-by: Kunkun Jiang +--- + hw/vfio/migration.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c +index b81cb7e23b..8c27298477 100644 +--- a/hw/vfio/migration.c ++++ b/hw/vfio/migration.c +@@ -720,7 +720,7 @@ static void vfio_vmstate_change_prepare(void *opaque, bool running, + static void vfio_vmstate_change(void *opaque, bool running, RunState state) + { + VFIODevice *vbasedev = opaque; +- enum vfio_device_mig_state new_state; ++ enum vfio_device_mig_state new_state, pre_state; + int ret; + + if (running) { +@@ -733,6 +733,8 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) + VFIO_DEVICE_STATE_STOP; + } + ++ pre_state = vbasedev->migration->device_state; ++ + /* + * If setting the device in new_state fails, the device should be reset. + * To do so, use ERROR state as a recover state. +@@ -747,6 +749,10 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state) + if (migrate_get_current()->to_dst_file) { + qemu_file_set_error(migrate_get_current()->to_dst_file, ret); + } ++ ++ if (pre_state == VFIO_DEVICE_STATE_RESUMING) { ++ exit(EXIT_FAILURE); ++ } + } + + trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index d97d3a54..d9355aad 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 46 +Release: 47 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1082,6 +1082,17 @@ Patch1065: ssh-Do-not-switch-session-to-non-blocking-mode.patch Patch1066: target-ppc-Fix-mtDPDES-targeting-SMT-siblings.patch Patch1067: target-ppc-Fix-non-maskable-interrupt-while-halted.patch Patch1068: elfload-Fix-alignment-when-unmapping-excess-reservat.patch +Patch1069: target-s390x-Fix-MVC-not-always-invalidating-transla.patch +Patch1070: target-sparc-Fix-gdbstub-incorrectly-handling-regist.patch +Patch1071: virtio-net-Fix-size-check-in-dhclient-workaround.patch +Patch1072: vdpa-Fix-endian-bugs-in-shadow-virtqueue.patch +Patch1073: x86-loader-only-patch-linux-kernels.patch +Patch1074: target-ppc-Fix-e200-duplicate-SPRs.patch +Patch1075: vfio-container-For-CSV3-VM-only-register-listener-to.patch +Patch1076: target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch +Patch1077: target-riscv-kvm-Fix-exposure-of-Zkr.patch +Patch1078: hw-arm-virt-Introduce-a-IPIV-machine-option.patch +Patch1079: hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch BuildRequires: flex BuildRequires: gcc @@ -1680,6 +1691,19 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Wed Oct 22 2025 Junqi Ma - 11:8.2.0-47 +- target/s390x: Fix MVC not always invalidating translation blocks +- target/sparc: Fix gdbstub incorrectly handling registers f32-f62 +- virtio-net: Fix size check in dhclient workaround +- vdpa: Fix endian bugs in shadow virtqueue +- x86/loader: only patch linux kernels +- target/ppc: Fix e200 duplicate SPRs +- vfio/container: For CSV3 VM, only register listener to shared_memory_listener list in vfio_connect_container() +- target/riscv/kvm: update the KVM regs to Linux rvck-6.6 +- target/riscv/kvm: Fix exposure of Zkr +- hw/arm/virt: Introduce a IPIV machine option +- hw/vfio/migration: Fix vfio migration isn't aborted in a corner case + * Mon Oct 20 2025 Pengrui Zhang - 11:8.2.0-46 - vdpa: Allow vDPA to work on big-endian machine - vfio/container: Replace basename with g_path_get_basename diff --git a/target-ppc-Fix-e200-duplicate-SPRs.patch b/target-ppc-Fix-e200-duplicate-SPRs.patch new file mode 100644 index 00000000..90264275 --- /dev/null +++ b/target-ppc-Fix-e200-duplicate-SPRs.patch @@ -0,0 +1,46 @@ +From 338823420b806247a98c1c6c2be3ac8a257a7eca Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 02:03:45 -0400 +Subject: [PATCH] target/ppc: Fix e200 duplicate SPRs + +cheery-pick from d63f951f4746f080fbdc11e577f1fba931be8cdc + +DSRR0/1 registers are in the BookE ISA not e200 specific, so +remove the duplicate e200 register definitions. + +Cc: Roman Kapl +Cc: qemu-stable@nongnu.org +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2768 +Fixes: 0e3bf4890906 ("ppc: add DBCR based debugging") +Signed-off-by: Nicholas Piggin +(cherry picked from commit 73c0c904fc99e2ceecbbded84ec76d40d3f2daae) +(Mjt: context fix for + v9.0.0-935-g581eea5d656b "target/ppc: Split off common embedded TLB init") +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + target/ppc/cpu_init.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c +index 40fe14a6c2..c01a8c9a90 100644 +--- a/target/ppc/cpu_init.c ++++ b/target/ppc/cpu_init.c +@@ -2713,14 +2713,6 @@ static void init_proc_e200(CPUPPCState *env) + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* TOFIX */ +- spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", +- SPR_NOACCESS, SPR_NOACCESS, +- &spr_read_generic, &spr_write_generic, +- 0x00000000); +- spr_register(env, SPR_BOOKE_DSRR1, "DSRR1", +- SPR_NOACCESS, SPR_NOACCESS, +- &spr_read_generic, &spr_write_generic, +- 0x00000000); + #if !defined(CONFIG_USER_ONLY) + env->nb_tlb = 64; + env->nb_ways = 1; +-- +2.33.0 + diff --git a/target-riscv-kvm-Fix-exposure-of-Zkr.patch b/target-riscv-kvm-Fix-exposure-of-Zkr.patch new file mode 100644 index 00000000..af31237d --- /dev/null +++ b/target-riscv-kvm-Fix-exposure-of-Zkr.patch @@ -0,0 +1,124 @@ +From 35a53e8e95ccd1d929f9091c08fc9f06f26ab3c1 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Thu, 4 Sep 2025 17:18:17 +0800 +Subject: [PATCH] target/riscv/kvm: Fix exposure of Zkr + +commit 86997772fa807f3961e5aeed97af7738adec1b43 upstream + +The Zkr extension may only be exposed to KVM guests if the VMM +implements the SEED CSR. Use the same implementation as TCG. + +Without this patch, running with a KVM which does not forward the +SEED CSR access to QEMU will result in an ILL exception being +injected into the guest (this results in Linux guests crashing on +boot). And, when running with a KVM which does forward the access, +QEMU will crash, since QEMU doesn't know what to do with the exit. + +Fixes: 3108e2f1c69d ("target/riscv/kvm: update KVM exts to Linux 6.8") +Signed-off-by: Andrew Jones +Reviewed-by: Daniel Henrique Barboza +Cc: qemu-stable +Message-ID: <20240422134605.534207-2-ajones@ventanamicro.com> +Signed-off-by: Alistair Francis +--- + target/riscv/cpu.h | 3 +++ + target/riscv/csr.c | 18 ++++++++++++++---- + target/riscv/kvm/kvm-cpu.c | 25 +++++++++++++++++++++++++ + 3 files changed, 42 insertions(+), 4 deletions(-) + +diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h +index e1c3485216..4b596a6964 100644 +--- a/target/riscv/cpu.h ++++ b/target/riscv/cpu.h +@@ -793,6 +793,9 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); + + void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); + ++target_ulong riscv_new_csr_seed(target_ulong new_value, ++ target_ulong write_mask); ++ + uint8_t satp_mode_max_from_map(uint32_t map); + const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); + +diff --git a/target/riscv/csr.c b/target/riscv/csr.c +index 3d9ea0c316..69921e04cf 100644 +--- a/target/riscv/csr.c ++++ b/target/riscv/csr.c +@@ -4199,10 +4199,8 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno, + #endif + + /* Crypto Extension */ +-static RISCVException rmw_seed(CPURISCVState *env, int csrno, +- target_ulong *ret_value, +- target_ulong new_value, +- target_ulong write_mask) ++target_ulong riscv_new_csr_seed(target_ulong new_value, ++ target_ulong write_mask) + { + uint16_t random_v; + Error *random_e = NULL; +@@ -4226,6 +4224,18 @@ static RISCVException rmw_seed(CPURISCVState *env, int csrno, + rval = random_v | SEED_OPST_ES16; + } + ++ return rval; ++} ++ ++static RISCVException rmw_seed(CPURISCVState *env, int csrno, ++ target_ulong *ret_value, ++ target_ulong new_value, ++ target_ulong write_mask) ++{ ++ target_ulong rval; ++ ++ rval = riscv_new_csr_seed(new_value, write_mask); ++ + if (ret_value) { + *ret_value = rval; + } +diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c +index ce26163d03..c38e8077a2 100644 +--- a/target/riscv/kvm/kvm-cpu.c ++++ b/target/riscv/kvm/kvm-cpu.c +@@ -1260,6 +1260,28 @@ static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) + return ret; + } + ++static int kvm_riscv_handle_csr(CPUState *cs, struct kvm_run *run) ++{ ++ target_ulong csr_num = run->riscv_csr.csr_num; ++ target_ulong new_value = run->riscv_csr.new_value; ++ target_ulong write_mask = run->riscv_csr.write_mask; ++ int ret = 0; ++ ++ switch (csr_num) { ++ case CSR_SEED: ++ run->riscv_csr.ret_value = riscv_new_csr_seed(new_value, write_mask); ++ break; ++ default: ++ qemu_log_mask(LOG_UNIMP, ++ "%s: un-handled CSR EXIT for CSR %lx\n", ++ __func__, csr_num); ++ ret = -1; ++ break; ++ } ++ ++ return ret; ++} ++ + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + { + int ret = 0; +@@ -1267,6 +1289,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + case KVM_EXIT_RISCV_SBI: + ret = kvm_riscv_handle_sbi(cs, run); + break; ++ case KVM_EXIT_RISCV_CSR: ++ ret = kvm_riscv_handle_csr(cs, run); ++ break; + default: + qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", + __func__, run->exit_reason); +-- +2.33.0 + diff --git a/target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch b/target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch new file mode 100644 index 00000000..fb8aa592 --- /dev/null +++ b/target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch @@ -0,0 +1,256 @@ +From bab10c628c7df3b79a6225c19cc0e0d1b795e79f Mon Sep 17 00:00:00 2001 +From: yechao-w +Date: Wed, 3 Sep 2025 14:14:03 +0800 +Subject: [PATCH] target/riscv/kvm: update the KVM regs to Linux rvck-6.6 + +Few new regs added: +ziccrse,zicond,zihintntl,zimop,zcmop,zabha,zacas,zawrs,zfa,zfh,zfhmin, +zbc,zbkb,zbkc,zbkx,zca,zcb,zcd,zcf,zknd,zkne,zknh,zkr,zksed,zksh,zkt, +ztso,zvbb,zvbc,zvfh,zvfhmin,zvkb,zvkg,zvkned,zvknha,zvknhb,zvksed,zvksh, +zvkt,smnpm,smstateen,ssnpm,svade,svadu,svvptc + +Signed-off-by: yechao-w +--- + linux-headers/asm-riscv/kvm.h | 44 ++++++++++++++++++++++++++++++++++ + target/riscv/cpu.c | 9 +++++++ + target/riscv/cpu.h | 3 ++- + target/riscv/cpu_cfg.h | 12 ++++++++++ + target/riscv/kvm/kvm-cpu.c | 45 +++++++++++++++++++++++++++++++++++ + 5 files changed, 112 insertions(+), 1 deletion(-) + +diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h +index 60d3b21dea..5655a69769 100644 +--- a/linux-headers/asm-riscv/kvm.h ++++ b/linux-headers/asm-riscv/kvm.h +@@ -139,6 +139,50 @@ enum KVM_RISCV_ISA_EXT_ID { + KVM_RISCV_ISA_EXT_ZIHPM, + KVM_RISCV_ISA_EXT_SMSTATEEN, + KVM_RISCV_ISA_EXT_ZICOND, ++ KVM_RISCV_ISA_EXT_ZBC, ++ KVM_RISCV_ISA_EXT_ZBKB, ++ KVM_RISCV_ISA_EXT_ZBKC, ++ KVM_RISCV_ISA_EXT_ZBKX, ++ KVM_RISCV_ISA_EXT_ZKND, ++ KVM_RISCV_ISA_EXT_ZKNE, ++ KVM_RISCV_ISA_EXT_ZKNH, ++ KVM_RISCV_ISA_EXT_ZKR, ++ KVM_RISCV_ISA_EXT_ZKSED, ++ KVM_RISCV_ISA_EXT_ZKSH, ++ KVM_RISCV_ISA_EXT_ZKT, ++ KVM_RISCV_ISA_EXT_ZVBB, ++ KVM_RISCV_ISA_EXT_ZVBC, ++ KVM_RISCV_ISA_EXT_ZVKB, ++ KVM_RISCV_ISA_EXT_ZVKG, ++ KVM_RISCV_ISA_EXT_ZVKNED, ++ KVM_RISCV_ISA_EXT_ZVKNHA, ++ KVM_RISCV_ISA_EXT_ZVKNHB, ++ KVM_RISCV_ISA_EXT_ZVKSED, ++ KVM_RISCV_ISA_EXT_ZVKSH, ++ KVM_RISCV_ISA_EXT_ZVKT, ++ KVM_RISCV_ISA_EXT_ZFH, ++ KVM_RISCV_ISA_EXT_ZFHMIN, ++ KVM_RISCV_ISA_EXT_ZIHINTNTL, ++ KVM_RISCV_ISA_EXT_ZVFH, ++ KVM_RISCV_ISA_EXT_ZVFHMIN, ++ KVM_RISCV_ISA_EXT_ZFA, ++ KVM_RISCV_ISA_EXT_ZTSO, ++ KVM_RISCV_ISA_EXT_ZACAS, ++ KVM_RISCV_ISA_EXT_SSCOFPMF, ++ KVM_RISCV_ISA_EXT_ZIMOP, ++ KVM_RISCV_ISA_EXT_ZCA, ++ KVM_RISCV_ISA_EXT_ZCB, ++ KVM_RISCV_ISA_EXT_ZCD, ++ KVM_RISCV_ISA_EXT_ZCF, ++ KVM_RISCV_ISA_EXT_ZCMOP, ++ KVM_RISCV_ISA_EXT_ZAWRS, ++ KVM_RISCV_ISA_EXT_SMNPM, ++ KVM_RISCV_ISA_EXT_SSNPM, ++ KVM_RISCV_ISA_EXT_SVADE, ++ KVM_RISCV_ISA_EXT_SVADU, ++ KVM_RISCV_ISA_EXT_SVVPTC, ++ KVM_RISCV_ISA_EXT_ZABHA, ++ KVM_RISCV_ISA_EXT_ZICCRSE, + KVM_RISCV_ISA_EXT_MAX, + }; + +diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c +index 77cb59b8a1..7d921d8e9b 100644 +--- a/target/riscv/cpu.c ++++ b/target/riscv/cpu.c +@@ -79,6 +79,7 @@ const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, + const RISCVIsaExtData isa_edata_arr[] = { + ISA_EXT_DATA_ENTRY(zicbom, PRIV_VERSION_1_12_0, ext_zicbom), + ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_zicboz), ++ ISA_EXT_DATA_ENTRY(ziccrse, PRIV_VERSION_1_11_0, ext_ziccrse), + ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond), + ISA_EXT_DATA_ENTRY(zicntr, PRIV_VERSION_1_12_0, ext_zicntr), + ISA_EXT_DATA_ENTRY(zicsr, PRIV_VERSION_1_10_0, ext_zicsr), +@@ -86,7 +87,10 @@ const RISCVIsaExtData isa_edata_arr[] = { + ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl), + ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause), + ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm), ++ ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop), + ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ++ ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha), ++ ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), + ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), + ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa), + ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin), +@@ -118,6 +122,7 @@ const RISCVIsaExtData isa_edata_arr[] = { + ISA_EXT_DATA_ENTRY(zksed, PRIV_VERSION_1_12_0, ext_zksed), + ISA_EXT_DATA_ENTRY(zksh, PRIV_VERSION_1_12_0, ext_zksh), + ISA_EXT_DATA_ENTRY(zkt, PRIV_VERSION_1_12_0, ext_zkt), ++ ISA_EXT_DATA_ENTRY(ztso, PRIV_VERSION_1_12_0, ext_ztso), + ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb), + ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc), + ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f), +@@ -145,14 +150,18 @@ const RISCVIsaExtData isa_edata_arr[] = { + ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin), + ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia), + ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp), ++ ISA_EXT_DATA_ENTRY(smmpm, PRIV_VERSION_1_13_0, ext_smmpm), ++ ISA_EXT_DATA_ENTRY(smnpm, PRIV_VERSION_1_13_0, ext_smnpm), + ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen), + ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia), + ISA_EXT_DATA_ENTRY(sscofpmf, PRIV_VERSION_1_12_0, ext_sscofpmf), + ISA_EXT_DATA_ENTRY(sstc, PRIV_VERSION_1_12_0, ext_sstc), ++ ISA_EXT_DATA_ENTRY(svade, PRIV_VERSION_1_11_0, ext_svade), + ISA_EXT_DATA_ENTRY(svadu, PRIV_VERSION_1_12_0, ext_svadu), + ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval), + ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot), + ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt), ++ ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc), + ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba), + ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb), + ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs), +diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h +index d74b361be6..e1c3485216 100644 +--- a/target/riscv/cpu.h ++++ b/target/riscv/cpu.h +@@ -81,8 +81,9 @@ enum { + PRIV_VERSION_1_10_0 = 0, + PRIV_VERSION_1_11_0, + PRIV_VERSION_1_12_0, ++ PRIV_VERSION_1_13_0, + +- PRIV_VERSION_LATEST = PRIV_VERSION_1_12_0, ++ PRIV_VERSION_LATEST = PRIV_VERSION_1_13_0, + }; + + #define VEXT_VERSION_1_00_0 0x00010000 +diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h +index f4605fb190..07b7e54877 100644 +--- a/target/riscv/cpu_cfg.h ++++ b/target/riscv/cpu_cfg.h +@@ -70,13 +70,19 @@ struct RISCVCPUConfig { + bool ext_zihintntl; + bool ext_zihintpause; + bool ext_zihpm; ++ bool ext_zimop; ++ bool ext_zcmop; ++ bool ext_ztso; + bool ext_smstateen; + bool ext_sstc; + bool ext_svadu; + bool ext_svinval; + bool ext_svnapot; + bool ext_svpbmt; ++ bool ext_svvptc; + bool ext_zdinx; ++ bool ext_zacas; ++ bool ext_zabha; + bool ext_zawrs; + bool ext_zfa; + bool ext_zfbfmin; +@@ -113,6 +119,9 @@ struct RISCVCPUConfig { + bool ext_ssaia; + bool ext_sscofpmf; + bool ext_smepmp; ++ bool ext_ssnpm; ++ bool ext_smnpm; ++ bool ext_smmpm; + bool rvv_ta_all_1s; + bool rvv_ma_all_1s; + +@@ -120,6 +129,9 @@ struct RISCVCPUConfig { + uint64_t marchid; + uint64_t mimpid; + ++ bool ext_svade; ++ bool ext_ziccrse; ++ + /* Vendor-specific custom extensions */ + bool ext_xtheadba; + bool ext_xtheadbb; +diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c +index 9615e68ce4..ce26163d03 100644 +--- a/target/riscv/kvm/kvm-cpu.c ++++ b/target/riscv/kvm/kvm-cpu.c +@@ -228,19 +228,64 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) + static KVMCPUConfig kvm_multi_ext_cfgs[] = { + KVM_EXT_CFG("zicbom", ext_zicbom, KVM_RISCV_ISA_EXT_ZICBOM), + KVM_EXT_CFG("zicboz", ext_zicboz, KVM_RISCV_ISA_EXT_ZICBOZ), ++ KVM_EXT_CFG("ziccrse", ext_ziccrse, KVM_RISCV_ISA_EXT_ZICCRSE), + KVM_EXT_CFG("zicntr", ext_zicntr, KVM_RISCV_ISA_EXT_ZICNTR), ++ KVM_EXT_CFG("zicond", ext_zicond, KVM_RISCV_ISA_EXT_ZICOND), + KVM_EXT_CFG("zicsr", ext_zicsr, KVM_RISCV_ISA_EXT_ZICSR), + KVM_EXT_CFG("zifencei", ext_zifencei, KVM_RISCV_ISA_EXT_ZIFENCEI), ++ KVM_EXT_CFG("zihintntl", ext_zihintntl, KVM_RISCV_ISA_EXT_ZIHINTNTL), + KVM_EXT_CFG("zihintpause", ext_zihintpause, KVM_RISCV_ISA_EXT_ZIHINTPAUSE), + KVM_EXT_CFG("zihpm", ext_zihpm, KVM_RISCV_ISA_EXT_ZIHPM), ++ KVM_EXT_CFG("zimop", ext_zimop, KVM_RISCV_ISA_EXT_ZIMOP), ++ KVM_EXT_CFG("zcmop", ext_zcmop, KVM_RISCV_ISA_EXT_ZCMOP), ++ KVM_EXT_CFG("zabha", ext_zabha, KVM_RISCV_ISA_EXT_ZABHA), ++ KVM_EXT_CFG("zacas", ext_zacas, KVM_RISCV_ISA_EXT_ZACAS), ++ KVM_EXT_CFG("zawrs", ext_zawrs, KVM_RISCV_ISA_EXT_ZAWRS), ++ KVM_EXT_CFG("zfa", ext_zfa, KVM_RISCV_ISA_EXT_ZFA), ++ KVM_EXT_CFG("zfh", ext_zfh, KVM_RISCV_ISA_EXT_ZFH), ++ KVM_EXT_CFG("zfhmin", ext_zfhmin, KVM_RISCV_ISA_EXT_ZFHMIN), + KVM_EXT_CFG("zba", ext_zba, KVM_RISCV_ISA_EXT_ZBA), + KVM_EXT_CFG("zbb", ext_zbb, KVM_RISCV_ISA_EXT_ZBB), ++ KVM_EXT_CFG("zbc", ext_zbc, KVM_RISCV_ISA_EXT_ZBC), ++ KVM_EXT_CFG("zbkb", ext_zbkb, KVM_RISCV_ISA_EXT_ZBKB), ++ KVM_EXT_CFG("zbkc", ext_zbkc, KVM_RISCV_ISA_EXT_ZBKC), ++ KVM_EXT_CFG("zbkx", ext_zbkx, KVM_RISCV_ISA_EXT_ZBKX), + KVM_EXT_CFG("zbs", ext_zbs, KVM_RISCV_ISA_EXT_ZBS), ++ KVM_EXT_CFG("zca", ext_zca, KVM_RISCV_ISA_EXT_ZCA), ++ KVM_EXT_CFG("zcb", ext_zcb, KVM_RISCV_ISA_EXT_ZCB), ++ KVM_EXT_CFG("zcd", ext_zcd, KVM_RISCV_ISA_EXT_ZCD), ++ KVM_EXT_CFG("zcf", ext_zcf, KVM_RISCV_ISA_EXT_ZCF), ++ KVM_EXT_CFG("zknd", ext_zknd, KVM_RISCV_ISA_EXT_ZKND), ++ KVM_EXT_CFG("zkne", ext_zkne, KVM_RISCV_ISA_EXT_ZKNE), ++ KVM_EXT_CFG("zknh", ext_zknh, KVM_RISCV_ISA_EXT_ZKNH), ++ KVM_EXT_CFG("zkr", ext_zkr, KVM_RISCV_ISA_EXT_ZKR), ++ KVM_EXT_CFG("zksed", ext_zksed, KVM_RISCV_ISA_EXT_ZKSED), ++ KVM_EXT_CFG("zksh", ext_zksh, KVM_RISCV_ISA_EXT_ZKSH), ++ KVM_EXT_CFG("zkt", ext_zkt, KVM_RISCV_ISA_EXT_ZKT), ++ KVM_EXT_CFG("ztso", ext_ztso, KVM_RISCV_ISA_EXT_ZTSO), ++ KVM_EXT_CFG("zvbb", ext_zvbb, KVM_RISCV_ISA_EXT_ZVBB), ++ KVM_EXT_CFG("zvbc", ext_zvbc, KVM_RISCV_ISA_EXT_ZVBC), ++ KVM_EXT_CFG("zvfh", ext_zvfh, KVM_RISCV_ISA_EXT_ZVFH), ++ KVM_EXT_CFG("zvfhmin", ext_zvfhmin, KVM_RISCV_ISA_EXT_ZVFHMIN), ++ KVM_EXT_CFG("zvkb", ext_zvkb, KVM_RISCV_ISA_EXT_ZVKB), ++ KVM_EXT_CFG("zvkg", ext_zvkg, KVM_RISCV_ISA_EXT_ZVKG), ++ KVM_EXT_CFG("zvkned", ext_zvkned, KVM_RISCV_ISA_EXT_ZVKNED), ++ KVM_EXT_CFG("zvknha", ext_zvknha, KVM_RISCV_ISA_EXT_ZVKNHA), ++ KVM_EXT_CFG("zvknhb", ext_zvknhb, KVM_RISCV_ISA_EXT_ZVKNHB), ++ KVM_EXT_CFG("zvksed", ext_zvksed, KVM_RISCV_ISA_EXT_ZVKSED), ++ KVM_EXT_CFG("zvksh", ext_zvksh, KVM_RISCV_ISA_EXT_ZVKSH), ++ KVM_EXT_CFG("zvkt", ext_zvkt, KVM_RISCV_ISA_EXT_ZVKT), ++ KVM_EXT_CFG("smnpm", ext_smnpm, KVM_RISCV_ISA_EXT_SMNPM), ++ KVM_EXT_CFG("smstateen", ext_smstateen, KVM_RISCV_ISA_EXT_SMSTATEEN), + KVM_EXT_CFG("ssaia", ext_ssaia, KVM_RISCV_ISA_EXT_SSAIA), ++ KVM_EXT_CFG("ssnpm", ext_ssnpm, KVM_RISCV_ISA_EXT_SSNPM), + KVM_EXT_CFG("sstc", ext_sstc, KVM_RISCV_ISA_EXT_SSTC), ++ KVM_EXT_CFG("svade", ext_svade, KVM_RISCV_ISA_EXT_SVADE), ++ KVM_EXT_CFG("svadu", ext_svadu, KVM_RISCV_ISA_EXT_SVADU), + KVM_EXT_CFG("svinval", ext_svinval, KVM_RISCV_ISA_EXT_SVINVAL), + KVM_EXT_CFG("svnapot", ext_svnapot, KVM_RISCV_ISA_EXT_SVNAPOT), + KVM_EXT_CFG("svpbmt", ext_svpbmt, KVM_RISCV_ISA_EXT_SVPBMT), ++ KVM_EXT_CFG("svvptc", ext_svvptc, KVM_RISCV_ISA_EXT_SVVPTC), + }; + + static void *kvmconfig_get_cfg_addr(RISCVCPU *cpu, KVMCPUConfig *kvmcfg) +-- +2.33.0 + diff --git a/target-s390x-Fix-MVC-not-always-invalidating-transla.patch b/target-s390x-Fix-MVC-not-always-invalidating-transla.patch new file mode 100644 index 00000000..64628dc1 --- /dev/null +++ b/target-s390x-Fix-MVC-not-always-invalidating-transla.patch @@ -0,0 +1,65 @@ +From f1d3e679818594b4cab0601d426f8d02a6d35bdb Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 02:39:09 -0400 +Subject: [PATCH] target/s390x: Fix MVC not always invalidating translation + blocks + +cheery-pick from cbdb457d7981133e511eafa3296431871d84bea4 + +Node.js crashes in qemu-system-s390x with random SIGSEGVs / SIGILLs. + +The v8 JIT used by Node.js can garbage collect and overwrite unused +code. Overwriting is performed by WritableJitAllocation::CopyCode(), +code. Overwriting is performed by WritableJitAllocation::CopyCode(), +which ultimately calls memcpy(). For certain sizes, memcpy() uses the +MVC instruction. + +QEMU implements MVC and other similar instructions using helpers. While +TCG store ops invalidate affected translation blocks automatically, +helpers must do this manually by calling probe_access_flags(). The MVC +helper does this using the access_prepare() -> access_prepare_nf() -> +s390_probe_access() -> probe_access_flags() call chain. + +At the last step of this chain, the store size is replaced with 0. This +causes the probe_access_flags() -> notdirty_write() -> +tb_invalidate_phys_range_fast() chain to miss some translation blocks. + +When this happens, QEMU executes a mix of old and new code. This +quickly leads to either a SIGSEGV or a SIGILL in case the old code +ends in the middle of a new instruction. + +Fix by passing the true size. + +Reported-by: Berthold Gunreben +Cc: Sarah Kriesch +Cc: qemu-stable@nongnu.org +Closes: https://bugzilla.opensuse.org/show_bug.cgi?id=1235709 +Signed-off-by: Ilya Leoshkevich +Reviewed-by: Richard Henderson +Reviewed-by: David Hildenbrand +Fixes: e2faabee78ff ("accel/tcg: Forward probe size on to notdirty_write") +Message-ID: <20250128001338.11474-1-iii@linux.ibm.com> +Signed-off-by: Thomas Huth +(cherry picked from commit e43ced8be18dda77c229ab09f85136a4d600d40d) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + target/s390x/tcg/mem_helper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c +index 84103251b9..1da47c78e8 100644 +--- a/target/s390x/tcg/mem_helper.c ++++ b/target/s390x/tcg/mem_helper.c +@@ -146,7 +146,7 @@ static inline int s390_probe_access(CPUArchState *env, target_ulong addr, + int mmu_idx, bool nonfault, + void **phost, uintptr_t ra) + { +- int flags = probe_access_flags(env, addr, 0, access_type, mmu_idx, ++ int flags = probe_access_flags(env, addr, size, access_type, mmu_idx, + nonfault, phost, ra); + + if (unlikely(flags & TLB_INVALID_MASK)) { +-- +2.33.0 + diff --git a/target-sparc-Fix-gdbstub-incorrectly-handling-regist.patch b/target-sparc-Fix-gdbstub-incorrectly-handling-regist.patch new file mode 100644 index 00000000..437e2a27 --- /dev/null +++ b/target-sparc-Fix-gdbstub-incorrectly-handling-regist.patch @@ -0,0 +1,69 @@ +From cb97a92ee393673ff2c927740b98db1ed38d0924 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 03:03:33 -0400 +Subject: [PATCH] target/sparc: Fix gdbstub incorrectly handling registers + f32-f62 + +cheery-pick from 5af648acff28171d34a68aec4cf0f52e6401284c + +The gdbstub implementation for the Sparc architecture would +incorrectly calculate the the floating point register offset. +This resulted in, for example, registers f32 and f34 to point to +the same value. + +The issue was caused by the confusion between even register numbers +and even register indexes. For example, the register index of f32 is 64 +and f34 is 65. + +Cc: qemu-stable@nongnu.org +Fixes: 30038fd81808 ("target-sparc: Change fpr representation to doubles.") +Signed-off-by: Mikael Szreder +Reviewed-by: Richard Henderson +Signed-off-by: Richard Henderson +Message-ID: <20250214070343.11501-1-git@miszr.win> +(cherry picked from commit 7a74e468089a58756b438d31a2a9a97f183780d7) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + target/sparc/gdbstub.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/target/sparc/gdbstub.c b/target/sparc/gdbstub.c +index a1c8fdc4d5..109b7237e0 100644 +--- a/target/sparc/gdbstub.c ++++ b/target/sparc/gdbstub.c +@@ -80,8 +80,13 @@ int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) + } + } + if (n < 80) { +- /* f32-f62 (double width, even numbers only) */ +- return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll); ++ /* f32-f62 (16 double width registers, even register numbers only) ++ * n == 64: f32 : env->fpr[16] ++ * n == 65: f34 : env->fpr[17] ++ * etc... ++ * n == 79: f62 : env->fpr[31] ++ */ ++ return gdb_get_reg64(mem_buf, env->fpr[(n - 64) + 16].ll); + } + switch (n) { + case 80: +@@ -174,8 +179,13 @@ int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) + } + return 4; + } else if (n < 80) { +- /* f32-f62 (double width, even numbers only) */ +- env->fpr[(n - 32) / 2].ll = tmp; ++ /* f32-f62 (16 double width registers, even register numbers only) ++ * n == 64: f32 : env->fpr[16] ++ * n == 65: f34 : env->fpr[17] ++ * etc... ++ * n == 79: f62 : env->fpr[31] ++ */ ++ env->fpr[(n - 64) + 16].ll = tmp; + } else { + switch (n) { + case 80: +-- +2.33.0 + diff --git a/vdpa-Fix-endian-bugs-in-shadow-virtqueue.patch b/vdpa-Fix-endian-bugs-in-shadow-virtqueue.patch new file mode 100644 index 00000000..72dc0f45 --- /dev/null +++ b/vdpa-Fix-endian-bugs-in-shadow-virtqueue.patch @@ -0,0 +1,98 @@ +From 99186ad14ebc29c79d17ff0afc46c087a9f44923 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 03:48:19 -0400 +Subject: [PATCH] vdpa: Fix endian bugs in shadow virtqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cheery-pick from ca12e95f1329b74c5fdaf0d92f38110129831090 + +VDPA didn't work on a big-endian machine due to missing/incorrect +CPU<->LE data format conversions. + +Signed-off-by: Konstantin Shkolnyy +Message-Id: <20250212164923.1971538-1-kshk@linux.ibm.com> +Fixes: 10857ec0ad ("vhost: Add VhostShadowVirtqueue") +Acked-by: Eugenio Pérez +Tested-by: Lei Yang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 50e9754149066dc91f58405d3378b589098cb408) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/virtio/vhost-shadow-virtqueue.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c +index fc5f408f77..ca60167b08 100644 +--- a/hw/virtio/vhost-shadow-virtqueue.c ++++ b/hw/virtio/vhost-shadow-virtqueue.c +@@ -165,10 +165,10 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg, + descs[i].len = cpu_to_le32(iovec[n].iov_len); + + last = i; +- i = cpu_to_le16(svq->desc_next[i]); ++ i = svq->desc_next[i]; + } + +- svq->free_head = le16_to_cpu(svq->desc_next[last]); ++ svq->free_head = svq->desc_next[last]; + return true; + } + +@@ -228,10 +228,12 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq) + smp_mb(); + + if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) { +- uint16_t avail_event = *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]); ++ uint16_t avail_event = le16_to_cpu( ++ *(uint16_t *)(&svq->vring.used->ring[svq->vring.num])); + needs_kick = vring_need_event(avail_event, svq->shadow_avail_idx, svq->shadow_avail_idx - 1); + } else { +- needs_kick = !(svq->vring.used->flags & VRING_USED_F_NO_NOTIFY); ++ needs_kick = ++ !(svq->vring.used->flags & cpu_to_le16(VRING_USED_F_NO_NOTIFY)); + } + + if (!needs_kick) { +@@ -365,7 +367,7 @@ static bool vhost_svq_more_used(VhostShadowVirtqueue *svq) + return true; + } + +- svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx); ++ svq->shadow_used_idx = le16_to_cpu(*(volatile uint16_t *)used_idx); + + return svq->last_used_idx != svq->shadow_used_idx; + } +@@ -383,7 +385,7 @@ static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq) + { + if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) { + uint16_t *used_event = (uint16_t *)&svq->vring.avail->ring[svq->vring.num]; +- *used_event = svq->shadow_used_idx; ++ *used_event = cpu_to_le16(svq->shadow_used_idx); + } else { + svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT); + } +@@ -408,7 +410,7 @@ static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq, + uint16_t num, uint16_t i) + { + for (uint16_t j = 0; j < (num - 1); ++j) { +- i = le16_to_cpu(svq->desc_next[i]); ++ i = svq->desc_next[i]; + } + + return i; +@@ -681,7 +683,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, + svq->desc_state = g_new0(SVQDescState, svq->vring.num); + svq->desc_next = g_new0(uint16_t, svq->vring.num); + for (unsigned i = 0; i < svq->vring.num - 1; i++) { +- svq->desc_next[i] = cpu_to_le16(i + 1); ++ svq->desc_next[i] = i + 1; + } + } + +-- +2.33.0 + diff --git a/vfio-container-For-CSV3-VM-only-register-listener-to.patch b/vfio-container-For-CSV3-VM-only-register-listener-to.patch new file mode 100644 index 00000000..67c69606 --- /dev/null +++ b/vfio-container-For-CSV3-VM-only-register-listener-to.patch @@ -0,0 +1,42 @@ +From 17038e49ea5b89bf3088d7e7f7186ca5aba4975f Mon Sep 17 00:00:00 2001 +From: hanliyang +Date: Thu, 21 Aug 2025 16:35:45 +0800 +Subject: [PATCH] vfio/container: For CSV3 VM, only register listener to + shared_memory_listener list in vfio_connect_container() + +There is a regression for booting CSV3 VM with passthr devices when +backporting the commit c7b313d300 ("vfio/container: Move listener to +base container"). + +Fix it here. + +Signed-off-by: hanliyang +--- + hw/vfio/container.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/vfio/container.c b/hw/vfio/container.c +index 95b8cff33b..56c55d00f1 100644 +--- a/hw/vfio/container.c ++++ b/hw/vfio/container.c +@@ -736,14 +736,14 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, + group->container = container; + QLIST_INSERT_HEAD(&container->group_list, group, container_next); + ++ bcontainer->listener = vfio_memory_listener; + if (kvm_csv3_enabled()) { + shared_memory_listener_register(&bcontainer->listener, + bcontainer->space->as); ++ } else { ++ memory_listener_register(&bcontainer->listener, bcontainer->space->as); + } + +- bcontainer->listener = vfio_memory_listener; +- memory_listener_register(&bcontainer->listener, bcontainer->space->as); +- + if (bcontainer->error) { + ret = -1; + error_propagate_prepend(errp, bcontainer->error, +-- +2.33.0 + diff --git a/virtio-net-Fix-size-check-in-dhclient-workaround.patch b/virtio-net-Fix-size-check-in-dhclient-workaround.patch new file mode 100644 index 00000000..6314115c --- /dev/null +++ b/virtio-net-Fix-size-check-in-dhclient-workaround.patch @@ -0,0 +1,43 @@ +From 441df39082f9eba5ab5fa56e33dda522060f87be Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 03:57:30 -0400 +Subject: [PATCH] virtio-net: Fix size check in dhclient workaround + +cheery-pick from aac6bdec4cb37ac1f0c12d769589ab14c8a5bbad + +work_around_broken_dhclient() accesses IP and UDP headers to detect +relevant packets and to calculate checksums, but it didn't check if +the packet has size sufficient to accommodate them, causing out-of-bound +access hazards. Fix this by correcting the size requirement. + +Fixes: 1d41b0c1ec66 ("Work around dhclient brokenness") +Cc: qemu-stable@nongnu.org +Signed-off-by: Akihiko Odaki +Signed-off-by: Jason Wang +(cherry picked from commit a8575f7fb2f213e6690b23160b04271d47fdfaa8) +Signed-off-by: Michael Tokarev +Signed-off-by: qihao_yewu +--- + hw/net/virtio-net.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 7184c9c526..5d58aa8a8c 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1712,8 +1712,11 @@ static void virtio_net_hdr_swap(VirtIODevice *vdev, struct virtio_net_hdr *hdr) + static void work_around_broken_dhclient(struct virtio_net_hdr *hdr, + uint8_t *buf, size_t size) + { ++ size_t csum_size = ETH_HLEN + sizeof(struct ip_header) + ++ sizeof(struct udp_header); ++ + if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */ +- (size > 27 && size < 1500) && /* normal sized MTU */ ++ (size >= csum_size && size < 1500) && /* normal sized MTU */ + (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */ + (buf[23] == 17) && /* ip.protocol == UDP */ + (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */ +-- +2.33.0 + diff --git a/x86-loader-only-patch-linux-kernels.patch b/x86-loader-only-patch-linux-kernels.patch new file mode 100644 index 00000000..23d87d16 --- /dev/null +++ b/x86-loader-only-patch-linux-kernels.patch @@ -0,0 +1,46 @@ +From 08d849e4c516ab826dfdb71d3e57dddf668b6898 Mon Sep 17 00:00:00 2001 +From: qihao_yewu +Date: Fri, 1 Aug 2025 04:02:45 -0400 +Subject: [PATCH] x86/loader: only patch linux kernels + +cheery-pick from 3f73fe11188307773ab6bce481a977c7a11e367e + +If the binary loaded via -kernel is *not* a linux kernel (in which +case protocol == 0), do not patch the linux kernel header fields. + +It's (a) pointless and (b) might break binaries by random patching +and (c) changes the binary hash which in turn breaks secure boot +verification. + +Background: OVMF happily loads and runs not only linux kernels but +any efi binary via direct kernel boot. + +Note: Breaking the secure boot verification is a problem for linux +kernels too, but fixed that is left for another day ... + +Signed-off-by: Gerd Hoffmann +Message-ID: <20240905141211.1253307-3-kraxel@redhat.com> +(cherry picked from commit 57e2cc9abf5da38f600354fe920ff20e719607b4) +Signed-off-by: Michael Tokarev +(Mjt: it is in hw/i386/x86.c not hw/i386/x86-common.c in 8.2.x) +Signed-off-by: qihao_yewu +--- + hw/i386/x86.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index 2b6291ad8d..672de72762 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -1105,7 +1105,7 @@ void x86_load_linux(X86MachineState *x86ms, + * kernel on the other side of the fw_cfg interface matches the hash of the + * file the user passed in. + */ +- if (!sev_enabled()) { ++ if (!sev_enabled() && protocol > 0) { + memcpy(setup, header, MIN(sizeof(header), setup_size)); + } + +-- +2.33.0 + -- Gitee From 4312bf275292d3c7de55589bcb4848da3180a054 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Fri, 24 Oct 2025 09:04:55 +0800 Subject: [PATCH 12/14] QEMU update to version 8.2.0-48 Signed-off-by: zhangpengrui Signed-off-by: zhangpengrui --- ...-riscv-use-tail-pseudoinstruction-fo.patch | 47 ++++++++++++ ...3_cpuif-Don-t-downgrade-monitor-trap.patch | 73 +++++++++++++++++++ ...don-t-assert-for-SETUP-to-non-0-endp.patch | 73 +++++++++++++++++++ hw-usb-hcd-xhci-Unmap-canceled-packet.patch | 64 ++++++++++++++++ ...CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch | 54 ++++++++++++++ ...se-has_header_symbol-to-check-getcpu.patch | 50 +++++++++++++ ...EK_CUR-offset-calculation-in-qio_cha.patch | 41 +++++++++++ qemu.spec | 20 ++++- ...lly-not-initialized-nr_volumes-in-qg.patch | 61 ++++++++++++++++ 9 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 common-user-host-riscv-use-tail-pseudoinstruction-fo.patch create mode 100644 hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch create mode 100644 hw-usb-hcd-uhci-don-t-assert-for-SETUP-to-non-0-endp.patch create mode 100644 hw-usb-hcd-xhci-Unmap-canceled-packet.patch create mode 100644 meson-Remove-CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch create mode 100644 meson-Use-has_header_symbol-to-check-getcpu.patch create mode 100644 migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch create mode 100644 qga-fix-potentially-not-initialized-nr_volumes-in-qg.patch diff --git a/common-user-host-riscv-use-tail-pseudoinstruction-fo.patch b/common-user-host-riscv-use-tail-pseudoinstruction-fo.patch new file mode 100644 index 00000000..4930e8a5 --- /dev/null +++ b/common-user-host-riscv-use-tail-pseudoinstruction-fo.patch @@ -0,0 +1,47 @@ +From 163c04af60750ebf617ac1152fccbf72fea3f873 Mon Sep 17 00:00:00 2001 +From: Icenowy Zheng +Date: Thu, 17 Apr 2025 15:22:06 +0800 +Subject: [PATCH] common-user/host/riscv: use tail pseudoinstruction for + calling tail + +The j pseudoinstruction maps to a JAL instruction, which can only handle +a jump to somewhere with a signed 20-bit destination. In case of static +linking and LTO'ing this easily leads to "relocation truncated to fit" +error. + +Switch to use tail pseudoinstruction, which is the standard way to +tail-call a function in medium code model (emits AUIPC+JALR). + +--- +Upstream commit 22b448ccc6611a59d4aa54419f4d88c1f343cb35 , v10.1.0 + +Signed-off-by: Icenowy Zheng +Reviewed-by: Richard Henderson +Message-ID: <20250417072206.364008-1-uwu@icenowy.me> +Signed-off-by: Alistair Francis +Cc: qemu-stable@nongnu.org +--- + common-user/host/riscv/safe-syscall.inc.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/common-user/host/riscv/safe-syscall.inc.S b/common-user/host/riscv/safe-syscall.inc.S +index dfe83c300e..c8b81e33d0 100644 +--- a/common-user/host/riscv/safe-syscall.inc.S ++++ b/common-user/host/riscv/safe-syscall.inc.S +@@ -69,11 +69,11 @@ safe_syscall_end: + + /* code path setting errno */ + 0: neg a0, a0 +- j safe_syscall_set_errno_tail ++ tail safe_syscall_set_errno_tail + + /* code path when we didn't execute the syscall */ + 2: li a0, QEMU_ERESTARTSYS +- j safe_syscall_set_errno_tail ++ tail safe_syscall_set_errno_tail + + .cfi_endproc + .size safe_syscall_base, .-safe_syscall_base +-- +2.33.0 + diff --git a/hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch b/hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch new file mode 100644 index 00000000..45fca24b --- /dev/null +++ b/hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch @@ -0,0 +1,73 @@ +From e03c56464bedc8dc78b2afa43b975cdb7a5897d9 Mon Sep 17 00:00:00 2001 +From: lijunwei +Date: Tue, 14 Oct 2025 15:04:01 +0800 +Subject: [PATCH] hw/intc/arm_gicv3_cpuif: Don't downgrade monitor traps + for AArch32 EL3 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + In the gicv3_{irq,fiq,irqfiq}_access() functions, there is a check + which downgrades a CP_ACCESS_TRAP_EL3 to CP_ACCESS_TRAP if EL3 is not + AArch64. This has been there since the GIC was first implemented, + but it isn't right: if we are trapping because of SCR.IRQ or SCR.FIQ + then we definitely want to be going to EL3 (doing + AArch32.TakeMonitorTrapException() in pseudocode terms). We might + want to not take a trap at all, but we don't ever want to go to the + default target EL, because that would mean, for instance, taking a + trap to Hyp mode if the trapped access was made from Hyp mode. + + (This might have been an attempt to work around our failure to + properly implement Monitor Traps.) + + Remove the bogus check. + + Cc: qemu-stable@nongnu.org + Fixes: 359fbe65 ("hw/intc/arm_gicv3: Implement GICv3 CPU interface registers") + Signed-off-by: default avatarPeter Maydell + Reviewed-by: default avatarAlex Bennée + Reviewed-by: default avatarRichard Henderson + Message-id: 20250130182309.717346-7-peter.maydell@linaro.org + (cherry picked from commit d04c6c3c) + Signed-off-by: default avatarMichael Tokarev +--- + hw/intc/arm_gicv3_cpuif.c | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c +index a013510074..27458d2b8a 100644 +--- a/hw/intc/arm_gicv3_cpuif.c ++++ b/hw/intc/arm_gicv3_cpuif.c +@@ -2098,9 +2098,6 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env, + } + } + +- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { +- r = CP_ACCESS_TRAP; +- } + return r; + } + +@@ -2163,9 +2160,6 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env, + } + } + +- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { +- r = CP_ACCESS_TRAP; +- } + return r; + } + +@@ -2202,9 +2196,6 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env, + } + } + +- if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { +- r = CP_ACCESS_TRAP; +- } + return r; + } + +-- +2.33.0 + diff --git a/hw-usb-hcd-uhci-don-t-assert-for-SETUP-to-non-0-endp.patch b/hw-usb-hcd-uhci-don-t-assert-for-SETUP-to-non-0-endp.patch new file mode 100644 index 00000000..36137592 --- /dev/null +++ b/hw-usb-hcd-uhci-don-t-assert-for-SETUP-to-non-0-endp.patch @@ -0,0 +1,73 @@ +From a7002fbaa0a8a88d5e57bf9cd981dcf70fb0cf5a Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Mon, 15 Sep 2025 14:29:10 +0100 +Subject: [PATCH] hw/usb/hcd-uhci: don't assert for SETUP to non-0 + endpoint(CVE-2024-8354) + +If the guest feeds invalid data to the UHCI controller, we +can assert: +qemu-system-x86_64: ../../hw/usb/core.c:744: usb_ep_get: Assertion `pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT' failed. + +(see issue 2548 for the repro case). This happens because the guest +attempts USB_TOKEN_SETUP to an endpoint other than 0, which is not +valid. The controller code doesn't catch this guest error, so +instead we hit the assertion in the USB core code. + +Catch the case of SETUP to non-zero endpoint, and treat it as a fatal +error in the TD, in the same way we do for an invalid PID value in +the TD. + +This is the UHCI equivalent of the same bug in OHCI that we fixed in +commit 3c3c233677 ("hw/usb/hcd-ohci: Fix #1510, #303: pid not IN or +OUT"). + +This bug has been tracked as CVE-2024-8354. + +Cc: qemu-stable@nongnu.org +Fixes: https://gitlab.com/qemu-project/qemu/-/issues/2548 +Signed-off-by: Peter Maydell +Reviewed-by: Michael Tokarev +--- + hw/usb/hcd-uhci.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index a92581ff5f..4ed30c59c7 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -763,6 +763,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + bool spd; + bool queuing = (q != NULL); + uint8_t pid = td->token & 0xff; ++ uint8_t ep_id = (td->token >> 15) & 0xf; + UHCIAsync *async; + + async = uhci_async_find_td(s, td_addr); +@@ -806,9 +807,14 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + + switch (pid) { + case USB_TOKEN_OUT: +- case USB_TOKEN_SETUP: + case USB_TOKEN_IN: + break; ++ case USB_TOKEN_SETUP: ++ /* SETUP is only valid to endpoint 0 */ ++ if (ep_id == 0) { ++ break; ++ } ++ /* fallthrough */ + default: + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; +@@ -855,7 +861,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, + return uhci_handle_td_error(s, td, td_addr, USB_RET_NODEV, + int_mask); + } +- ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); ++ ep = usb_ep_get(dev, pid, ep_id); + q = uhci_queue_new(s, qh_addr, td, ep); + } + async = uhci_async_alloc(q, td_addr); +-- +2.33.0 + diff --git a/hw-usb-hcd-xhci-Unmap-canceled-packet.patch b/hw-usb-hcd-xhci-Unmap-canceled-packet.patch new file mode 100644 index 00000000..27e42f81 --- /dev/null +++ b/hw-usb-hcd-xhci-Unmap-canceled-packet.patch @@ -0,0 +1,64 @@ +From 04c9b45704f42bd398407acc3e2d3749ac5c00b7 Mon Sep 17 00:00:00 2001 +From: luowei +Date: Wed, 6 Aug 2025 10:26:27 +0800 +Subject: [PATCH] hw/usb/hcd-xhci: Unmap canceled packet cheery-pick from + aca4967567aaa168ce51d54145ba970aafb135de +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the Stop Endpoint Command is received, packets running +asynchronously are canceled and then all packets are cleaned up. Packets +running asynchronously hold the DMA mapping so cleaning the packets leak +the mapping. Remove the mapping after canceling packets to fix the leak. + +Fixes: 62c6ae04 ("xhci: Initial xHCI implementation") +Signed-off-by: default avatarAkihiko Odaki +Reviewed-by: default avatarPhilippe Mathieu-Daudé +Message-ID: <20250418-xhc-v1-1-bb32dab6a67e@daynix.com> +Signed-off-by: default avatarPhilippe Mathieu-Daudé +--- + hw/usb/hcd-xhci.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 4b60114207..3413a36ebe 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -1190,6 +1190,12 @@ static void xhci_ep_free_xfer(XHCITransfer *xfer) + g_free(xfer); + } + ++static void xhci_xfer_unmap(XHCITransfer *xfer) ++{ ++ usb_packet_unmap(&xfer->packet, &xfer->sgl); ++ qemu_sglist_destroy(&xfer->sgl); ++} ++ + static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) + { + int killed = 0; +@@ -1201,6 +1207,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) + + if (t->running_async) { + usb_cancel_packet(&t->packet); ++ xhci_xfer_unmap(t); + t->running_async = 0; + killed = 1; + } +@@ -1483,12 +1490,6 @@ err: + return -1; + } + +-static void xhci_xfer_unmap(XHCITransfer *xfer) +-{ +- usb_packet_unmap(&xfer->packet, &xfer->sgl); +- qemu_sglist_destroy(&xfer->sgl); +-} +- + static void xhci_xfer_report(XHCITransfer *xfer) + { + uint32_t edtla = 0; +-- +2.33.0 + diff --git a/meson-Remove-CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch b/meson-Remove-CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch new file mode 100644 index 00000000..27c54d13 --- /dev/null +++ b/meson-Remove-CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch @@ -0,0 +1,54 @@ +From 19702630b27b96aa48b1acd4e4c9a22a6dfb444e Mon Sep 17 00:00:00 2001 +From: lijunwei +Date: Tue, 23 Sep 2025 16:02:55 +0800 +Subject: [PATCH] meson: Remove CONFIG_STATX and CONFIG_STATX_MNT_ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CONFIG_STATX and CONFIG_STATX_MNT_ID are not used since commit +e0dc2631 ("virtiofsd: Remove source"). + +Cc: qemu-stable@nongnu.org +Signed-off-by: default avatarAkihiko Odaki +Reviewed-by: default avatarPhilippe Mathieu-Daudé +Tested-by: default avatarPhilippe Mathieu-Daudé +Message-ID: <20250424-buildsys-v1-2-97655e3b25d7@daynix.com> +Signed-off-by: default avatarPhilippe Mathieu-Daudé +(cherry picked from commit 6804b89f) +Signed-off-by: default avatarMichael Tokarev +--- + meson.build | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/meson.build b/meson.build +index d221f5cad5..66c66c1ada 100644 +--- a/meson.build ++++ b/meson.build +@@ -1921,14 +1921,6 @@ gnu_source_prefix = ''' + #endif + ''' + +-# Check whether the glibc provides STATX_BASIC_STATS +- +-has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix) +- +-# Check whether statx() provides mount ID information +- +-has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix) +- + have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ + .require(targetos == 'linux', + error_message: 'vhost_user_blk_server requires linux') \ +@@ -2304,8 +2296,6 @@ config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found()) + config_host_data.set('CONFIG_HOGWEED', hogweed.found()) + config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') + config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) +-config_host_data.set('CONFIG_STATX', has_statx) +-config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id) + config_host_data.set('CONFIG_ZSTD', zstd.found()) + config_host_data.set('CONFIG_QPL', qpl.found()) + config_host_data.set('CONFIG_UADK', uadk.found()) +-- +2.33.0 + diff --git a/meson-Use-has_header_symbol-to-check-getcpu.patch b/meson-Use-has_header_symbol-to-check-getcpu.patch new file mode 100644 index 00000000..00f0dbc4 --- /dev/null +++ b/meson-Use-has_header_symbol-to-check-getcpu.patch @@ -0,0 +1,50 @@ +From ddd158c60e9af53567067798eaf3996b012c3a20 Mon Sep 17 00:00:00 2001 +From: lijunwei +Date: Tue, 14 Oct 2025 15:00:01 +0800 +Subject: [PATCH] meson: Use has_header_symbol() to check getcpu() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The use of gnu_source_prefix in the detection of getcpu() was +ineffective because the header file that declares getcpu() when +_GNU_SOURCE is defined was not included. Pass sched.h to +has_header_symbol() so that the existence of the declaration will be +properly checked. + +Cc: qemu-stable@nongnu.org +Signed-off-by: default avatarAkihiko Odaki +Reviewed-by: default avatarPhilippe Mathieu-Daudé +Tested-by: default avatarPhilippe Mathieu-Daudé +Message-ID: <20250424-buildsys-v1-1-97655e3b25d7@daynix.com> +Signed-off-by: default avatarPhilippe Mathieu-Daudé +(cherry picked from commit 563cd698) +Signed-off-by: default avatarMichael Tokarev ')) + # Note that we need to specify prefix: here to avoid incorrectly + # thinking that Windows has posix_memalign() +@@ -2427,6 +2426,8 @@ config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE', + config_host_data.set('CONFIG_FIEMAP', + cc.has_header('linux/fiemap.h') and + cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP')) ++config_host_data.set('CONFIG_GETCPU', ++ cc.has_header_symbol('sched.h', 'getcpu', prefix: gnu_source_prefix)) + config_host_data.set('CONFIG_GETRANDOM', + cc.has_function('getrandom') and + cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) +-- +2.33.0 + diff --git a/migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch b/migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch new file mode 100644 index 00000000..4d8eb2f0 --- /dev/null +++ b/migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch @@ -0,0 +1,41 @@ +From 47d070644db6fd423da4e01728d91117180b7908 Mon Sep 17 00:00:00 2001 +From: lijunwei +Date: Tue, 14 Oct 2025 15:13:40 +0800 +Subject: [PATCH] migration: fix SEEK_CUR offset calculation in + qio_channel_block_seek +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SEEK_CUR case in qio_channel_block_seek was incorrectly using the +'whence' parameter instead of the 'offset' parameter when calculating the +new position. + +Fixes: 65cf200a ("migration: introduce a QIOChannel impl for BlockDriverState VMState") +Signed-off-by: default avatarMarco Cavenati +Reviewed-by: default avatarDaniel P. Berrangé +Reviewed-by: default avatarMichael Tokarev +Message-ID: <20250326162230.3323199-1-Marco.Cavenati@eurecom.fr> +Signed-off-by: default avatarFabiano Rosas +(cherry picked from commit c0b32426) +Signed-off-by: default avatarMichael Tokarev +--- + migration/channel-block.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/migration/channel-block.c b/migration/channel-block.c +index fff8d87094..b0477f5b6d 100644 +--- a/migration/channel-block.c ++++ b/migration/channel-block.c +@@ -123,7 +123,7 @@ qio_channel_block_seek(QIOChannel *ioc, + bioc->offset = offset; + break; + case SEEK_CUR: +- bioc->offset += whence; ++ bioc->offset += offset; + break; + case SEEK_END: + error_setg(errp, "Size of VMstate region is unknown"); +-- +2.33.0 + diff --git a/qemu.spec b/qemu.spec index d9355aad..c3d6bf48 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 47 +Release: 48 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1093,6 +1093,14 @@ Patch1076: target-riscv-kvm-update-the-KVM-regs-to-Linux-rvck-6.patch Patch1077: target-riscv-kvm-Fix-exposure-of-Zkr.patch Patch1078: hw-arm-virt-Introduce-a-IPIV-machine-option.patch Patch1079: hw-vfio-migration-Fix-vfio-migration-isn-t-aborted-i.patch +Patch1080: common-user-host-riscv-use-tail-pseudoinstruction-fo.patch +Patch1081: meson-Remove-CONFIG_STATX-and-CONFIG_STATX_MNT_ID.patch +Patch1082: qga-fix-potentially-not-initialized-nr_volumes-in-qg.patch +Patch1083: hw-usb-hcd-uhci-don-t-assert-for-SETUP-to-non-0-endp.patch +Patch1084: hw-usb-hcd-xhci-Unmap-canceled-packet.patch +Patch1085: meson-Use-has_header_symbol-to-check-getcpu.patch +Patch1086: hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch +Patch1087: migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch BuildRequires: flex BuildRequires: gcc @@ -1691,6 +1699,16 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Fri Oct 24 2025 Pengrui Zhang - 11:8.2.0-48 +- common-user/host/riscv: use tail pseudoinstruction for calling tail +- meson: Remove CONFIG_STATX and CONFIG_STATX_MNT_ID +- qga: fix potentially not initialized nr_volumes in qga_vss_fsfreeze() +- hw/usb/hcd-uhci: don't assert for SETUP to non-0 endpoint(CVE-2024-8354) +- hw/usb/hcd-xhci: Unmap canceled packet +- meson: Use has_header_symbol() to check getcpu() +- hw/intc/arm_gicv3_cpuif: Don't downgrade monitor traps for AArch32 EL3 +- migration: fix SEEK_CUR offset calculation in qio_channel_block_seek + * Wed Oct 22 2025 Junqi Ma - 11:8.2.0-47 - target/s390x: Fix MVC not always invalidating translation blocks - target/sparc: Fix gdbstub incorrectly handling registers f32-f62 diff --git a/qga-fix-potentially-not-initialized-nr_volumes-in-qg.patch b/qga-fix-potentially-not-initialized-nr_volumes-in-qg.patch new file mode 100644 index 00000000..df347485 --- /dev/null +++ b/qga-fix-potentially-not-initialized-nr_volumes-in-qg.patch @@ -0,0 +1,61 @@ +From 78427e1c7669c60f3e0d3577830477b69dc498d2 Mon Sep 17 00:00:00 2001 +From: jipengfei +Date: Thu, 7 Aug 2025 15:32:21 +0200 +Subject: [PATCH] qga: fix potentially not initialized nr_volumes in + qga_vss_fsfreeze() + +In this function we could have this variable not initialized. If this +could be acceptable on error, the variable could be left not initialized +f.e. as follows: + +void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) +{ + ... + if (mountpoints) { + ... + if (num_mount_points == 0) { + /* If there is no valid mount points, just exit. */ + goto out; + } + } + ... + if (!mountpoints) { + ... + if (num_fixed_drives == 0) { + goto out; /* If there is no fixed drive, just exit. */ + } + } + ... +} + +Stay on safe side, initialize the variable at the beginning. + +cheery-pick from 42bdb911c22f9449f7a310efc73b70548ca42b24 + +Signed-off-by:jipengfei +Signed-off-by: Denis V. Lunev +CC: Kostiantyn Kostiuk +CC: Michael Roth +Reviewed-by: Kostiantyn Kostiuk +Link: https://lore.kernel.org/qemu-devel/20250807133221.1135453-1-den@openvz.org +Signed-off-by: Kostiantyn Kostiuk +--- + qga/vss-win32.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qga/vss-win32.c b/qga/vss-win32.c +index f444a25a70..b272bfc782 100644 +--- a/qga/vss-win32.c ++++ b/qga/vss-win32.c +@@ -157,6 +157,8 @@ void qga_vss_fsfreeze(int *nr_volume, bool freeze, + .errp = errp, + }; + ++ *nr_volume = 0; ++ + g_assert(errp); /* requester.cpp requires it */ + func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name); + if (!func) { +-- +2.33.0 + -- Gitee From 34db9489729f5660ec666595c01a6f97cae5f4d5 Mon Sep 17 00:00:00 2001 From: zhangpengrui Date: Thu, 30 Oct 2025 10:04:32 +0800 Subject: [PATCH 13/14] QEMU update to version 8.2.0-49 Signed-off-by: zhangpengrui (cherry picked from commit 6b81e8571f56d3a889506f90bd04e8c32a6bcfcd) Signed-off-by: zhangpengrui --- ...he-compilation-of-target-arm-softmmu.patch | 28 + ...virt-Introduce-a-IPIV-machine-option.patch | 108 ++ arm-cpu-Add-generated-sysreg-properties.patch | 783 ++++++++++++ ...a-to-handle-generated-ID-register-de.patch | 175 +++ ...-sysreg-definitions-in-cpu-sysregs.h.patch | 229 ++++ arm-cpu-Add-sysreg-generation-scripts.patch | 123 ++ ...cpu-Add-sysreg-properties-generation.patch | 385 ++++++ ...ore-aa64dfr0-1-into-the-idregs-array.patch | 430 +++++++ ...64isar0-aa64zfr0-into-the-idregs-arr.patch | 710 +++++++++++ ...re-aa64isar1-2-into-the-idregs-array.patch | 386 ++++++ ...re-aa64mmfr0-2-into-the-idregs-array.patch | 563 +++++++++ ...ore-aa64pfr0-1-into-the-idregs-array.patch | 558 +++++++++ ...tore-aa64smfr0-into-the-idregs-array.patch | 133 ++ ...tore-id_dfr0-1-into-the-idregs-array.patch | 468 +++++++ ...ore-id_isar0-7-into-the-idregs-array.patch | 1093 +++++++++++++++++ ...ore-id_mmfr0-5-into-the-idregs-array.patch | 703 +++++++++++ ...re-id_pfr0-1-2-into-the-idregs-array.patch | 575 +++++++++ ...-accessors-for-writable-id-registers.patch | 51 + arm-cpu-enable-MIDR-writable.patch | 34 + ...-features-document-ID-reg-properties.patch | 159 +++ ...ually-make-MIDR-REVIDR-AIDR-writable.patch | 122 ++ ...tomization-for-the-kvm-host-cpu-mode.patch | 277 +++++ ...tch-to-a-generated-cpu-sysregs.h.inc.patch | 85 ++ ...eading-all-the-writable-ID-registers.patch | 262 ++++ arm-kvm-use-fd-instead-of-fdarray-2.patch | 45 + ...m-write-back-modified-ID-regs-to-KVM.patch | 142 +++ ...-introspection-for-ID-register-props.patch | 66 + ...tial-support-to-set-target_impl-CPUs.patch | 256 ++++ kvm-kvm_get_writable_id_regs.patch | 139 +++ qemu.spec | 75 +- target-arm-add-ipiv-on-off-option.patch | 78 ++ ...m-kvm-Add-SMMC-hypercall-definitions.patch | 73 ++ ...rm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch | 40 + ...vm-Use-PSCI_VERSIOn-for-version-info.patch | 35 + 34 files changed, 9388 insertions(+), 1 deletion(-) create mode 100644 Fix-the-compilation-of-target-arm-softmmu.patch create mode 100644 Revert-hw-arm-virt-Introduce-a-IPIV-machine-option.patch create mode 100644 arm-cpu-Add-generated-sysreg-properties.patch create mode 100644 arm-cpu-Add-infra-to-handle-generated-ID-register-de.patch create mode 100644 arm-cpu-Add-sysreg-definitions-in-cpu-sysregs.h.patch create mode 100644 arm-cpu-Add-sysreg-generation-scripts.patch create mode 100644 arm-cpu-Add-sysreg-properties-generation.patch create mode 100644 arm-cpu-Store-aa64dfr0-1-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-aa64isar0-aa64zfr0-into-the-idregs-arr.patch create mode 100644 arm-cpu-Store-aa64isar1-2-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-aa64mmfr0-2-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-aa64pfr0-1-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-aa64smfr0-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-id_dfr0-1-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-id_isar0-7-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-id_mmfr0-5-into-the-idregs-array.patch create mode 100644 arm-cpu-Store-id_pfr0-1-2-into-the-idregs-array.patch create mode 100644 arm-cpu-accessors-for-writable-id-registers.patch create mode 100644 arm-cpu-enable-MIDR-writable.patch create mode 100644 arm-cpu-features-document-ID-reg-properties.patch create mode 100644 arm-cpu-manually-make-MIDR-REVIDR-AIDR-writable.patch create mode 100644 arm-cpu-more-customization-for-the-kvm-host-cpu-mode.patch create mode 100644 arm-cpu-switch-to-a-generated-cpu-sysregs.h.inc.patch create mode 100644 arm-kvm-Allow-reading-all-the-writable-ID-registers.patch create mode 100644 arm-kvm-use-fd-instead-of-fdarray-2.patch create mode 100644 arm-kvm-write-back-modified-ID-regs-to-KVM.patch create mode 100644 arm-qmp-cmds-introspection-for-ID-register-props.patch create mode 100644 hw-arm-virt-Initial-support-to-set-target_impl-CPUs.patch create mode 100644 kvm-kvm_get_writable_id_regs.patch create mode 100644 target-arm-add-ipiv-on-off-option.patch create mode 100644 target-arm-kvm-Add-SMMC-hypercall-definitions.patch create mode 100644 target-arm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch create mode 100644 target-arm-kvm-Use-PSCI_VERSIOn-for-version-info.patch diff --git a/Fix-the-compilation-of-target-arm-softmmu.patch b/Fix-the-compilation-of-target-arm-softmmu.patch new file mode 100644 index 00000000..070233c6 --- /dev/null +++ b/Fix-the-compilation-of-target-arm-softmmu.patch @@ -0,0 +1,28 @@ +From 54926203be817a82c7062cc5b277d488e6836758 Mon Sep 17 00:00:00 2001 +From: Jian Cai +Date: Thu, 30 Oct 2025 15:49:31 +0800 +Subject: [PATCH] Fix the compilation of target arm-softmmu + +Fix the compilation of target arm-softmmu. + +Signed-off-by: Jian Cai +--- + target/arm/kvm_arm.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 8c69957fbf..13509b7836 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -534,7 +534,7 @@ static inline int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap) + return -ENOSYS; + } + +-void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu) ++static inline void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu) + { + g_assert_not_reached(); + } +-- +2.33.0 + diff --git a/Revert-hw-arm-virt-Introduce-a-IPIV-machine-option.patch b/Revert-hw-arm-virt-Introduce-a-IPIV-machine-option.patch new file mode 100644 index 00000000..beb14a58 --- /dev/null +++ b/Revert-hw-arm-virt-Introduce-a-IPIV-machine-option.patch @@ -0,0 +1,108 @@ +From cf868536745ed2db3c0e148e34039a829dbbf4b7 Mon Sep 17 00:00:00 2001 +From: Jinqian Yang +Date: Mon, 20 Oct 2025 16:06:49 +0800 +Subject: [PATCH] Revert "hw/arm/virt: Introduce a IPIV machine option" + +This reverts commit 9db5487d84eef5ba38adefb70138644d1012f05f. +This patch will cause virsh to fail to start because libvirt first +starts a QEMU process with `-machine none` for initialization, and +then starts one with `-machine virt`. When using `-machine none`, +the VIRT_MACHINE conversion will result in an error. + +Signed-off-by: Jinqian Yang +--- + hw/arm/virt.c | 19 ------------------- + include/hw/arm/virt.h | 1 - + target/arm/kvm.c | 10 ++-------- + 3 files changed, 2 insertions(+), 28 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index db1b9715e0..f7a9ba9a58 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -3044,20 +3044,6 @@ static void virt_set_its(Object *obj, bool value, Error **errp) + vms->its = value; + } + +-static bool virt_get_ipiv(Object *obj, Error **errp) +-{ +- VirtMachineState *vms = VIRT_MACHINE(obj); +- +- return vms->ipiv; +-} +- +-static void virt_set_ipiv(Object *obj, bool value, Error **errp) +-{ +- VirtMachineState *vms = VIRT_MACHINE(obj); +- +- vms->ipiv = value; +-} +- + static void virt_get_dtb_randomness(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +@@ -4100,11 +4086,6 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + "in ACPI table header." + "The string may be up to 8 bytes in size"); + +- object_class_property_add_bool(oc, "ipiv", +- virt_get_ipiv, +- virt_set_ipiv); +- object_class_property_set_description(oc, "ipiv", +- "Set on/off to enable/disable IPIV"); + } + + static char *virt_get_kvm_type(Object *obj, Error **errp G_GNUC_UNUSED) +diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h +index a54b0057fb..fee7c27e0c 100644 +--- a/include/hw/arm/virt.h ++++ b/include/hw/arm/virt.h +@@ -225,7 +225,6 @@ struct VirtMachineState { + bool cpu_hotplug_enabled; + bool ras; + bool mte; +- bool ipiv; + OnOffAuto dtb_randomness; + bool pmu; + int smmu_accel_count; +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 7d443a967d..f45783a9da 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -34,7 +34,6 @@ + #include "hw/irq.h" + #include "qapi/visitor.h" + #include "qemu/log.h" +-#include "hw/arm/virt.h" + + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +@@ -260,15 +259,10 @@ int kvm_arch_get_default_type(MachineState *ms) + return fixed_ipa ? 0 : size; + } + +-static void kvm_update_ipiv_cap(MachineState *ms, KVMState *s) ++static void kvm_update_ipiv_cap(KVMState *s) + { +- VirtMachineState *vms = VIRT_MACHINE(ms); + int ret; + +- if (!vms->ipiv) { +- return; +- } +- + if (!kvm_check_extension(s, KVM_CAP_ARM_HISI_IPIV)) { + return; + } +@@ -355,7 +349,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + } + + kvm_arm_init_debug(s); +- kvm_update_ipiv_cap(ms, s); ++ kvm_update_ipiv_cap(s); + + ret = kvm_arm_rme_init(ms); + if (ret) { +-- +2.33.0 + diff --git a/arm-cpu-Add-generated-sysreg-properties.patch b/arm-cpu-Add-generated-sysreg-properties.patch new file mode 100644 index 00000000..7b849f74 --- /dev/null +++ b/arm-cpu-Add-generated-sysreg-properties.patch @@ -0,0 +1,783 @@ +From 3581592ca359fbeca14d1ee29b1335d97d346d29 Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 17/26] arm/cpu: Add generated sysreg properties + +Generated against Linux 6.14-rc4. + +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-sysreg-properties.c | 748 ++++++++++++++++++++++++++++- + 1 file changed, 726 insertions(+), 22 deletions(-) + +diff --git a/target/arm/cpu-sysreg-properties.c b/target/arm/cpu-sysreg-properties.c +index 8b7ef5badf..94cc496438 100644 +--- a/target/arm/cpu-sysreg-properties.c ++++ b/target/arm/cpu-sysreg-properties.c +@@ -1,24 +1,3 @@ +-/* +- * QEMU ARM CPU SYSREG PROPERTIES +- * to be generated from linux sysreg +- * +- * Copyright (c) Red Hat, Inc. 2024 +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License +- * as published by the Free Software Foundation; either version 2 +- * of the License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see +- * +- */ +- + #include "cpu-custom.h" + + ARM64SysReg arm64_id_regs[NUM_ID_IDX]; +@@ -26,6 +5,657 @@ ARM64SysReg arm64_id_regs[NUM_ID_IDX]; + void initialize_cpu_sysreg_properties(void) + { + memset(arm64_id_regs, 0, sizeof(ARM64SysReg) * NUM_ID_IDX); ++ ++/* For SPMACCESSR_EL12 fields see SPMACCESSR_EL1 */ ++ ++ /* ID_PFR0_EL1 */ ++ ARM64SysReg *ID_PFR0_EL1 = arm64_sysreg_get(ID_PFR0_EL1_IDX); ++ ID_PFR0_EL1->name = "ID_PFR0_EL1"; ++ arm64_sysreg_add_field(ID_PFR0_EL1, "RAS", 28, 31); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "DIT", 24, 27); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "AMU", 20, 23); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "CSV2", 16, 19); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "State3", 12, 15); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "State2", 8, 11); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "State1", 4, 7); ++ arm64_sysreg_add_field(ID_PFR0_EL1, "State0", 0, 3); ++ ++ /* ID_PFR1_EL1 */ ++ ARM64SysReg *ID_PFR1_EL1 = arm64_sysreg_get(ID_PFR1_EL1_IDX); ++ ID_PFR1_EL1->name = "ID_PFR1_EL1"; ++ arm64_sysreg_add_field(ID_PFR1_EL1, "GIC", 28, 31); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "Virt_frac", 24, 27); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "Sec_frac", 20, 23); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "GenTimer", 16, 19); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "Virtualization", 12, 15); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "MProgMod", 8, 11); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "Security", 4, 7); ++ arm64_sysreg_add_field(ID_PFR1_EL1, "ProgMod", 0, 3); ++ ++ /* ID_DFR0_EL1 */ ++ ARM64SysReg *ID_DFR0_EL1 = arm64_sysreg_get(ID_DFR0_EL1_IDX); ++ ID_DFR0_EL1->name = "ID_DFR0_EL1"; ++ arm64_sysreg_add_field(ID_DFR0_EL1, "TraceFilt", 28, 31); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "PerfMon", 24, 27); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "MProfDbg", 20, 23); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "MMapTrc", 16, 19); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "CopTrc", 12, 15); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "MMapDbg", 8, 11); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "CopSDbg", 4, 7); ++ arm64_sysreg_add_field(ID_DFR0_EL1, "CopDbg", 0, 3); ++ ++ /* ID_AFR0_EL1 */ ++ ARM64SysReg *ID_AFR0_EL1 = arm64_sysreg_get(ID_AFR0_EL1_IDX); ++ ID_AFR0_EL1->name = "ID_AFR0_EL1"; ++ arm64_sysreg_add_field(ID_AFR0_EL1, "IMPDEF3", 12, 15); ++ arm64_sysreg_add_field(ID_AFR0_EL1, "IMPDEF2", 8, 11); ++ arm64_sysreg_add_field(ID_AFR0_EL1, "IMPDEF1", 4, 7); ++ arm64_sysreg_add_field(ID_AFR0_EL1, "IMPDEF0", 0, 3); ++ ++ /* ID_MMFR0_EL1 */ ++ ARM64SysReg *ID_MMFR0_EL1 = arm64_sysreg_get(ID_MMFR0_EL1_IDX); ++ ID_MMFR0_EL1->name = "ID_MMFR0_EL1"; ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "InnerShr", 28, 31); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "FCSE", 24, 27); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "AuxReg", 20, 23); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "TCM", 16, 19); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "ShareLvl", 12, 15); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "OuterShr", 8, 11); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "PMSA", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR0_EL1, "VMSA", 0, 3); ++ ++ /* ID_MMFR1_EL1 */ ++ ARM64SysReg *ID_MMFR1_EL1 = arm64_sysreg_get(ID_MMFR1_EL1_IDX); ++ ID_MMFR1_EL1->name = "ID_MMFR1_EL1"; ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "BPred", 28, 31); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1TstCln", 24, 27); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1Uni", 20, 23); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1Hvd", 16, 19); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1UniSW", 12, 15); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1HvdSW", 8, 11); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1UniVA", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR1_EL1, "L1HvdVA", 0, 3); ++ ++ /* ID_MMFR2_EL1 */ ++ ARM64SysReg *ID_MMFR2_EL1 = arm64_sysreg_get(ID_MMFR2_EL1_IDX); ++ ID_MMFR2_EL1->name = "ID_MMFR2_EL1"; ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "HWAccFlg", 28, 31); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "WFIStall", 24, 27); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "MemBarr", 20, 23); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "UniTLB", 16, 19); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "HvdTLB", 12, 15); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "L1HvdRng", 8, 11); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "L1HvdBG", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR2_EL1, "L1HvdFG", 0, 3); ++ ++ /* ID_MMFR3_EL1 */ ++ ARM64SysReg *ID_MMFR3_EL1 = arm64_sysreg_get(ID_MMFR3_EL1_IDX); ++ ID_MMFR3_EL1->name = "ID_MMFR3_EL1"; ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "Supersec", 28, 31); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "CMemSz", 24, 27); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "CohWalk", 20, 23); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "PAN", 16, 19); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "MaintBcst", 12, 15); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "BPMaint", 8, 11); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "CMaintSW", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR3_EL1, "CMaintVA", 0, 3); ++ ++ /* ID_ISAR0_EL1 */ ++ ARM64SysReg *ID_ISAR0_EL1 = arm64_sysreg_get(ID_ISAR0_EL1_IDX); ++ ID_ISAR0_EL1->name = "ID_ISAR0_EL1"; ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "Divide", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "Debug", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "Coproc", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "CmpBranch", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "BitField", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "BitCount", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR0_EL1, "Swap", 0, 3); ++ ++ /* ID_ISAR1_EL1 */ ++ ARM64SysReg *ID_ISAR1_EL1 = arm64_sysreg_get(ID_ISAR1_EL1_IDX); ++ ID_ISAR1_EL1->name = "ID_ISAR1_EL1"; ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Jazelle", 28, 31); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Interwork", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Immediate", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "IfThen", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Extend", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Except_AR", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Except", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR1_EL1, "Endian", 0, 3); ++ ++ /* ID_ISAR2_EL1 */ ++ ARM64SysReg *ID_ISAR2_EL1 = arm64_sysreg_get(ID_ISAR2_EL1_IDX); ++ ID_ISAR2_EL1->name = "ID_ISAR2_EL1"; ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "Reversal", 28, 31); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "PSR_AR", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "MultU", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "MultS", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "Mult", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "MultiAccessInt", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "MemHint", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR2_EL1, "LoadStore", 0, 3); ++ ++ /* ID_ISAR3_EL1 */ ++ ARM64SysReg *ID_ISAR3_EL1 = arm64_sysreg_get(ID_ISAR3_EL1_IDX); ++ ID_ISAR3_EL1->name = "ID_ISAR3_EL1"; ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "T32EE", 28, 31); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "TrueNOP", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "T32Copy", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "TabBranch", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "SynchPrim", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "SVC", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "SIMD", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR3_EL1, "Saturate", 0, 3); ++ ++ /* ID_ISAR4_EL1 */ ++ ARM64SysReg *ID_ISAR4_EL1 = arm64_sysreg_get(ID_ISAR4_EL1_IDX); ++ ID_ISAR4_EL1->name = "ID_ISAR4_EL1"; ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "SWP_frac", 28, 31); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "PSR_M", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "SynchPrim_frac", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "Barrier", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "SMC", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "Writeback", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "WithShifts", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR4_EL1, "Unpriv", 0, 3); ++ ++ /* ID_ISAR5_EL1 */ ++ ARM64SysReg *ID_ISAR5_EL1 = arm64_sysreg_get(ID_ISAR5_EL1_IDX); ++ ID_ISAR5_EL1->name = "ID_ISAR5_EL1"; ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "VCMA", 28, 31); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "RDM", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "CRC32", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "SHA2", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "SHA1", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "AES", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR5_EL1, "SEVL", 0, 3); ++ ++ /* ID_ISAR6_EL1 */ ++ ARM64SysReg *ID_ISAR6_EL1 = arm64_sysreg_get(ID_ISAR6_EL1_IDX); ++ ID_ISAR6_EL1->name = "ID_ISAR6_EL1"; ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "I8MM", 24, 27); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "BF16", 20, 23); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "SPECRES", 16, 19); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "SB", 12, 15); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "FHM", 8, 11); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "DP", 4, 7); ++ arm64_sysreg_add_field(ID_ISAR6_EL1, "JSCVT", 0, 3); ++ ++ /* ID_MMFR4_EL1 */ ++ ARM64SysReg *ID_MMFR4_EL1 = arm64_sysreg_get(ID_MMFR4_EL1_IDX); ++ ID_MMFR4_EL1->name = "ID_MMFR4_EL1"; ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "EVT", 28, 31); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "CCIDX", 24, 27); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "LSM", 20, 23); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "HPDS", 16, 19); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "CnP", 12, 15); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "XNX", 8, 11); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "AC2", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR4_EL1, "SpecSEI", 0, 3); ++ ++ /* MVFR0_EL1 */ ++ ARM64SysReg *MVFR0_EL1 = arm64_sysreg_get(MVFR0_EL1_IDX); ++ MVFR0_EL1->name = "MVFR0_EL1"; ++ arm64_sysreg_add_field(MVFR0_EL1, "FPRound", 28, 31); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPShVec", 24, 27); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPSqrt", 20, 23); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPDivide", 16, 19); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPTrap", 12, 15); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPDP", 8, 11); ++ arm64_sysreg_add_field(MVFR0_EL1, "FPSP", 4, 7); ++ arm64_sysreg_add_field(MVFR0_EL1, "SIMDReg", 0, 3); ++ ++ /* MVFR1_EL1 */ ++ ARM64SysReg *MVFR1_EL1 = arm64_sysreg_get(MVFR1_EL1_IDX); ++ MVFR1_EL1->name = "MVFR1_EL1"; ++ arm64_sysreg_add_field(MVFR1_EL1, "SIMDFMAC", 28, 31); ++ arm64_sysreg_add_field(MVFR1_EL1, "FPHP", 24, 27); ++ arm64_sysreg_add_field(MVFR1_EL1, "SIMDHP", 20, 23); ++ arm64_sysreg_add_field(MVFR1_EL1, "SIMDSP", 16, 19); ++ arm64_sysreg_add_field(MVFR1_EL1, "SIMDInt", 12, 15); ++ arm64_sysreg_add_field(MVFR1_EL1, "SIMDLS", 8, 11); ++ arm64_sysreg_add_field(MVFR1_EL1, "FPDNaN", 4, 7); ++ arm64_sysreg_add_field(MVFR1_EL1, "FPFtZ", 0, 3); ++ ++ /* MVFR2_EL1 */ ++ ARM64SysReg *MVFR2_EL1 = arm64_sysreg_get(MVFR2_EL1_IDX); ++ MVFR2_EL1->name = "MVFR2_EL1"; ++ arm64_sysreg_add_field(MVFR2_EL1, "FPMisc", 4, 7); ++ arm64_sysreg_add_field(MVFR2_EL1, "SIMDMisc", 0, 3); ++ ++ /* ID_PFR2_EL1 */ ++ ARM64SysReg *ID_PFR2_EL1 = arm64_sysreg_get(ID_PFR2_EL1_IDX); ++ ID_PFR2_EL1->name = "ID_PFR2_EL1"; ++ arm64_sysreg_add_field(ID_PFR2_EL1, "RAS_frac", 8, 11); ++ arm64_sysreg_add_field(ID_PFR2_EL1, "SSBS", 4, 7); ++ arm64_sysreg_add_field(ID_PFR2_EL1, "CSV3", 0, 3); ++ ++ /* ID_DFR1_EL1 */ ++ ARM64SysReg *ID_DFR1_EL1 = arm64_sysreg_get(ID_DFR1_EL1_IDX); ++ ID_DFR1_EL1->name = "ID_DFR1_EL1"; ++ arm64_sysreg_add_field(ID_DFR1_EL1, "HPMN0", 4, 7); ++ arm64_sysreg_add_field(ID_DFR1_EL1, "MTPMU", 0, 3); ++ ++ /* ID_MMFR5_EL1 */ ++ ARM64SysReg *ID_MMFR5_EL1 = arm64_sysreg_get(ID_MMFR5_EL1_IDX); ++ ID_MMFR5_EL1->name = "ID_MMFR5_EL1"; ++ arm64_sysreg_add_field(ID_MMFR5_EL1, "nTLBPA", 4, 7); ++ arm64_sysreg_add_field(ID_MMFR5_EL1, "ETS", 0, 3); ++ ++ /* ID_AA64PFR0_EL1 */ ++ ARM64SysReg *ID_AA64PFR0_EL1 = arm64_sysreg_get(ID_AA64PFR0_EL1_IDX); ++ ID_AA64PFR0_EL1->name = "ID_AA64PFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "CSV3", 60, 63); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "CSV2", 56, 59); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "RME", 52, 55); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "DIT", 48, 51); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "AMU", 44, 47); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "MPAM", 40, 43); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "SEL2", 36, 39); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "SVE", 32, 35); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "RAS", 28, 31); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "GIC", 24, 27); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "AdvSIMD", 20, 23); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "AdvSIMD", 20, 23); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "FP", 16, 19); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "FP", 16, 19); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "EL3", 12, 15); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "EL2", 8, 11); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "EL1", 4, 7); ++ arm64_sysreg_add_field(ID_AA64PFR0_EL1, "EL0", 0, 3); ++ ++ /* ID_AA64PFR1_EL1 */ ++ ARM64SysReg *ID_AA64PFR1_EL1 = arm64_sysreg_get(ID_AA64PFR1_EL1_IDX); ++ ID_AA64PFR1_EL1->name = "ID_AA64PFR1_EL1"; ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "PFAR", 60, 63); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "DF2", 56, 59); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "MTEX", 52, 55); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "THE", 48, 51); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "GCS", 44, 47); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "MTE_frac", 40, 43); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "NMI", 36, 39); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "CSV2_frac", 32, 35); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "RNDR_trap", 28, 31); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "SME", 24, 27); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "MPAM_frac", 16, 19); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "RAS_frac", 12, 15); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "MTE", 8, 11); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "SSBS", 4, 7); ++ arm64_sysreg_add_field(ID_AA64PFR1_EL1, "BT", 0, 3); ++ ++ /* ID_AA64PFR2_EL1 */ ++ ARM64SysReg *ID_AA64PFR2_EL1 = arm64_sysreg_get(ID_AA64PFR2_EL1_IDX); ++ ID_AA64PFR2_EL1->name = "ID_AA64PFR2_EL1"; ++ arm64_sysreg_add_field(ID_AA64PFR2_EL1, "FPMR", 32, 35); ++ arm64_sysreg_add_field(ID_AA64PFR2_EL1, "UINJ", 16, 19); ++ arm64_sysreg_add_field(ID_AA64PFR2_EL1, "MTEFAR", 8, 11); ++ arm64_sysreg_add_field(ID_AA64PFR2_EL1, "MTESTOREONLY", 4, 7); ++ arm64_sysreg_add_field(ID_AA64PFR2_EL1, "MTEPERM", 0, 3); ++ ++ /* ID_AA64ZFR0_EL1 */ ++ ARM64SysReg *ID_AA64ZFR0_EL1 = arm64_sysreg_get(ID_AA64ZFR0_EL1_IDX); ++ ID_AA64ZFR0_EL1->name = "ID_AA64ZFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "F64MM", 56, 59); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "F32MM", 52, 55); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "F16MM", 48, 51); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "I8MM", 44, 47); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "SM4", 40, 43); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "SHA3", 32, 35); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "B16B16", 24, 27); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "BF16", 20, 23); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "BitPerm", 16, 19); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "EltPerm", 12, 15); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "AES", 4, 7); ++ arm64_sysreg_add_field(ID_AA64ZFR0_EL1, "SVEver", 0, 3); ++ ++ /* ID_AA64SMFR0_EL1 */ ++ ARM64SysReg *ID_AA64SMFR0_EL1 = arm64_sysreg_get(ID_AA64SMFR0_EL1_IDX); ++ ID_AA64SMFR0_EL1->name = "ID_AA64SMFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "FA64", 63, 63); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "LUTv2", 60, 60); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SMEver", 56, 59); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "I16I64", 52, 55); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F64F64", 48, 48); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "I16I32", 44, 47); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "B16B16", 43, 43); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F16F16", 42, 42); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F8F16", 41, 41); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F8F32", 40, 40); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "I8I32", 36, 39); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F16F32", 35, 35); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "B16F32", 34, 34); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "BI32I32", 33, 33); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "F32F32", 32, 32); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SF8FMA", 30, 30); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SF8DP4", 29, 29); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SF8DP2", 28, 28); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SBitPerm", 25, 25); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "AES", 24, 24); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SFEXPA", 23, 23); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "STMOP", 16, 16); ++ arm64_sysreg_add_field(ID_AA64SMFR0_EL1, "SMOP4", 0, 0); ++ ++ /* ID_AA64FPFR0_EL1 */ ++ ARM64SysReg *ID_AA64FPFR0_EL1 = arm64_sysreg_get(ID_AA64FPFR0_EL1_IDX); ++ ID_AA64FPFR0_EL1->name = "ID_AA64FPFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8CVT", 31, 31); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8FMA", 30, 30); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8DP4", 29, 29); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8DP2", 28, 28); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8MM8", 27, 27); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8MM4", 26, 26); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8E4M3", 1, 1); ++ arm64_sysreg_add_field(ID_AA64FPFR0_EL1, "F8E5M2", 0, 0); ++ ++ /* ID_AA64DFR0_EL1 */ ++ ARM64SysReg *ID_AA64DFR0_EL1 = arm64_sysreg_get(ID_AA64DFR0_EL1_IDX); ++ ID_AA64DFR0_EL1->name = "ID_AA64DFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "HPMN0", 60, 63); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "ExtTrcBuff", 56, 59); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "BRBE", 52, 55); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "MTPMU", 48, 51); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "MTPMU", 48, 51); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "TraceBuffer", 44, 47); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "TraceFilt", 40, 43); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "DoubleLock", 36, 39); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "PMSVer", 32, 35); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "CTX_CMPs", 28, 31); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "SEBEP", 24, 27); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "WRPs", 20, 23); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "PMSS", 16, 19); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "BRPs", 12, 15); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "PMUVer", 8, 11); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "TraceVer", 4, 7); ++ arm64_sysreg_add_field(ID_AA64DFR0_EL1, "DebugVer", 0, 3); ++ ++ /* ID_AA64DFR1_EL1 */ ++ ARM64SysReg *ID_AA64DFR1_EL1 = arm64_sysreg_get(ID_AA64DFR1_EL1_IDX); ++ ID_AA64DFR1_EL1->name = "ID_AA64DFR1_EL1"; ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "ABL_CMPs", 56, 63); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "DPFZS", 52, 55); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "EBEP", 48, 51); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "ITE", 44, 47); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "ABLE", 40, 43); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "PMICNTR", 36, 39); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "SPMU", 32, 35); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "CTX_CMPs", 24, 31); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "WRPs", 16, 23); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "BRPs", 8, 15); ++ arm64_sysreg_add_field(ID_AA64DFR1_EL1, "SYSPMUID", 0, 7); ++ ++ /* ID_AA64DFR2_EL1 */ ++ ARM64SysReg *ID_AA64DFR2_EL1 = arm64_sysreg_get(ID_AA64DFR2_EL1_IDX); ++ ID_AA64DFR2_EL1->name = "ID_AA64DFR2_EL1"; ++ arm64_sysreg_add_field(ID_AA64DFR2_EL1, "TRBE_EXC", 24, 27); ++ arm64_sysreg_add_field(ID_AA64DFR2_EL1, "SPE_nVM", 20, 23); ++ arm64_sysreg_add_field(ID_AA64DFR2_EL1, "SPE_EXC", 16, 19); ++ arm64_sysreg_add_field(ID_AA64DFR2_EL1, "BWE", 4, 7); ++ arm64_sysreg_add_field(ID_AA64DFR2_EL1, "STEP", 0, 3); ++ ++ /* ID_AA64AFR0_EL1 */ ++ ARM64SysReg *ID_AA64AFR0_EL1 = arm64_sysreg_get(ID_AA64AFR0_EL1_IDX); ++ ID_AA64AFR0_EL1->name = "ID_AA64AFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF7", 28, 31); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF6", 24, 27); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF5", 20, 23); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF4", 16, 19); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF3", 12, 15); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF2", 8, 11); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF1", 4, 7); ++ arm64_sysreg_add_field(ID_AA64AFR0_EL1, "IMPDEF0", 0, 3); ++ ++ /* ID_AA64AFR1_EL1 */ ++ ARM64SysReg *ID_AA64AFR1_EL1 = arm64_sysreg_get(ID_AA64AFR1_EL1_IDX); ++ ID_AA64AFR1_EL1->name = "ID_AA64AFR1_EL1"; ++ ++ /* ID_AA64ISAR0_EL1 */ ++ ARM64SysReg *ID_AA64ISAR0_EL1 = arm64_sysreg_get(ID_AA64ISAR0_EL1_IDX); ++ ID_AA64ISAR0_EL1->name = "ID_AA64ISAR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "RNDR", 60, 63); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "TLB", 56, 59); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "TS", 52, 55); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "FHM", 48, 51); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "DP", 44, 47); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "SM4", 40, 43); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "SM3", 36, 39); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "SHA3", 32, 35); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "RDM", 28, 31); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "TME", 24, 27); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "ATOMIC", 20, 23); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "CRC32", 16, 19); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "SHA2", 12, 15); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "SHA1", 8, 11); ++ arm64_sysreg_add_field(ID_AA64ISAR0_EL1, "AES", 4, 7); ++ ++ /* ID_AA64ISAR1_EL1 */ ++ ARM64SysReg *ID_AA64ISAR1_EL1 = arm64_sysreg_get(ID_AA64ISAR1_EL1_IDX); ++ ID_AA64ISAR1_EL1->name = "ID_AA64ISAR1_EL1"; ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "LS64", 60, 63); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "XS", 56, 59); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "I8MM", 52, 55); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "DGH", 48, 51); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "BF16", 44, 47); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "SPECRES", 40, 43); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "SB", 36, 39); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "FRINTTS", 32, 35); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "GPI", 28, 31); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "GPA", 24, 27); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "LRCPC", 20, 23); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "FCMA", 16, 19); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "JSCVT", 12, 15); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "API", 8, 11); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "APA", 4, 7); ++ arm64_sysreg_add_field(ID_AA64ISAR1_EL1, "DPB", 0, 3); ++ ++ /* ID_AA64ISAR2_EL1 */ ++ ARM64SysReg *ID_AA64ISAR2_EL1 = arm64_sysreg_get(ID_AA64ISAR2_EL1_IDX); ++ ID_AA64ISAR2_EL1->name = "ID_AA64ISAR2_EL1"; ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "ATS1A", 60, 63); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "LUT", 56, 59); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "CSSC", 52, 55); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "RPRFM", 48, 51); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "PCDPHINT", 44, 47); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "PRFMSLC", 40, 43); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "SYSINSTR_128", 36, 39); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "SYSREG_128", 32, 35); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "CLRBHB", 28, 31); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "PAC_frac", 24, 27); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "BC", 20, 23); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "MOPS", 16, 19); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "APA3", 12, 15); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "GPA3", 8, 11); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "RPRES", 4, 7); ++ arm64_sysreg_add_field(ID_AA64ISAR2_EL1, "WFxT", 0, 3); ++ ++ /* ID_AA64ISAR3_EL1 */ ++ ARM64SysReg *ID_AA64ISAR3_EL1 = arm64_sysreg_get(ID_AA64ISAR3_EL1_IDX); ++ ID_AA64ISAR3_EL1->name = "ID_AA64ISAR3_EL1"; ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "FPRCVT", 28, 31); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "LSUI", 24, 27); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "OCCMO", 20, 23); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "LSFE", 16, 19); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "PACM", 12, 15); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "TLBIW", 8, 11); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "FAMINMAX", 4, 7); ++ arm64_sysreg_add_field(ID_AA64ISAR3_EL1, "CPA", 0, 3); ++ ++ /* ID_AA64MMFR0_EL1 */ ++ ARM64SysReg *ID_AA64MMFR0_EL1 = arm64_sysreg_get(ID_AA64MMFR0_EL1_IDX); ++ ID_AA64MMFR0_EL1->name = "ID_AA64MMFR0_EL1"; ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "ECV", 60, 63); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "FGT", 56, 59); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "EXS", 44, 47); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN4_2", 40, 43); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN64_2", 36, 39); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN16_2", 32, 35); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN4", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN4", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN64", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN64", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "TGRAN16", 20, 23); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "BIGENDEL0", 16, 19); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "SNSMEM", 12, 15); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "BIGEND", 8, 11); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "ASIDBITS", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR0_EL1, "PARANGE", 0, 3); ++ ++ /* ID_AA64MMFR1_EL1 */ ++ ARM64SysReg *ID_AA64MMFR1_EL1 = arm64_sysreg_get(ID_AA64MMFR1_EL1_IDX); ++ ID_AA64MMFR1_EL1->name = "ID_AA64MMFR1_EL1"; ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "ECBHB", 60, 63); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "CMOW", 56, 59); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "TIDCP1", 52, 55); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "nTLBPA", 48, 51); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "AFP", 44, 47); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "HCX", 40, 43); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "ETS", 36, 39); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "TWED", 32, 35); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "XNX", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "SpecSEI", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "PAN", 20, 23); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "LO", 16, 19); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "HPDS", 12, 15); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "VH", 8, 11); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "VMIDBits", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR1_EL1, "HAFDBS", 0, 3); ++ ++ /* ID_AA64MMFR2_EL1 */ ++ ARM64SysReg *ID_AA64MMFR2_EL1 = arm64_sysreg_get(ID_AA64MMFR2_EL1_IDX); ++ ID_AA64MMFR2_EL1->name = "ID_AA64MMFR2_EL1"; ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "E0PD", 60, 63); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "EVT", 56, 59); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "BBM", 52, 55); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "TTL", 48, 51); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "FWB", 40, 43); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "IDS", 36, 39); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "AT", 32, 35); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "ST", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "NV", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "CCIDX", 20, 23); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "VARange", 16, 19); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "IESB", 12, 15); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "LSM", 8, 11); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "UAO", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR2_EL1, "CnP", 0, 3); ++ ++ /* ID_AA64MMFR3_EL1 */ ++ ARM64SysReg *ID_AA64MMFR3_EL1 = arm64_sysreg_get(ID_AA64MMFR3_EL1_IDX); ++ ID_AA64MMFR3_EL1->name = "ID_AA64MMFR3_EL1"; ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "Spec_FPACC", 60, 63); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "ADERR", 56, 59); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "SDERR", 52, 55); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "ANERR", 44, 47); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "SNERR", 40, 43); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "D128_2", 36, 39); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "D128", 32, 35); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "MEC", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "AIE", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "S2POE", 20, 23); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "S1POE", 16, 19); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "S2PIE", 12, 15); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "S1PIE", 8, 11); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "SCTLRX", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR3_EL1, "TCRX", 0, 3); ++ ++ /* ID_AA64MMFR4_EL1 */ ++ ARM64SysReg *ID_AA64MMFR4_EL1 = arm64_sysreg_get(ID_AA64MMFR4_EL1_IDX); ++ ID_AA64MMFR4_EL1->name = "ID_AA64MMFR4_EL1"; ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "SRMASK", 44, 47); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "E3DSE", 36, 39); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "RMEGDI", 28, 31); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "E2H0", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "E2H0", 24, 27); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "NV_frac", 20, 23); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "FGWTE3", 16, 19); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "HACDBS", 12, 15); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "ASID2", 8, 11); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "EIESB", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "EIESB", 4, 7); ++ arm64_sysreg_add_field(ID_AA64MMFR4_EL1, "PoPS", 0, 3); ++ ++/* For SCTLR_EL12 fields see SCTLR_EL1 */ ++ ++/* For SCTLRALIAS_EL1 fields see SCTLR_EL1 */ ++ ++/* For ACTLR_EL12 fields see ACTLR_EL1 */ ++ ++/* For ACTLRALIAS_EL1 fields see ACTLR_EL1 */ ++ ++/* For CPACR_EL12 fields see CPACR_EL1 */ ++ ++/* For CPACRALIAS_EL1 fields see CPACR_EL1 */ ++ ++/* For ACTLRMASK_EL12 fields see ACTLRMASK_EL1 */ ++ ++/* For CPACRMASK_EL12 fields see CPACRMASK_EL1 */ ++ ++/* For PFAR_EL12 fields see PFAR_EL1 */ ++ ++/* For SCTLR2_EL12 fields see SCTLR2_EL1 */ ++ ++/* For SCTLR2ALIAS_EL1 fields see SCTLR2_EL1 */ ++ ++/* For SCTLR2MASK_EL12 fields see SCTLR2MASK_EL1 */ ++ ++/* For SCTLRMASK_EL12 fields see SCTLRMASK_EL1 */ ++ ++/* For TCR2MASK_EL12 fields see TCR2MASK_EL1 */ ++ ++/* For TCRMASK_EL12 fields see TCRMASK_EL1 */ ++ ++/* For TRCITECR_EL12 fields see TRCITECR_EL1 */ ++ ++/* For ZCR_EL1 fields see ZCR_ELx */ ++ ++/* For SMCR_EL1 fields see SMCR_ELx */ ++ ++/* For GCSCR_EL1 fields see GCSCR_ELx */ ++ ++/* For GCSPR_EL1 fields see GCSPR_ELx */ ++ ++/* For CONTEXTIDR_EL1 fields see CONTEXTIDR_ELx */ ++ ++ /* CCSIDR_EL1 */ ++ ARM64SysReg *CCSIDR_EL1 = arm64_sysreg_get(CCSIDR_EL1_IDX); ++ CCSIDR_EL1->name = "CCSIDR_EL1"; ++ arm64_sysreg_add_field(CCSIDR_EL1, "NumSets", 13, 27); ++ arm64_sysreg_add_field(CCSIDR_EL1, "Associativity", 3, 12); ++ arm64_sysreg_add_field(CCSIDR_EL1, "LineSize", 0, 2); ++ ++ /* CLIDR_EL1 */ ++ ARM64SysReg *CLIDR_EL1 = arm64_sysreg_get(CLIDR_EL1_IDX); ++ CLIDR_EL1->name = "CLIDR_EL1"; ++ arm64_sysreg_add_field(CLIDR_EL1, "Ttypen", 33, 46); ++ arm64_sysreg_add_field(CLIDR_EL1, "ICB", 30, 32); ++ arm64_sysreg_add_field(CLIDR_EL1, "LoUU", 27, 29); ++ arm64_sysreg_add_field(CLIDR_EL1, "LoC", 24, 26); ++ arm64_sysreg_add_field(CLIDR_EL1, "LoUIS", 21, 23); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype7", 18, 20); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype6", 15, 17); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype5", 12, 14); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype4", 9, 11); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype3", 6, 8); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype2", 3, 5); ++ arm64_sysreg_add_field(CLIDR_EL1, "Ctype1", 0, 2); ++ ++ /* CCSIDR2_EL1 */ ++ ARM64SysReg *CCSIDR2_EL1 = arm64_sysreg_get(CCSIDR2_EL1_IDX); ++ CCSIDR2_EL1->name = "CCSIDR2_EL1"; ++ arm64_sysreg_add_field(CCSIDR2_EL1, "NumSets", 0, 23); ++ ++ /* GMID_EL1 */ ++ ARM64SysReg *GMID_EL1 = arm64_sysreg_get(GMID_EL1_IDX); ++ GMID_EL1->name = "GMID_EL1"; ++ arm64_sysreg_add_field(GMID_EL1, "BS", 0, 3); ++ ++ /* SMIDR_EL1 */ ++ ARM64SysReg *SMIDR_EL1 = arm64_sysreg_get(SMIDR_EL1_IDX); ++ SMIDR_EL1->name = "SMIDR_EL1"; ++ arm64_sysreg_add_field(SMIDR_EL1, "IMPLEMENTER", 24, 31); ++ arm64_sysreg_add_field(SMIDR_EL1, "REVISION", 16, 23); ++ arm64_sysreg_add_field(SMIDR_EL1, "SMPS", 15, 15); ++ arm64_sysreg_add_field(SMIDR_EL1, "AFFINITY", 0, 11); ++ + /* CTR_EL0 */ + ARM64SysReg *CTR_EL0 = arm64_sysreg_get(CTR_EL0_IDX); + CTR_EL0->name = "CTR_EL0"; +@@ -37,5 +667,79 @@ void initialize_cpu_sysreg_properties(void) + arm64_sysreg_add_field(CTR_EL0, "DminLine", 16, 19); + arm64_sysreg_add_field(CTR_EL0, "L1Ip", 14, 15); + arm64_sysreg_add_field(CTR_EL0, "IminLine", 0, 3); +-} + ++ /* DCZID_EL0 */ ++ ARM64SysReg *DCZID_EL0 = arm64_sysreg_get(DCZID_EL0_IDX); ++ DCZID_EL0->name = "DCZID_EL0"; ++ arm64_sysreg_add_field(DCZID_EL0, "DZP", 4, 4); ++ arm64_sysreg_add_field(DCZID_EL0, "BS", 0, 3); ++ ++/* For GCSPR_EL0 fields see GCSPR_ELx */ ++ ++/* For ZCR_EL2 fields see ZCR_ELx */ ++ ++/* For SMCR_EL2 fields see SMCR_ELx */ ++ ++/* For GCSCR_EL2 fields see GCSCR_ELx */ ++ ++/* For GCSPR_EL2 fields see GCSPR_ELx */ ++ ++/* For CONTEXTIDR_EL2 fields see CONTEXTIDR_ELx */ ++ ++/* For CPACR_EL12 fields see CPACR_EL1 */ ++ ++/* For ZCR_EL12 fields see ZCR_EL1 */ ++ ++/* For TRFCR_EL12 fields see TRFCR_EL1 */ ++ ++/* For SMCR_EL12 fields see SMCR_EL1 */ ++ ++/* For GCSCR_EL12 fields see GCSCR_EL1 */ ++ ++/* For GCSPR_EL12 fields see GCSPR_EL1 */ ++ ++/* For MPAM1_EL12 fields see MPAM1_ELx */ ++ ++/* For CONTEXTIDR_EL12 fields see CONTEXTIDR_EL1 */ ++ ++/* For TTBR0_EL1 fields see TTBRx_EL1 */ ++ ++/* For TTBR1_EL1 fields see TTBRx_EL1 */ ++ ++/* For TCR_EL12 fields see TCR_EL1 */ ++ ++/* For TCRALIAS_EL1 fields see TCR_EL1 */ ++ ++/* For TCR2_EL12 fields see TCR2_EL1 */ ++ ++/* For TCR2ALIAS_EL1 fields see TCR2_EL1 */ ++ ++/* For MAIR2_EL1 fields see MAIR2_ELx */ ++ ++/* For MAIR2_EL2 fields see MAIR2_ELx */ ++ ++/* For PIRE0_EL1 fields see PIRx_ELx */ ++ ++/* For PIRE0_EL12 fields see PIRE0_EL1 */ ++ ++/* For PIRE0_EL2 fields see PIRx_ELx */ ++ ++/* For PIR_EL1 fields see PIRx_ELx */ ++ ++/* For PIR_EL12 fields see PIR_EL1 */ ++ ++/* For PIR_EL2 fields see PIRx_ELx */ ++ ++/* For POR_EL0 fields see PIRx_ELx */ ++ ++/* For POR_EL1 fields see PIRx_ELx */ ++ ++/* For POR_EL2 fields see PIRx_ELx */ ++ ++/* For POR_EL12 fields see POR_EL1 */ ++ ++/* For S2POR_EL1 fields see PIRx_ELx */ ++ ++/* For S2PIR_EL2 fields see PIRx_ELx */ ++ ++} +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Add-infra-to-handle-generated-ID-register-de.patch b/arm-cpu-Add-infra-to-handle-generated-ID-register-de.patch new file mode 100644 index 00000000..98daf697 --- /dev/null +++ b/arm-cpu-Add-infra-to-handle-generated-ID-register-de.patch @@ -0,0 +1,175 @@ +From 39eea84e3923cca8d0bb9fba1c87b2965d14eed2 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 15/26] arm/cpu: Add infra to handle generated ID register + definitions + +The known ID regs are described in a new initialization function +dubbed initialize_cpu_sysreg_properties(). That code will be +automatically generated from linux arch/arm64/tools/sysreg. For the +time being let's just describe a single id reg, CTR_EL0. In this +description we only care about non RES/RAZ fields, ie. named fields. + +The registers are populated in an array indexed by ARMIDRegisterIdx +and their fields are added in a sorted list. + +[CH: adapted to reworked register storage] +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-custom.h | 60 ++++++++++++++++++++++++++++++ + target/arm/cpu-sysreg-properties.c | 41 ++++++++++++++++++++ + target/arm/cpu64.c | 2 + + target/arm/meson.build | 1 + + 4 files changed, 104 insertions(+) + create mode 100644 target/arm/cpu-custom.h + create mode 100644 target/arm/cpu-sysreg-properties.c + +diff --git a/target/arm/cpu-custom.h b/target/arm/cpu-custom.h +new file mode 100644 +index 0000000000..615347376e +--- /dev/null ++++ b/target/arm/cpu-custom.h +@@ -0,0 +1,60 @@ ++/* ++ * handle ID registers and their fields ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++#ifndef ARM_CPU_CUSTOM_H ++#define ARM_CPU_CUSTOM_H ++ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "cpu.h" ++#include "cpu-sysregs.h" ++ ++typedef struct ARM64SysRegField { ++ const char *name; /* name of the field, for instance CTR_EL0_IDC */ ++ int index; ++ int lower; ++ int upper; ++} ARM64SysRegField; ++ ++typedef struct ARM64SysReg { ++ const char *name; /* name of the sysreg, for instance CTR_EL0 */ ++ ARMSysRegs sysreg; ++ int index; ++ GList *fields; /* list of named fields, excluding RES* */ ++} ARM64SysReg; ++ ++void initialize_cpu_sysreg_properties(void); ++ ++/* ++ * List of exposed ID regs (automatically populated from linux ++ * arch/arm64/tools/sysreg) ++ */ ++extern ARM64SysReg arm64_id_regs[NUM_ID_IDX]; ++ ++/* Allocate a new field and insert it at the head of the @reg list */ ++static inline GList *arm64_sysreg_add_field(ARM64SysReg *reg, const char *name, ++ uint8_t min, uint8_t max) { ++ ++ ARM64SysRegField *field = g_new0(ARM64SysRegField, 1); ++ ++ field->name = name; ++ field->lower = min; ++ field->upper = max; ++ field->index = reg->index; ++ ++ reg->fields = g_list_append(reg->fields, field); ++ return reg->fields; ++} ++ ++static inline ARM64SysReg *arm64_sysreg_get(ARMIDRegisterIdx index) ++{ ++ ARM64SysReg *reg = &arm64_id_regs[index]; ++ ++ reg->index = index; ++ reg->sysreg = id_register_sysreg[index]; ++ return reg; ++} ++ ++#endif +diff --git a/target/arm/cpu-sysreg-properties.c b/target/arm/cpu-sysreg-properties.c +new file mode 100644 +index 0000000000..8b7ef5badf +--- /dev/null ++++ b/target/arm/cpu-sysreg-properties.c +@@ -0,0 +1,41 @@ ++/* ++ * QEMU ARM CPU SYSREG PROPERTIES ++ * to be generated from linux sysreg ++ * ++ * Copyright (c) Red Hat, Inc. 2024 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see ++ * ++ */ ++ ++#include "cpu-custom.h" ++ ++ARM64SysReg arm64_id_regs[NUM_ID_IDX]; ++ ++void initialize_cpu_sysreg_properties(void) ++{ ++ memset(arm64_id_regs, 0, sizeof(ARM64SysReg) * NUM_ID_IDX); ++ /* CTR_EL0 */ ++ ARM64SysReg *CTR_EL0 = arm64_sysreg_get(CTR_EL0_IDX); ++ CTR_EL0->name = "CTR_EL0"; ++ arm64_sysreg_add_field(CTR_EL0, "TminLine", 32, 37); ++ arm64_sysreg_add_field(CTR_EL0, "DIC", 29, 29); ++ arm64_sysreg_add_field(CTR_EL0, "IDC", 28, 28); ++ arm64_sysreg_add_field(CTR_EL0, "CWG", 24, 27); ++ arm64_sysreg_add_field(CTR_EL0, "ERG", 20, 23); ++ arm64_sysreg_add_field(CTR_EL0, "DminLine", 16, 19); ++ arm64_sysreg_add_field(CTR_EL0, "L1Ip", 14, 15); ++ arm64_sysreg_add_field(CTR_EL0, "IminLine", 0, 3); ++} ++ +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 0942bb7a60..5ad6f77417 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -34,6 +34,7 @@ + #include "internals.h" + #include "cpu-features.h" + #include "cpregs.h" ++#include "cpu-custom.h" + + /* convert between _IDX and SYS_ */ + #define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \ +@@ -1071,6 +1072,7 @@ static void aarch64_cpu_register_types(void) + { + size_t i; + ++ initialize_cpu_sysreg_properties(); + type_register_static(&aarch64_cpu_type_info); + + for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { +diff --git a/target/arm/meson.build b/target/arm/meson.build +index 7973b35cca..963ad9592b 100644 +--- a/target/arm/meson.build ++++ b/target/arm/meson.build +@@ -15,6 +15,7 @@ arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c', 'kvm-tmm.c'), + arm_ss.add(when: 'TARGET_AARCH64', if_true: files( + 'cpu64.c', + 'gdbstub64.c', ++ 'cpu-sysreg-properties.c', + )) + + arm_system_ss = ss.source_set() +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Add-sysreg-definitions-in-cpu-sysregs.h.patch b/arm-cpu-Add-sysreg-definitions-in-cpu-sysregs.h.patch new file mode 100644 index 00000000..97fd74bc --- /dev/null +++ b/arm-cpu-Add-sysreg-definitions-in-cpu-sysregs.h.patch @@ -0,0 +1,229 @@ +From 9f21bf95b285da235b3bba67a3d96f180068eaeb Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 01/26] arm/cpu: Add sysreg definitions in cpu-sysregs.h + +This new header contains macros that define aarch64 registers. +In a subsequent patch, this will be replaced by a more exhaustive +version that will be generated from linux arch/arm64/tools/sysreg +file. Those macros are sufficient to migrate the storage of those +ID regs from named fields in isar struct to an array cell. + +[CH: reworked to use different structures] +[CH: moved accessors from the patches first using them to here, + dropped interaction with writable registers, which will happen + later] +[CH: use DEF magic suggested by rth] +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-sysregs.h | 42 +++++++++++++++++++++++++++++++ + target/arm/cpu-sysregs.h.inc | 36 ++++++++++++++++++++++++++ + target/arm/cpu.h | 49 ++++++++++++++++++++++++++++++++++++ + target/arm/cpu64.c | 22 ++++++++++++++++ + 4 files changed, 149 insertions(+) + create mode 100644 target/arm/cpu-sysregs.h + create mode 100644 target/arm/cpu-sysregs.h.inc + +diff --git a/target/arm/cpu-sysregs.h b/target/arm/cpu-sysregs.h +new file mode 100644 +index 0000000000..7877a3b06a +--- /dev/null ++++ b/target/arm/cpu-sysregs.h +@@ -0,0 +1,42 @@ ++/* ++ * Definitions for Arm ID system registers ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++#ifndef ARM_CPU_SYSREGS_H ++#define ARM_CPU_SYSREGS_H ++ ++/* ++ * Following is similar to the coprocessor regs encodings, but with an argument ++ * ordering that matches the ARM ARM. We also reuse the various CP_REG_ defines ++ * that actually are the same as the equivalent KVM_REG_ values. ++ */ ++#define ENCODE_ID_REG(op0, op1, crn, crm, op2) \ ++ (((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \ ++ ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \ ++ ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \ ++ ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \ ++ ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT)) ++ ++#define DEF(NAME, OP0, OP1, CRN, CRM, OP2) NAME##_IDX, ++ ++typedef enum ARMIDRegisterIdx { ++#include "cpu-sysregs.h.inc" ++ NUM_ID_IDX, ++} ARMIDRegisterIdx; ++ ++#undef DEF ++#define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \ ++ SYS_##NAME = ENCODE_ID_REG(OP0, OP1, CRN, CRM, OP2), ++ ++typedef enum ARMSysRegs { ++#include "cpu-sysregs.h.inc" ++} ARMSysRegs; ++ ++#undef DEF ++ ++extern const uint32_t id_register_sysreg[NUM_ID_IDX]; ++ ++int get_sysreg_idx(ARMSysRegs sysreg); ++ ++#endif /* ARM_CPU_SYSREGS_H */ +diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc +new file mode 100644 +index 0000000000..cb99286f70 +--- /dev/null ++++ b/target/arm/cpu-sysregs.h.inc +@@ -0,0 +1,36 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++DEF(ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) ++DEF(ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) ++DEF(ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5) ++DEF(ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) ++DEF(ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) ++DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) ++DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1) ++DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2) ++DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0) ++DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1) ++DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2) ++DEF(ID_AA64MMFR3_EL1, 3, 0, 0, 7, 3) ++DEF(ID_PFR0_EL1, 3, 0, 0, 1, 0) ++DEF(ID_PFR1_EL1, 3, 0, 0, 1, 1) ++DEF(ID_DFR0_EL1, 3, 0, 0, 1, 2) ++DEF(ID_MMFR0_EL1, 3, 0, 0, 1, 4) ++DEF(ID_MMFR1_EL1, 3, 0, 0, 1, 5) ++DEF(ID_MMFR2_EL1, 3, 0, 0, 1, 6) ++DEF(ID_MMFR3_EL1, 3, 0, 0, 1, 7) ++DEF(ID_ISAR0_EL1, 3, 0, 0, 2, 0) ++DEF(ID_ISAR1_EL1, 3, 0, 0, 2, 1) ++DEF(ID_ISAR2_EL1, 3, 0, 0, 2, 2) ++DEF(ID_ISAR3_EL1, 3, 0, 0, 2, 3) ++DEF(ID_ISAR4_EL1, 3, 0, 0, 2, 4) ++DEF(ID_ISAR5_EL1, 3, 0, 0, 2, 5) ++DEF(ID_MMFR4_EL1, 3, 0, 0, 2, 6) ++DEF(ID_ISAR6_EL1, 3, 0, 0, 2, 7) ++DEF(MVFR0_EL1, 3, 0, 0, 3, 0) ++DEF(MVFR1_EL1, 3, 0, 0, 3, 1) ++DEF(MVFR2_EL1, 3, 0, 0, 3, 2) ++DEF(ID_PFR2_EL1, 3, 0, 0, 3, 4) ++DEF(ID_DFR1_EL1, 3, 0, 0, 3, 5) ++DEF(ID_MMFR5_EL1, 3, 0, 0, 3, 6) ++DEF(ID_AA64ZFR0_EL1, 3, 0, 0, 4, 4) ++DEF(CTR_EL0, 3, 3, 0, 0, 1) +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index cb546a93e2..6933b1a73f 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -26,6 +26,7 @@ + #include "cpu-qom.h" + #include "exec/cpu-defs.h" + #include "qapi/qapi-types-common.h" ++#include "target/arm/cpu-sysregs.h" + + /* ARM processors have a weak memory model */ + #define TCG_GUEST_DEFAULT_MO (0) +@@ -845,6 +846,53 @@ typedef struct { + uint32_t map, init, supported; + } ARMVQMap; + ++/* REG is ID_XXX */ ++#define FIELD_DP64_IDREG(ISAR, REG, FIELD, VALUE) \ ++ ({ \ ++ ARMISARegisters *i_ = (ISAR); \ ++ uint64_t regval = i_->idregs[REG ## _EL1_IDX]; \ ++ regval = FIELD_DP64(regval, REG, FIELD, VALUE); \ ++ i_->idregs[REG ## _EL1_IDX] = regval; \ ++ }) ++ ++#define FIELD_DP32_IDREG(ISAR, REG, FIELD, VALUE) \ ++ ({ \ ++ ARMISARegisters *i_ = (ISAR); \ ++ uint64_t regval = i_->idregs[REG ## _EL1_IDX]; \ ++ regval = FIELD_DP32(regval, REG, FIELD, VALUE); \ ++ i_->idregs[REG ## _EL1_IDX] = regval; \ ++ }) ++ ++#define FIELD_EX64_IDREG(ISAR, REG, FIELD) \ ++ ({ \ ++ const ARMISARegisters *i_ = (ISAR); \ ++ FIELD_EX64(i_->idregs[REG ## _EL1_IDX], REG, FIELD); \ ++ }) ++ ++#define FIELD_EX32_IDREG(ISAR, REG, FIELD) \ ++ ({ \ ++ const ARMISARegisters *i_ = (ISAR); \ ++ FIELD_EX32(i_->idregs[REG ## _EL1_IDX], REG, FIELD); \ ++ }) ++ ++#define FIELD_SEX64_IDREG(ISAR, REG, FIELD) \ ++ ({ \ ++ const ARMISARegisters *i_ = (ISAR); \ ++ FIELD_SEX64(i_->idregs[REG ## _EL1_IDX], REG, FIELD); \ ++ }) ++ ++#define SET_IDREG(ISAR, REG, VALUE) \ ++ ({ \ ++ ARMISARegisters *i_ = (ISAR); \ ++ i_->idregs[REG ## _EL1_IDX] = VALUE; \ ++ }) ++ ++#define GET_IDREG(ISAR, REG) \ ++ ({ \ ++ const ARMISARegisters *i_ = (ISAR); \ ++ i_->idregs[REG ## _EL1_IDX]; \ ++ }) ++ + /** + * ARMCPU: + * @env: #CPUARMState +@@ -1047,6 +1095,7 @@ struct ArchCPU { + uint64_t id_aa64zfr0; + uint64_t id_aa64smfr0; + uint64_t reset_pmcr_el0; ++ uint64_t idregs[NUM_ID_IDX]; + } isar; + uint64_t midr; + uint32_t revidr; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 4cf8446b6e..20e49aa72a 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -35,6 +35,28 @@ + #include "cpu-features.h" + #include "cpregs.h" + ++/* convert between _IDX and SYS_ */ ++#define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \ ++ [NAME##_IDX] = SYS_##NAME, ++ ++const uint32_t id_register_sysreg[NUM_ID_IDX] = { ++#include "cpu-sysregs.h.inc" ++}; ++ ++#undef DEF ++#define DEF(NAME, OP0, OP1, CRN, CRM, OP2) \ ++ case SYS_##NAME: return NAME##_IDX; ++ ++int get_sysreg_idx(ARMSysRegs sysreg) ++{ ++ switch (sysreg) { ++#include "cpu-sysregs.h.inc" ++ } ++ g_assert_not_reached(); ++} ++ ++#undef DEF ++ + void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) + { + /* +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Add-sysreg-generation-scripts.patch b/arm-cpu-Add-sysreg-generation-scripts.patch new file mode 100644 index 00000000..1c317cea --- /dev/null +++ b/arm-cpu-Add-sysreg-generation-scripts.patch @@ -0,0 +1,123 @@ +From ce63c58400412a3f206e3bfb085c0a4f9322436f Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 12/26] arm/cpu: Add sysreg generation scripts + +Introduce scripts that automate the generation of system register +definitions from a given linux source tree arch/arm64/tools/sysreg. + +Invocation of +./update-aarch64-sysreg-code.sh $PATH_TO_LINUX_SOURCE_TREE +in scripts directory generates target/arm/cpu-sysregs.h.inc +containing defines for all system registers. + +[CH: update to handle current kernel sysregs structure, and to emit + the re-worked register structures; cpu properties will be added + later] +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + MAINTAINERS | 1 + + scripts/arm-gen-cpu-sysregs-header.awk | 37 ++++++++++++++++++++++++++ + scripts/update-aarch64-sysreg-code.sh | 32 ++++++++++++++++++++++ + 3 files changed, 70 insertions(+) + create mode 100755 scripts/arm-gen-cpu-sysregs-header.awk + create mode 100755 scripts/update-aarch64-sysreg-code.sh + +diff --git a/MAINTAINERS b/MAINTAINERS +index ada87bfa9e..73ae0ba448 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -459,6 +459,7 @@ M: Peter Maydell + L: qemu-arm@nongnu.org + S: Maintained + F: target/arm/kvm.c ++F: scripts/*-sysreg* + + MIPS KVM CPUs + M: Huacai Chen +diff --git a/scripts/arm-gen-cpu-sysregs-header.awk b/scripts/arm-gen-cpu-sysregs-header.awk +new file mode 100755 +index 0000000000..f92bbbafa7 +--- /dev/null ++++ b/scripts/arm-gen-cpu-sysregs-header.awk +@@ -0,0 +1,37 @@ ++#!/bin/awk -f ++# SPDX-License-Identifier: GPL-2.0-or-later ++# arm-gen-cpu-sysregs-header.awk: arm64 sysreg header include generator ++# ++# Usage: awk -f arm-gen-cpu-sysregs-header.awk $LINUX_PATH/arch/arm64/tools/sysreg ++ ++BEGIN { ++ print "/* SPDX-License-Identifier: GPL-2.0-or-later */" ++ print "/* GENERATED FILE, DO NOT EDIT */" ++ print "/* use arm-gen-cpu-sysregs-header.awk to regenerate */" ++} END { ++ print "" ++} ++ ++# skip blank lines and comment lines ++/^$/ { next } ++/^[\t ]*#/ { next } ++ ++/^Sysreg\t/ || /^Sysreg /{ ++ ++ reg = $2 ++ op0 = $3 ++ op1 = $4 ++ crn = $5 ++ crm = $6 ++ op2 = $7 ++ ++ if (op0 == 3 && (op1==0 || op1==1 || op1==3) && crn==0 && (crm>=0 && crm<=7) && (op2>=0 && op2<=7)) { ++ print "DEF("reg", "op0", "op1", "crn", "crm", "op2")" ++ } ++ next ++} ++ ++{ ++ /* skip all other lines */ ++ next ++} +diff --git a/scripts/update-aarch64-sysreg-code.sh b/scripts/update-aarch64-sysreg-code.sh +new file mode 100755 +index 0000000000..7bba0bcd6f +--- /dev/null ++++ b/scripts/update-aarch64-sysreg-code.sh +@@ -0,0 +1,32 @@ ++#!/bin/sh -e ++# ++# SPDX-License-Identifier: GPL-2.0-or-later ++# Update target/arm/cpu-sysregs.h ++# from a linux source tree (arch/arm64/tools/sysreg) ++# ++# Copyright Red Hat, Inc. 2024 ++# ++# Authors: ++# Eric Auger ++# ++ ++scripts="$(dirname "$0")" ++linux="$1" ++output="$2" ++ ++if [ -z "$linux" ] || ! [ -d "$linux" ]; then ++ cat << EOF ++usage: update-aarch64-sysreg-code.sh LINUX_PATH [OUTPUT_PATH] ++ ++LINUX_PATH Linux kernel directory to obtain the register definitions from ++OUTPUT_PATH output directory, usually the qemu source tree (default: $PWD) ++EOF ++ exit 1 ++fi ++ ++if [ -z "$output" ]; then ++ output="$PWD" ++fi ++ ++awk -f $scripts/arm-gen-cpu-sysregs-header.awk \ ++ $linux/arch/arm64/tools/sysreg > $output/target/arm/cpu-sysregs.h.inc +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Add-sysreg-properties-generation.patch b/arm-cpu-Add-sysreg-properties-generation.patch new file mode 100644 index 00000000..96895351 --- /dev/null +++ b/arm-cpu-Add-sysreg-properties-generation.patch @@ -0,0 +1,385 @@ +From 6c5df2e2647b9178b35fa5d39a83d3f44cc41534 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 16/26] arm/cpu: Add sysreg properties generation + +Introduce a script that automates the generation of system register +properties definitions from a given linux source tree +arch/arm64/tools/sysreg. + +Invocation of +./update-aarch64-sysreg-code.sh $PATH_TO_LINUX_SOURCE_TREE +in scripts directory additionally generates +target/arm/cpu-sysreg-properties.c containing definitions for +feature ID registers. + +update-aarch64-sysreg-code.sh additionally calls +gen-cpu-sysreg-properties.awk which is inherited from kernel +arch/arm64/tools/gen-sysreg.awk. All credits to Mark Rutland +the original author of this script. + +[CH: split off from original patch adding both sysreg definitions + and properties] +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + scripts/gen-cpu-sysreg-properties.awk | 325 ++++++++++++++++++++++++++ + scripts/update-aarch64-sysreg-code.sh | 5 +- + 2 files changed, 329 insertions(+), 1 deletion(-) + create mode 100755 scripts/gen-cpu-sysreg-properties.awk + +diff --git a/scripts/gen-cpu-sysreg-properties.awk b/scripts/gen-cpu-sysreg-properties.awk +new file mode 100755 +index 0000000000..da00d377ff +--- /dev/null ++++ b/scripts/gen-cpu-sysreg-properties.awk +@@ -0,0 +1,325 @@ ++#!/bin/awk -f ++# SPDX-License-Identifier: GPL-2.0 ++# gen-cpu-sysreg-properties.awk: arm64 sysreg header generator ++# ++# Usage: awk -f gen-cpu-sysreg-properties.awk $LINUX_PATH/arch/arm64/tools/sysreg ++ ++function block_current() { ++ return __current_block[__current_block_depth]; ++} ++ ++# Log an error and terminate ++function fatal(msg) { ++ print "Error at " NR ": " msg > "/dev/stderr" ++ ++ printf "Current block nesting:" ++ ++ for (i = 0; i <= __current_block_depth; i++) { ++ printf " " __current_block[i] ++ } ++ printf "\n" ++ ++ exit 1 ++} ++ ++# Enter a new block, setting the active block to @block ++function block_push(block) { ++ __current_block[++__current_block_depth] = block ++} ++ ++# Exit a block, setting the active block to the parent block ++function block_pop() { ++ if (__current_block_depth == 0) ++ fatal("error: block_pop() in root block") ++ ++ __current_block_depth--; ++} ++ ++# Sanity check the number of records for a field makes sense. If not, produce ++# an error and terminate. ++function expect_fields(nf) { ++ if (NF != nf) ++ fatal(NF " fields found where " nf " expected") ++} ++ ++# Print a CPP macro definition, padded with spaces so that the macro bodies ++# line up in a column ++function define(name, val) { ++ printf "%-56s%s\n", "#define " name, val ++} ++ ++# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field ++function define_field(reg, field, msb, lsb, idreg) { ++ if (idreg) ++ print " arm64_sysreg_add_field("reg", \""field"\", "lsb", "msb");" ++} ++ ++# Print a field _SIGNED definition for a field ++function define_field_sign(reg, field, sign, idreg) { ++ if (idreg) ++ print " arm64_sysreg_add_field("reg", \""field"\", "lsb", "msb");" ++} ++ ++# Parse a "[:]" string into the global variables @msb and @lsb ++function parse_bitdef(reg, field, bitdef, _bits) ++{ ++ if (bitdef ~ /^[0-9]+$/) { ++ msb = bitdef ++ lsb = bitdef ++ } else if (split(bitdef, _bits, ":") == 2) { ++ msb = _bits[1] ++ lsb = _bits[2] ++ } else { ++ fatal("invalid bit-range definition '" bitdef "'") ++ } ++ ++ ++ if (msb != next_bit) ++ fatal(reg "." field " starts at " msb " not " next_bit) ++ if (63 < msb || msb < 0) ++ fatal(reg "." field " invalid high bit in '" bitdef "'") ++ if (63 < lsb || lsb < 0) ++ fatal(reg "." field " invalid low bit in '" bitdef "'") ++ if (msb < lsb) ++ fatal(reg "." field " invalid bit-range '" bitdef "'") ++ if (low > high) ++ fatal(reg "." field " has invalid range " high "-" low) ++ ++ next_bit = lsb - 1 ++} ++ ++BEGIN { ++ print "#include \"cpu-custom.h\"" ++ print "" ++ print "ARM64SysReg arm64_id_regs[NUM_ID_IDX];" ++ print "" ++ print "void initialize_cpu_sysreg_properties(void)" ++ print "{" ++ print " memset(arm64_id_regs, 0, sizeof(ARM64SysReg) * NUM_ID_IDX);" ++ print "" ++ ++ __current_block_depth = 0 ++ __current_block[__current_block_depth] = "Root" ++} ++ ++END { ++ if (__current_block_depth != 0) ++ fatal("Missing terminator for " block_current() " block") ++ ++ print "}" ++} ++ ++# skip blank lines and comment lines ++/^$/ { next } ++/^[\t ]*#/ { next } ++ ++/^SysregFields/ && block_current() == "Root" { ++ block_push("SysregFields") ++ ++ expect_fields(2) ++ ++ reg = $2 ++ ++ res0 = "UL(0)" ++ res1 = "UL(0)" ++ unkn = "UL(0)" ++ ++ next_bit = 63 ++ ++ next ++} ++ ++/^EndSysregFields/ && block_current() == "SysregFields" { ++ if (next_bit > 0) ++ fatal("Unspecified bits in " reg) ++ ++ reg = null ++ res0 = null ++ res1 = null ++ unkn = null ++ ++ block_pop() ++ next ++} ++ ++/^Sysreg/ && block_current() == "Root" { ++ block_push("Sysreg") ++ ++ expect_fields(7) ++ ++ reg = $2 ++ op0 = $3 ++ op1 = $4 ++ crn = $5 ++ crm = $6 ++ op2 = $7 ++ ++ res0 = "UL(0)" ++ res1 = "UL(0)" ++ unkn = "UL(0)" ++ ++ if (op0 == 3 && (op1<2 || op1==3) && crn==0 && (crm>=0 && crm<=7) && (op2>=0 && op2<=7)) { ++ idreg = 1 ++ } else { ++ idreg = 0 ++ } ++ ++ if (idreg == 1) { ++ print " /* "reg" */" ++ print " ARM64SysReg *"reg" = arm64_sysreg_get("reg"_IDX);" ++ print " "reg"->name = \""reg"\";" ++ } ++ ++ next_bit = 63 ++ ++ next ++} ++ ++/^EndSysreg/ && block_current() == "Sysreg" { ++ if (next_bit > 0) ++ fatal("Unspecified bits in " reg) ++ ++ reg = null ++ op0 = null ++ op1 = null ++ crn = null ++ crm = null ++ op2 = null ++ res0 = null ++ res1 = null ++ unkn = null ++ ++ if (idreg==1) ++ print "" ++ block_pop() ++ next ++} ++ ++# Currently this is effectivey a comment, in future we may want to emit ++# defines for the fields. ++(/^Fields/ || /^Mapping/) && block_current() == "Sysreg" { ++ expect_fields(2) ++ ++ if (next_bit != 63) ++ fatal("Some fields already defined for " reg) ++ ++ print "/* For " reg " fields see " $2 " */" ++ print "" ++ ++ next_bit = 0 ++ res0 = null ++ res1 = null ++ unkn = null ++ ++ next ++} ++ ++ ++/^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ expect_fields(2) ++ parse_bitdef(reg, "RES0", $2) ++ field = "RES0_" msb "_" lsb ++ ++ res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")" ++ ++ next ++} ++ ++/^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ expect_fields(2) ++ parse_bitdef(reg, "RES1", $2) ++ field = "RES1_" msb "_" lsb ++ ++ res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")" ++ ++ next ++} ++ ++/^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ expect_fields(2) ++ parse_bitdef(reg, "UNKN", $2) ++ field = "UNKN_" msb "_" lsb ++ ++ unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")" ++ ++ next ++} ++ ++/^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ expect_fields(3) ++ field = $3 ++ parse_bitdef(reg, field, $2) ++ ++ ++ define_field(reg, field, msb, lsb, idreg) ++ ++ next ++} ++ ++/^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ expect_fields(2) ++ parse_bitdef(reg, field, $2) ++ ++ next ++} ++ ++/^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ block_push("Enum") ++ ++ expect_fields(3) ++ field = $3 ++ parse_bitdef(reg, field, $2) ++ ++ define_field(reg, field, msb, lsb, idreg) ++ define_field_sign(reg, field, "true", idreg) ++ ++ next ++} ++ ++/^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ block_push("Enum") ++ ++ expect_fields(3) ++ field = $3 ++ parse_bitdef(reg, field, $2) ++ ++ define_field(reg, field, msb, lsb, idreg) ++ #define_field_sign(reg, field, "false", idreg) ++ ++ next ++} ++ ++/^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { ++ block_push("Enum") ++ ++ expect_fields(3) ++ field = $3 ++ parse_bitdef(reg, field, $2) ++ ++ define_field(reg, field, msb, lsb, idreg) ++ ++ next ++} ++ ++/^EndEnum/ && block_current() == "Enum" { ++ ++ field = null ++ msb = null ++ lsb = null ++ ++ block_pop() ++ next ++} ++ ++/0b[01]+/ && block_current() == "Enum" { ++ expect_fields(2) ++ val = $1 ++ name = $2 ++ ++ next ++} ++ ++# Any lines not handled by previous rules are unexpected ++{ ++ fatal("unhandled statement") ++} +diff --git a/scripts/update-aarch64-sysreg-code.sh b/scripts/update-aarch64-sysreg-code.sh +index 7bba0bcd6f..764c63a9cc 100755 +--- a/scripts/update-aarch64-sysreg-code.sh ++++ b/scripts/update-aarch64-sysreg-code.sh +@@ -1,7 +1,7 @@ + #!/bin/sh -e + # + # SPDX-License-Identifier: GPL-2.0-or-later +-# Update target/arm/cpu-sysregs.h ++# Update target/arm/cpu-sysreg-properties.c and target/arm/cpu-sysregs.h + # from a linux source tree (arch/arm64/tools/sysreg) + # + # Copyright Red Hat, Inc. 2024 +@@ -30,3 +30,6 @@ fi + + awk -f $scripts/arm-gen-cpu-sysregs-header.awk \ + $linux/arch/arm64/tools/sysreg > $output/target/arm/cpu-sysregs.h.inc ++ ++awk -f $scripts/gen-cpu-sysreg-properties.awk \ ++ $linux/arch/arm64/tools/sysreg > $output/target/arm/cpu-sysreg-properties.c +\ No newline at end of file +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64dfr0-1-into-the-idregs-array.patch b/arm-cpu-Store-aa64dfr0-1-into-the-idregs-array.patch new file mode 100644 index 00000000..ec66b599 --- /dev/null +++ b/arm-cpu-Store-aa64dfr0-1-into-the-idregs-array.patch @@ -0,0 +1,430 @@ +From da581f393d2d7379cc0850ed7a9f2a7fa48c8186 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 06/26] arm/cpu: Store aa64dfr0/1 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 16 ++++++++-------- + target/arm/cpu.c | 15 +++++---------- + target/arm/cpu.h | 2 -- + target/arm/cpu64.c | 16 ++++++++-------- + target/arm/helper.c | 4 ++-- + target/arm/hvf/hvf.c | 4 ++-- + target/arm/internals.h | 6 +++--- + target/arm/kvm-rme.c | 5 +++-- + target/arm/kvm.c | 2 +- + target/arm/kvm64.c | 12 +++++------- + target/arm/tcg/cpu64.c | 32 ++++++++++++++++---------------- + 11 files changed, 53 insertions(+), 61 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index aefde4b057..eea88ea681 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -842,30 +842,30 @@ static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) >= 4 && ++ FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_aa64_pmuv3p4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) >= 5 && ++ FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_aa64_pmuv3p5(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 6 && +- FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; ++ return FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) >= 6 && ++ FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) != 0xf; + } + + static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8; ++ return FIELD_EX64_IDREG(id, ID_AA64DFR0, DEBUGVER) >= 8; + } + + static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id) + { +- return FIELD_SEX64(id->id_aa64dfr0, ID_AA64DFR0, DOUBLELOCK) >= 0; ++ return FIELD_SEX64_IDREG(id, ID_AA64DFR0, DOUBLELOCK) >= 0; + } + + static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 7ac964b550..22c3335522 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2180,8 +2180,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu); + #endif + } else { +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMUVER, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64DFR0, PMUVER, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; +@@ -2226,19 +2225,15 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * try to access the non-existent system registers for them. + */ + /* FEAT_SPE (Statistical Profiling Extension) */ +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMSVER, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64DFR0, PMSVER, 0); + /* FEAT_TRBE (Trace Buffer Extension) */ +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, TRACEBUFFER, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEBUFFER, 0); + /* FEAT_TRF (Self-hosted Trace Extension) */ +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, TRACEFILT, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEFILT, 0); + cpu->isar.id_dfr0 = + FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, TRACEFILT, 0); + /* Trace Macrocell system register access */ +- cpu->isar.id_aa64dfr0 = +- FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, TRACEVER, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEVER, 0); + cpu->isar.id_dfr0 = + FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPTRC, 0); + /* Memory mapped trace */ +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 3ef3a6f958..be5587411f 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,8 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64dfr0; +- uint64_t id_aa64dfr1; + uint64_t id_aa64smfr0; + uint64_t reset_pmcr_el0; + uint64_t idregs[NUM_ID_IDX]; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index f980f1efd2..3a7a8861cf 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -602,7 +602,7 @@ static void arm_cpu_get_num_wps(Object *obj, Visitor *v, const char *name, + + val = cpu->num_wps; + if (val == 0) { +- val = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ val = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, WRPS) + 1; + } + + visit_type_uint8(v, name, &val, errp); +@@ -613,7 +613,7 @@ static void arm_cpu_set_num_wps(Object *obj, Visitor *v, const char *name, + { + uint8_t val; + ARMCPU *cpu = ARM_CPU(obj); +- uint8_t max_wps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ uint8_t max_wps = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, WRPS) + 1; + + if (!visit_type_uint8(v, name, &val, errp)) { + return; +@@ -635,7 +635,7 @@ static void arm_cpu_get_num_bps(Object *obj, Visitor *v, const char *name, + + val = cpu->num_bps; + if (val == 0) { +- val = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ val = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, BRPS) + 1; + } + + visit_type_uint8(v, name, &val, errp); +@@ -646,7 +646,7 @@ static void arm_cpu_set_num_bps(Object *obj, Visitor *v, const char *name, + { + uint8_t val; + ARMCPU *cpu = ARM_CPU(obj); +- uint8_t max_bps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ uint8_t max_bps = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, BRPS) + 1; + + if (!visit_type_uint8(v, name, &val, errp)) { + return; +@@ -769,7 +769,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); +- cpu->isar.id_aa64dfr0 = 0x10305106; ++ SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; +@@ -827,7 +827,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); +- cpu->isar.id_aa64dfr0 = 0x10305106; ++ SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(isar, ID_AA64MMFR0, 0x00001122); /* 40 bit physical addr */ + cpu->isar.dbgdidr = 0x3516d000; +@@ -883,7 +883,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x00002222); +- cpu->isar.id_aa64dfr0 = 0x10305106; ++ SET_IDREG(&cpu->isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; +@@ -912,7 +912,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x11001111); +- cpu->isar.id_aa64dfr0 = 0x110305408; ++ SET_IDREG(&cpu->isar, ID_AA64DFR0, 0x110305408); + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x10211120); + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x101125); + } +diff --git a/target/arm/helper.c b/target/arm/helper.c +index a44c13b2b0..46f0b4089b 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8415,12 +8415,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64dfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64DFR0) }, + { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64dfr1 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64DFR1) }, + { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index 7bf5276484..13d72b0bd6 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -844,8 +844,8 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + } regs[] = { + { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] }, + { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] }, +- { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 }, +- { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 }, ++ { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.idregs[ID_AA64DFR0_EL1_IDX] }, ++ { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.idregs[ID_AA64DFR1_EL1_IDX] }, + { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, + { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] }, + /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ +diff --git a/target/arm/internals.h b/target/arm/internals.h +index efc58c7146..dc0c5d9051 100644 +--- a/target/arm/internals.h ++++ b/target/arm/internals.h +@@ -831,7 +831,7 @@ static inline bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) + static inline int arm_num_brps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS) + 1; ++ return FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, BRPS) + 1; + } else { + return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, BRPS) + 1; + } +@@ -845,7 +845,7 @@ static inline int arm_num_brps(ARMCPU *cpu) + static inline int arm_num_wrps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS) + 1; ++ return FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, WRPS) + 1; + } else { + return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, WRPS) + 1; + } +@@ -859,7 +859,7 @@ static inline int arm_num_wrps(ARMCPU *cpu) + static inline int arm_num_ctx_cmps(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { +- return FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS) + 1; ++ return FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, CTX_CMPS) + 1; + } else { + return FIELD_EX32(cpu->isar.dbgdidr, DBGDIDR, CTX_CMPS) + 1; + } +diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c +index 26dda39df6..43ff825425 100644 +--- a/target/arm/kvm-rme.c ++++ b/target/arm/kvm-rme.c +@@ -267,8 +267,9 @@ static int rme_log_realm_create(Error **errp) + params.flags |= REALM_PARAMS_FLAG_SVE; + params.sve_vl = cpu->sve_max_vq - 1; + } +- params.num_bps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); +- params.num_wps = FIELD_EX64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); ++ ++ params.num_bps = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, BRPS); ++ params.num_wps = FIELD_EX64_IDREG(&cpu->isar, ID_AA64DFR0, WRPS); + + switch (rme_guest->measurement_algo) { + case RME_GUEST_MEASUREMENT_ALGORITHM_SHA256: +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 13679c7c18..c6c92c120f 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -696,7 +696,7 @@ static void kvm_arm_configure_aa64dfr0(ARMCPU *cpu) + return; + } + +- newval = cpu->isar.id_aa64dfr0; ++ newval = GET_IDREG(&cpu->isar, ID_AA64DFR0); + if (cpu->num_bps) { + uint64_t ctx_cmps = FIELD_EX64(newval, ID_AA64DFR0, CTX_CMPS); + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 1d0dc2e2b3..e46afd00bb 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -358,10 +358,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_AA64PFR1_EL1_IDX); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, + ARM64_SYS_REG(3, 0, 0, 4, 5)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, +- KVM_REG_ARM_ID_AA64DFR0_EL1); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, +- ARM64_SYS_REG(3, 0, 0, 5, 1)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR0_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR2_EL1_IDX); +@@ -431,10 +429,10 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * We only do this if the CPU supports AArch32 at EL1. + */ + if (FIELD_EX32_IDREG(&ahcf->isar, ID_AA64PFR0, EL1) >= 2) { +- int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); +- int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); ++ int wrps = FIELD_EX64_IDREG(&ahcf->isar, ID_AA64DFR0, WRPS); ++ int brps = FIELD_EX64_IDREG(&ahcf->isar, ID_AA64DFR0, BRPS); + int ctx_cmps = +- FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); ++ FIELD_EX64_IDREG(&ahcf->isar, ID_AA64DFR0, CTX_CMPS); + int version = 6; /* ARMv8 debug architecture */ + bool has_el3 = + !!FIELD_EX32_IDREG(&ahcf->isar, ID_AA64PFR0, EL3); +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 4805af8409..b0a020c14e 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -90,8 +90,8 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(isar, ID_AA64PFR1, 0); +- cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64dfr1 = 0; ++ SET_IDREG(isar, ID_AA64DFR0, 0x10305106); ++ SET_IDREG(isar, ID_AA64DFR1, 0); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(isar, ID_AA64ISAR1, 0); + SET_IDREG(isar, ID_AA64MMFR0, 0x00101122); +@@ -240,7 +240,7 @@ static void aarch64_a55_initfn(Object *obj) + cpu->clidr = 0x82000023; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->dcz_blocksize = 4; /* 64 bytes */ +- cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; ++ SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408ull); + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101122ull); +@@ -327,7 +327,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); +- cpu->isar.id_aa64dfr0 = 0x10305106; ++ SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; +@@ -365,7 +365,7 @@ static void aarch64_a76_initfn(Object *obj) + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; +- cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; ++ SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408ull), + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101122ull); +@@ -435,8 +435,8 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->reset_sctlr = 0x30000180; + SET_IDREG(isar, ID_AA64PFR0, 0x0000000101111111); /* No RAS Extensions */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000000); +- cpu->isar.id_aa64dfr0 = 0x0000000010305408; +- cpu->isar.id_aa64dfr1 = 0x0000000000000000; ++ SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408), ++ SET_IDREG(isar, ID_AA64DFR1, 0x0000000000000000), + cpu->id_aa64afr0 = 0x0000000000000000; + cpu->id_aa64afr1 = 0x0000000000000000; + SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000001122); +@@ -605,7 +605,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->clidr = 0x82000023; + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; +- cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; ++ SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull); + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull); +@@ -679,8 +679,8 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->dcz_blocksize = 4; + cpu->id_aa64afr0 = 0x00000000; + cpu->id_aa64afr1 = 0x00000000; +- cpu->isar.id_aa64dfr0 = 0x000001f210305519ull; +- cpu->isar.id_aa64dfr1 = 0x00000000; ++ SET_IDREG(isar, ID_AA64DFR0, 0x000001f210305519ull), ++ SET_IDREG(isar, ID_AA64DFR1, 0x00000000), + SET_IDREG(isar, ID_AA64ISAR0, 0x1011111110212120ull); /* with FEAT_RNG */ + SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0x0111000001211032ull); + SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x0000000000101125ull); +@@ -922,8 +922,8 @@ static void aarch64_a710_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ +- cpu->isar.id_aa64dfr0 = 0x000011f010305619ull; +- cpu->isar.id_aa64dfr1 = 0; ++ SET_IDREG(isar, ID_AA64DFR0, 0x000011f010305619ull); ++ SET_IDREG(isar, ID_AA64DFR1, 0); + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x0221111110212120ull); /* with Crypto */ +@@ -1020,8 +1020,8 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ +- cpu->isar.id_aa64dfr0 = 0x000011f210305619ull; +- cpu->isar.id_aa64dfr1 = 0; ++ SET_IDREG(isar, ID_AA64DFR0, 0x000011f210305619ull); ++ SET_IDREG(isar, ID_AA64DFR1, 0); + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x1221111110212120ull); /* with Crypto and FEAT_RNG */ +@@ -1223,11 +1223,11 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ZFR0, F64MM, 1); /* FEAT_F64MM */ + SET_IDREG(isar, ID_AA64ZFR0, t); + +- t = cpu->isar.id_aa64dfr0; ++ t = GET_IDREG(isar, ID_AA64DFR0); + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP64(t, ID_AA64DFR0, PMUVER, 6); /* FEAT_PMUv3p5 */ + t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* FEAT_HPMN0 */ +- cpu->isar.id_aa64dfr0 = t; ++ SET_IDREG(isar, ID_AA64DFR0, t); + + t = cpu->isar.id_aa64smfr0; + t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64isar0-aa64zfr0-into-the-idregs-arr.patch b/arm-cpu-Store-aa64isar0-aa64zfr0-into-the-idregs-arr.patch new file mode 100644 index 00000000..19f5a490 --- /dev/null +++ b/arm-cpu-Store-aa64isar0-aa64zfr0-into-the-idregs-arr.patch @@ -0,0 +1,710 @@ +From ed6851b867dd3184eb2f978e83273d41f89784d0 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 02/26] arm/cpu: Store aa64isar0/aa64zfr0 into the idregs + arrays + +Also add kvm accessors for storing host features into idregs. + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 57 ++++++++++++++++++++------------------- + target/arm/cpu-sysregs.h | 4 +++ + target/arm/cpu.c | 9 +++---- + target/arm/cpu.h | 2 -- + target/arm/cpu64.c | 12 +++++---- + target/arm/helper.c | 6 +++-- + target/arm/hvf/hvf.c | 3 ++- + target/arm/kvm.c | 1 + + target/arm/kvm64.c | 29 +++++++++++++++++--- + target/arm/tcg/cpu64.c | 44 ++++++++++++++++++------------ + 10 files changed, 103 insertions(+), 64 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 165a497f7b..b9ece5f03a 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -20,6 +20,7 @@ + #ifndef TARGET_ARM_FEATURES_H + #define TARGET_ARM_FEATURES_H + ++#include "cpu-sysregs.h" + /* + * Naming convention for isar_feature functions: + * Functions which test 32-bit ID registers should have _aa32_ in +@@ -373,92 +374,92 @@ static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id) + */ + static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, AES) != 0; + } + + static inline bool isar_feature_aa64_pmull(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) > 1; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, AES) > 1; + } + + static inline bool isar_feature_aa64_sha1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA1) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SHA1) != 0; + } + + static inline bool isar_feature_aa64_sha256(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SHA2) != 0; + } + + static inline bool isar_feature_aa64_sha512(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) > 1; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SHA2) > 1; + } + + static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, CRC32) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, CRC32) != 0; + } + + static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, ATOMIC) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, ATOMIC) != 0; + } + + static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RDM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RDM) != 0; + } + + static inline bool isar_feature_aa64_sha3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA3) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SHA3) != 0; + } + + static inline bool isar_feature_aa64_sm3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM3) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SM3) != 0; + } + + static inline bool isar_feature_aa64_sm4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM4) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, SM4) != 0; + } + + static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, DP) != 0; + } + + static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, FHM) != 0; + } + + static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TS) != 0; + } + + static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TS) >= 2; + } + + static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, RNDR) != 0; + } + + static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) == 2; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) == 2; + } + + static inline bool isar_feature_aa64_tlbios(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR0, TLB) != 0; + } + + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) +@@ -869,52 +870,52 @@ static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, SVEVER) != 0; + } + + static inline bool isar_feature_aa64_sve2_aes(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, AES) != 0; + } + + static inline bool isar_feature_aa64_sve2_pmull128(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, AES) >= 2; + } + + static inline bool isar_feature_aa64_sve2_bitperm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BITPERM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, BITPERM) != 0; + } + + static inline bool isar_feature_aa64_sve_bf16(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BFLOAT16) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, BFLOAT16) != 0; + } + + static inline bool isar_feature_aa64_sve2_sha3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SHA3) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, SHA3) != 0; + } + + static inline bool isar_feature_aa64_sve2_sm4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SM4) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, SM4) != 0; + } + + static inline bool isar_feature_aa64_sve_i8mm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, I8MM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, I8MM) != 0; + } + + static inline bool isar_feature_aa64_sve_f32mm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F32MM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, F32MM) != 0; + } + + static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ZFR0, F64MM) != 0; + } + + static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id) +diff --git a/target/arm/cpu-sysregs.h b/target/arm/cpu-sysregs.h +index 7877a3b06a..e89a110590 100644 +--- a/target/arm/cpu-sysregs.h ++++ b/target/arm/cpu-sysregs.h +@@ -39,4 +39,8 @@ extern const uint32_t id_register_sysreg[NUM_ID_IDX]; + + int get_sysreg_idx(ARMSysRegs sysreg); + ++#ifdef CONFIG_KVM ++uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg); ++#endif ++ + #endif /* ARM_CPU_SYSREGS_H */ +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 3de2e1a3c3..262c5017d2 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1815,6 +1815,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + { + CPUState *cs = CPU(dev); + ARMCPU *cpu = ARM_CPU(dev); ++ ARMISARegisters *isar = &cpu->isar; + ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev); + CPUARMState *env = &cpu->env; + int pagebits; +@@ -2008,7 +2009,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_NEON); + +- t = cpu->isar.id_aa64isar0; ++ t = GET_IDREG(isar, ID_AA64ISAR0); + t = FIELD_DP64(t, ID_AA64ISAR0, AES, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 0); +@@ -2016,7 +2017,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 0); + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0); +- cpu->isar.id_aa64isar0 = t; ++ SET_IDREG(isar, ID_AA64ISAR0, t); + + t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0); +@@ -2061,9 +2062,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + uint64_t t; + uint32_t u; + +- t = cpu->isar.id_aa64isar0; +- t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0); +- cpu->isar.id_aa64isar0 = t; ++ FIELD_DP64_IDREG(isar, ID_AA64ISAR0, FHM, 0); + + t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0); +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 6933b1a73f..b6e988e570 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,7 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64isar0; + uint64_t id_aa64isar1; + uint64_t id_aa64isar2; + uint64_t id_aa64pfr0; +@@ -1092,7 +1091,6 @@ struct ArchCPU { + uint64_t id_aa64mmfr2; + uint64_t id_aa64dfr0; + uint64_t id_aa64dfr1; +- uint64_t id_aa64zfr0; + uint64_t id_aa64smfr0; + uint64_t reset_pmcr_el0; + uint64_t idregs[NUM_ID_IDX]; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 20e49aa72a..4d31d34591 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -136,7 +136,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) + * SVE is disabled and so are all vector lengths. Good. + * Disable all SVE extensions as well. + */ +- cpu->isar.id_aa64zfr0 = 0; ++ SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0); + return; + } + +@@ -738,6 +738,7 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) + static void aarch64_a57_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a57"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -774,7 +775,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; +@@ -795,6 +796,7 @@ static void aarch64_a57_initfn(Object *obj) + static void aarch64_a53_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a53"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -831,7 +833,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_isar6 = 0; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x00110f13; +@@ -887,7 +889,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; ++ SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; +@@ -916,7 +918,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + cpu->ctr = 0x84448004; + cpu->isar.id_aa64pfr0 = 0x11001111; + cpu->isar.id_aa64dfr0 = 0x110305408; +- cpu->isar.id_aa64isar0 = 0x10211120; ++ SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x10211120); + cpu->isar.id_aa64mmfr0 = 0x101125; + } + +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 0370a739e3..02c0033712 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8202,6 +8202,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) + { + /* Register all the coprocessor registers based on feature bits */ + CPUARMState *env = &cpu->env; ++ ARMISARegisters *isar = &cpu->isar; ++ + if (arm_feature(env, ARM_FEATURE_M)) { + /* M profile has no coprocessor registers */ + return; +@@ -8393,7 +8395,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64zfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64ZFR0)}, + { .name = "ID_AA64SMFR0_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -8453,7 +8455,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64isar0 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)}, + { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index d7cc00a084..3953e6257d 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -18,6 +18,7 @@ + #include "sysemu/hw_accel.h" + #include "hvf_arm.h" + #include "cpregs.h" ++#include "cpu-sysregs.h" + + #include + +@@ -845,7 +846,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 }, + { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 }, + { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 }, +- { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.id_aa64isar0 }, ++ { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, + { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 }, + /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ + { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 }, +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 599c2c2462..13679c7c18 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -23,6 +23,7 @@ + #include "sysemu/kvm_int.h" + #include "kvm_arm.h" + #include "cpu.h" ++#include "cpu-sysregs.h" + #include "trace.h" + #include "internals.h" + #include "hw/pci/pci.h" +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 6a8aad0f06..f47a5be3ac 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -17,6 +17,7 @@ + #include + + #include "qapi/error.h" ++#include "qapi/visitor.h" + #include "cpu.h" + #include "qemu/timer.h" + #include "qemu/error-report.h" +@@ -251,6 +252,27 @@ static bool kvm_arm_pauth_supported(void) + kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_GENERIC)); + } + ++uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg) ++{ ++ return ARM64_SYS_REG((sysreg & CP_REG_ARM64_SYSREG_OP0_MASK) >> CP_REG_ARM64_SYSREG_OP0_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_OP1_MASK) >> CP_REG_ARM64_SYSREG_OP1_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_CRN_MASK) >> CP_REG_ARM64_SYSREG_CRN_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_CRM_MASK) >> CP_REG_ARM64_SYSREG_CRM_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_OP2_MASK) >> CP_REG_ARM64_SYSREG_OP2_SHIFT); ++} ++ ++/* read a sysreg value and store it in the idregs */ ++static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf, ARMIDRegisterIdx index) ++{ ++ uint64_t *reg; ++ int ret; ++ ++ reg = &ahcf->isar.idregs[index]; ++ ret = read_sys_reg64(fd, reg, ++ idregs_sysreg_to_kvm_reg(id_register_sysreg[index])); ++ return ret; ++} ++ + bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + { + /* Identify the feature bits corresponding to the host CPU, and +@@ -310,6 +332,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + + ahcf->target = init.target; + ahcf->dtb_compatible = "arm,arm-v8"; ++ int fd = fdarray[2]; + + err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, + ARM64_SYS_REG(3, 0, 0, 4, 0)); +@@ -341,8 +364,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + KVM_REG_ARM_ID_AA64DFR0_EL1); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, + ARM64_SYS_REG(3, 0, 0, 5, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar0, +- ARM64_SYS_REG(3, 0, 0, 6, 0)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR0_EL1_IDX); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, + ARM64_SYS_REG(3, 0, 0, 6, 1)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar2, +@@ -449,8 +471,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * enabled SVE support, which resulted in an error rather than RAZ. + * So only read the register if we set KVM_ARM_VCPU_SVE above. + */ +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64zfr0, +- ARM64_SYS_REG(3, 0, 0, 4, 4)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64ZFR0_EL1_IDX); + } + } + +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index fcda99e158..2515026ce5 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -58,6 +58,7 @@ static uint64_t make_ccsidr64(unsigned assoc, unsigned linesize, + static void aarch64_a35_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a35"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -91,7 +92,7 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_aa64pfr1 = 0; + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64dfr1 = 0; +- cpu->isar.id_aa64isar0 = 0x00011120; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64isar1 = 0; + cpu->isar.id_aa64mmfr0 = 0x00101122; + cpu->isar.id_aa64mmfr1 = 0; +@@ -226,6 +227,7 @@ static Property arm_cpu_lpa2_property = + static void aarch64_a55_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a55"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -242,7 +244,7 @@ static void aarch64_a55_initfn(Object *obj) + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; +- cpu->isar.id_aa64isar0 = 0x0000100010211120ull; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -294,6 +296,7 @@ static void aarch64_a55_initfn(Object *obj) + static void aarch64_a72_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a72"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -328,7 +331,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_aa64pfr0 = 0x00002222; + cpu->isar.id_aa64dfr0 = 0x10305106; +- cpu->isar.id_aa64isar0 = 0x00011120; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; +@@ -349,6 +352,7 @@ static void aarch64_a72_initfn(Object *obj) + static void aarch64_a76_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a76"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -365,7 +369,7 @@ static void aarch64_a76_initfn(Object *obj) + cpu->ctr = 0x8444C004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; +- cpu->isar.id_aa64isar0 = 0x0000100010211120ull; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -418,6 +422,7 @@ static void aarch64_a76_initfn(Object *obj) + static void aarch64_a64fx_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,a64fx"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -440,9 +445,9 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->isar.id_aa64mmfr0 = 0x0000000000001122; + cpu->isar.id_aa64mmfr1 = 0x0000000011212100; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011; +- cpu->isar.id_aa64isar0 = 0x0000000010211120; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x0000000010211120); + cpu->isar.id_aa64isar1 = 0x0000000000010001; +- cpu->isar.id_aa64zfr0 = 0x0000000000000000; ++ SET_IDREG(isar, ID_AA64ZFR0, 0x0000000000000000); + cpu->clidr = 0x0000000080000023; + cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ + cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */ +@@ -587,6 +592,7 @@ static void define_neoverse_v1_cp_reginfo(ARMCPU *cpu) + static void aarch64_neoverse_n1_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,neoverse-n1"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -603,7 +609,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->ctr = 0x8444c004; + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; +- cpu->isar.id_aa64isar0 = 0x0000100010211120ull; ++ SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + cpu->isar.id_aa64isar1 = 0x0000000000100001ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -658,6 +664,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + static void aarch64_neoverse_v1_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,neoverse-v1"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -677,7 +684,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->id_aa64afr1 = 0x00000000; + cpu->isar.id_aa64dfr0 = 0x000001f210305519ull; + cpu->isar.id_aa64dfr1 = 0x00000000; +- cpu->isar.id_aa64isar0 = 0x1011111110212120ull; /* with FEAT_RNG */ ++ SET_IDREG(isar, ID_AA64ISAR0, 0x1011111110212120ull); /* with FEAT_RNG */ + cpu->isar.id_aa64isar1 = 0x0111000001211032ull; + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -733,7 +740,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + + /* From 3.7.5 ID_AA64ZFR0_EL1 */ +- cpu->isar.id_aa64zfr0 = 0x0000100000100000; ++ SET_IDREG(isar, ID_AA64ZFR0, 0x0000100000100000); + cpu->sve_vq.supported = (1 << 0) /* 128bit */ + | (1 << 1); /* 256bit */ + +@@ -880,6 +887,7 @@ static const ARMCPRegInfo cortex_a710_cp_reginfo[] = { + static void aarch64_a710_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a710"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -916,12 +924,12 @@ static void aarch64_a710_initfn(Object *obj) + cpu->isar.id_pfr2 = 0x00000011; + cpu->isar.id_aa64pfr0 = 0x1201111120111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000221ull; +- cpu->isar.id_aa64zfr0 = 0x0000110100110021ull; /* with Crypto */ ++ SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ + cpu->isar.id_aa64dfr0 = 0x000011f010305619ull; + cpu->isar.id_aa64dfr1 = 0; + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; +- cpu->isar.id_aa64isar0 = 0x0221111110212120ull; /* with Crypto */ ++ SET_IDREG(isar, ID_AA64ISAR0, 0x0221111110212120ull); /* with Crypto */ + cpu->isar.id_aa64isar1 = 0x0010111101211052ull; + cpu->isar.id_aa64mmfr0 = 0x0000022200101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -977,6 +985,7 @@ static const ARMCPRegInfo neoverse_n2_cp_reginfo[] = { + static void aarch64_neoverse_n2_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,neoverse-n2"; + set_feature(&cpu->env, ARM_FEATURE_V8); +@@ -1013,12 +1022,12 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->isar.id_pfr2 = 0x00000011; + cpu->isar.id_aa64pfr0 = 0x1201111120111112ull; /* GIC filled in later */ + cpu->isar.id_aa64pfr1 = 0x0000000000000221ull; +- cpu->isar.id_aa64zfr0 = 0x0000110100110021ull; /* with Crypto */ ++ SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ + cpu->isar.id_aa64dfr0 = 0x000011f210305619ull; + cpu->isar.id_aa64dfr1 = 0; + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; +- cpu->isar.id_aa64isar0 = 0x1221111110212120ull; /* with Crypto and FEAT_RNG */ ++ SET_IDREG(isar, ID_AA64ISAR0, 0x1221111110212120ull); /* with Crypto and FEAT_RNG */ + cpu->isar.id_aa64isar1 = 0x0011111101211052ull; + cpu->isar.id_aa64mmfr0 = 0x0000022200101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +@@ -1074,6 +1083,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + void aarch64_max_tcg_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + uint64_t t; + uint32_t u; + +@@ -1105,7 +1115,7 @@ void aarch64_max_tcg_initfn(Object *obj) + u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0); + cpu->clidr = u; + +- t = cpu->isar.id_aa64isar0; ++ 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 */ +@@ -1120,7 +1130,7 @@ void aarch64_max_tcg_initfn(Object *obj) + 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 */ +- cpu->isar.id_aa64isar0 = t; ++ SET_IDREG(isar, ID_AA64ISAR0, t); + + t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2); /* FEAT_DPB2 */ +@@ -1204,7 +1214,7 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64MMFR2, E0PD, 1); /* FEAT_E0PD */ + cpu->isar.id_aa64mmfr2 = t; + +- t = cpu->isar.id_aa64zfr0; ++ t = GET_IDREG(isar, ID_AA64ZFR0); + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); + t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ + t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */ +@@ -1214,7 +1224,7 @@ void aarch64_max_tcg_initfn(Object *obj) + 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 */ +- cpu->isar.id_aa64zfr0 = t; ++ SET_IDREG(isar, ID_AA64ZFR0, t); + + t = cpu->isar.id_aa64dfr0; + t = FIELD_DP64(t, ID_AA64DFR0, DEBUGVER, 9); /* FEAT_Debugv8p4 */ +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64isar1-2-into-the-idregs-array.patch b/arm-cpu-Store-aa64isar1-2-into-the-idregs-array.patch new file mode 100644 index 00000000..4a8cb23c --- /dev/null +++ b/arm-cpu-Store-aa64isar1-2-into-the-idregs-array.patch @@ -0,0 +1,386 @@ +From 5847c51bd1ace4a48a489ae278807c4b7e3dd7eb Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 03/26] arm/cpu: Store aa64isar1/2 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 36 ++++++++++++++++++------------------ + target/arm/cpu.c | 13 ++++--------- + target/arm/cpu.h | 2 -- + target/arm/cpu64.c | 9 +++++---- + target/arm/helper.c | 4 ++-- + target/arm/hvf/hvf.c | 2 +- + target/arm/kvm64.c | 6 ++---- + target/arm/tcg/cpu64.c | 24 ++++++++++++------------ + 8 files changed, 44 insertions(+), 52 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index b9ece5f03a..06f3666d07 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -464,12 +464,12 @@ static inline bool isar_feature_aa64_tlbios(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, JSCVT) != 0; + } + + static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, FCMA) != 0; + } + + /* +@@ -493,9 +493,9 @@ isar_feature_pauth_feature(const ARMISARegisters *id) + * Architecturally, only one of {APA,API,APA3} may be active (non-zero) + * and the other two must be zero. Thus we may avoid conditionals. + */ +- return (FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) | +- FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, API) | +- FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3)); ++ return (FIELD_EX64_IDREG(id, ID_AA64ISAR1, APA) | ++ FIELD_EX64_IDREG(id, ID_AA64ISAR1, API) | ++ FIELD_EX64_IDREG(id, ID_AA64ISAR2, APA3)); + } + + static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) +@@ -513,7 +513,7 @@ static inline bool isar_feature_aa64_pauth_qarma5(const ARMISARegisters *id) + * Return true if pauth is enabled with the architected QARMA5 algorithm. + * QEMU will always enable or disable both APA and GPA. + */ +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, APA) != 0; + } + + static inline bool isar_feature_aa64_pauth_qarma3(const ARMISARegisters *id) +@@ -522,62 +522,62 @@ static inline bool isar_feature_aa64_pauth_qarma3(const ARMISARegisters *id) + * Return true if pauth is enabled with the architected QARMA3 algorithm. + * QEMU will always enable or disable both APA3 and GPA3. + */ +- return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR2, APA3) != 0; + } + + static inline bool isar_feature_aa64_sb(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, SB) != 0; + } + + static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, SPECRES) != 0; + } + + static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, FRINTTS) != 0; + } + + static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, DPB) != 0; + } + + static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, DPB) >= 2; + } + + static inline bool isar_feature_aa64_bf16(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, BF16) != 0; + } + + static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, LRCPC) != 0; + } + + static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, LRCPC) >= 2; + } + + static inline bool isar_feature_aa64_i8mm(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR1, I8MM) != 0; + } + + static inline bool isar_feature_aa64_hbc(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, BC) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR2, BC) != 0; + } + + static inline bool isar_feature_aa64_mops(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, MOPS); ++ return FIELD_EX64_IDREG(id, ID_AA64ISAR2, MOPS); + } + + static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 262c5017d2..a61f081ec5 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1964,9 +1964,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + uint64_t t; + uint32_t u; + +- t = cpu->isar.id_aa64isar1; +- t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0); +- cpu->isar.id_aa64isar1 = t; ++ FIELD_DP64_IDREG(isar, ID_AA64ISAR1, JSCVT, 0); + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf); +@@ -2019,11 +2017,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0); + SET_IDREG(isar, ID_AA64ISAR0, t); + +- t = cpu->isar.id_aa64isar1; ++ t = GET_IDREG(isar, ID_AA64ISAR1); + t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0); + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 0); + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 0); +- cpu->isar.id_aa64isar1 = t; ++ SET_IDREG(isar, ID_AA64ISAR1, t); + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf); +@@ -2059,14 +2057,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + } + + if (!cpu->has_neon && !cpu->has_vfp) { +- uint64_t t; + uint32_t u; + + FIELD_DP64_IDREG(isar, ID_AA64ISAR0, FHM, 0); + +- t = cpu->isar.id_aa64isar1; +- t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0); +- cpu->isar.id_aa64isar1 = t; ++ FIELD_DP64_IDREG(isar, ID_AA64ISAR1, FRINTTS, 0); + + u = cpu->isar.mvfr0; + u = FIELD_DP32(u, MVFR0, SIMDREG, 0); +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index b6e988e570..fa5a916c92 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,8 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64isar1; +- uint64_t id_aa64isar2; + uint64_t id_aa64pfr0; + uint64_t id_aa64pfr1; + uint64_t id_aa64mmfr0; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 4d31d34591..b646c7bdeb 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -502,6 +502,7 @@ void aarch64_add_sme_properties(Object *obj) + void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) + { + ARMPauthFeature features = cpu_isar_feature(pauth_feature, cpu); ++ ARMISARegisters *isar = &cpu->isar; + uint64_t isar1, isar2; + + /* +@@ -512,13 +513,13 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) + * + * Begin by disabling all fields. + */ +- isar1 = cpu->isar.id_aa64isar1; ++ isar1 = GET_IDREG(isar, ID_AA64ISAR1); + isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, 0); + isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 0); + isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, 0); + isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 0); + +- isar2 = cpu->isar.id_aa64isar2; ++ isar2 = GET_IDREG(isar, ID_AA64ISAR2); + isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0); + isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0); + +@@ -565,8 +566,8 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) + } + } + +- cpu->isar.id_aa64isar1 = isar1; +- cpu->isar.id_aa64isar2 = isar2; ++ SET_IDREG(isar, ID_AA64ISAR1, isar1); ++ SET_IDREG(isar, ID_AA64ISAR2, isar2); + } + + static Property arm_cpu_pauth_property = +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 02c0033712..6758e82440 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8460,12 +8460,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64isar1 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64ISAR1)}, + { .name = "ID_AA64ISAR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64isar2 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64ISAR2)}, + { .name = "ID_AA64ISAR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index 3953e6257d..80c1e36d10 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -847,7 +847,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 }, + { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 }, + { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, +- { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 }, ++ { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] }, + /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ + { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 }, + { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 }, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index f47a5be3ac..5ff37ab24d 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -365,10 +365,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr1, + ARM64_SYS_REG(3, 0, 0, 5, 1)); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR0_EL1_IDX); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1, +- ARM64_SYS_REG(3, 0, 0, 6, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar2, +- ARM64_SYS_REG(3, 0, 0, 6, 2)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR1_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR2_EL1_IDX); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0, + ARM64_SYS_REG(3, 0, 0, 7, 0)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 2515026ce5..a62d735029 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -93,7 +93,7 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64dfr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +- cpu->isar.id_aa64isar1 = 0; ++ SET_IDREG(isar, ID_AA64ISAR1, 0); + cpu->isar.id_aa64mmfr0 = 0x00101122; + cpu->isar.id_aa64mmfr1 = 0; + cpu->clidr = 0x0a200023; +@@ -245,7 +245,7 @@ static void aarch64_a55_initfn(Object *obj) + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); +- cpu->isar.id_aa64isar1 = 0x0000000000100001ull; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +@@ -370,7 +370,7 @@ static void aarch64_a76_initfn(Object *obj) + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); +- cpu->isar.id_aa64isar1 = 0x0000000000100001ull; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +@@ -446,7 +446,7 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->isar.id_aa64mmfr1 = 0x0000000011212100; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000000010211120); +- cpu->isar.id_aa64isar1 = 0x0000000000010001; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000010001); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000000000000000); + cpu->clidr = 0x0000000080000023; + cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */ +@@ -610,7 +610,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->dcz_blocksize = 4; + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); +- cpu->isar.id_aa64isar1 = 0x0000000000100001ull; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +@@ -685,7 +685,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x000001f210305519ull; + cpu->isar.id_aa64dfr1 = 0x00000000; + SET_IDREG(isar, ID_AA64ISAR0, 0x1011111110212120ull); /* with FEAT_RNG */ +- cpu->isar.id_aa64isar1 = 0x0111000001211032ull; ++ SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0x0111000001211032ull); + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0220011102101011ull; +@@ -930,7 +930,7 @@ static void aarch64_a710_initfn(Object *obj) + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x0221111110212120ull); /* with Crypto */ +- cpu->isar.id_aa64isar1 = 0x0010111101211052ull; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0010111101211052ull); + cpu->isar.id_aa64mmfr0 = 0x0000022200101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x1221011110101011ull; +@@ -1028,7 +1028,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->id_aa64afr0 = 0; + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x1221111110212120ull); /* with Crypto and FEAT_RNG */ +- cpu->isar.id_aa64isar1 = 0x0011111101211052ull; ++ SET_IDREG(isar, ID_AA64ISAR1, 0x0011111101211052ull); + cpu->isar.id_aa64mmfr0 = 0x0000022200101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x1221011112101011ull; +@@ -1132,7 +1132,7 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR0, RNDR, 1); /* FEAT_RNG */ + SET_IDREG(isar, ID_AA64ISAR0, t); + +- t = cpu->isar.id_aa64isar1; ++ 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, API, 1); +@@ -1145,12 +1145,12 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */ + t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */ + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */ +- cpu->isar.id_aa64isar1 = t; ++ SET_IDREG(&cpu->isar, ID_AA64ISAR1, t); + +- t = cpu->isar.id_aa64isar2; ++ t = GET_IDREG(isar, ID_AA64ISAR2); + t = FIELD_DP64(t, ID_AA64ISAR2, MOPS, 1); /* FEAT_MOPS */ + t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */ +- cpu->isar.id_aa64isar2 = t; ++ SET_IDREG(&cpu->isar, ID_AA64ISAR2, t); + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */ +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64mmfr0-2-into-the-idregs-array.patch b/arm-cpu-Store-aa64mmfr0-2-into-the-idregs-array.patch new file mode 100644 index 00000000..19a2ca9f --- /dev/null +++ b/arm-cpu-Store-aa64mmfr0-2-into-the-idregs-array.patch @@ -0,0 +1,563 @@ +From a5a09e88e80abbe211001aa0f0d0c35f56c09fb2 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 05/26] arm/cpu: Store aa64mmfr0-2 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 62 +++++++++++++++++++-------------------- + target/arm/cpu.c | 3 +- + target/arm/cpu.h | 3 -- + target/arm/cpu64.c | 12 ++++---- + target/arm/helper.c | 6 ++-- + target/arm/hvf/hvf.c | 8 ++--- + target/arm/kvm64.c | 9 ++---- + target/arm/ptw.c | 6 ++-- + target/arm/tcg/cpu64.c | 60 ++++++++++++++++++------------------- + 9 files changed, 81 insertions(+), 88 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index d3935981d1..aefde4b057 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -682,162 +682,162 @@ static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id) + { +- return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1; ++ return FIELD_SEX64_IDREG(id, ID_AA64MMFR0, TGRAN4) >= 1; + } + + static inline bool isar_feature_aa64_tgran4_2_lpa2(const ARMISARegisters *id) + { +- unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2); ++ unsigned t = FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN4_2); + return t >= 3 || (t == 0 && isar_feature_aa64_tgran4_lpa2(id)); + } + + static inline bool isar_feature_aa64_tgran16_lpa2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN16) >= 2; + } + + static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id) + { +- unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2); ++ unsigned t = FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN16_2); + return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id)); + } + + static inline bool isar_feature_aa64_tgran4(const ARMISARegisters *id) + { +- return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 0; ++ return FIELD_SEX64_IDREG(id, ID_AA64MMFR0, TGRAN4) >= 0; + } + + static inline bool isar_feature_aa64_tgran16(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 1; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN16) >= 1; + } + + static inline bool isar_feature_aa64_tgran64(const ARMISARegisters *id) + { +- return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64) >= 0; ++ return FIELD_SEX64_IDREG(id, ID_AA64MMFR0, TGRAN64) >= 0; + } + + static inline bool isar_feature_aa64_tgran4_2(const ARMISARegisters *id) + { +- unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2); ++ unsigned t = FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN4_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran4(id)); + } + + static inline bool isar_feature_aa64_tgran16_2(const ARMISARegisters *id) + { +- unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2); ++ unsigned t = FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN16_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran16(id)); + } + + static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id) + { +- unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64_2); ++ unsigned t = FIELD_EX64_IDREG(id, ID_AA64MMFR0, TGRAN64_2); + return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id)); + } + + static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR0, FGT) != 0; + } + + static inline bool isar_feature_aa64_vh(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, VH) != 0; + } + + static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, LO) != 0; + } + + static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, PAN) != 0; + } + + static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, PAN) >= 2; + } + + static inline bool isar_feature_aa64_pan3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 3; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, PAN) >= 3; + } + + static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HCX) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, HCX) != 0; + } + + static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, TIDCP1) != 0; + } + + static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, HAFDBS) != 0; + } + + static inline bool isar_feature_aa64_hdbs(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, HAFDBS) >= 2; + } + + static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR1, XNX) != 0; + } + + static inline bool isar_feature_aa64_uao(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, UAO) != 0; + } + + static inline bool isar_feature_aa64_st(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, ST) != 0; + } + + static inline bool isar_feature_aa64_lse2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, AT) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, AT) != 0; + } + + static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, FWB) != 0; + } + + static inline bool isar_feature_aa64_ids(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, IDS) != 0; + } + + static inline bool isar_feature_aa64_half_evt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 1; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, EVT) >= 1; + } + + static inline bool isar_feature_aa64_evt(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, EVT) >= 2; + } + + static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, CCIDX) != 0; + } + + static inline bool isar_feature_aa64_lva(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, VARANGE) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, VARANGE) != 0; + } + + static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64MMFR2, E0PD) != 0; + } + + static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index f708782d00..7ac964b550 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2251,8 +2251,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */ + FIELD_DP64_IDREG(isar, ID_AA64PFR0, MPAM, 0); + /* FEAT_NV (Nested Virtualization) */ +- cpu->isar.id_aa64mmfr2 = +- FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64MMFR2, NV, 0); + } + + /* MPU can be configured out of a PMSA CPU either by setting has-mpu +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 057d669075..3ef3a6f958 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,9 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64mmfr0; +- uint64_t id_aa64mmfr1; +- uint64_t id_aa64mmfr2; + uint64_t id_aa64dfr0; + uint64_t id_aa64dfr1; + uint64_t id_aa64smfr0; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 2c03735a93..f980f1efd2 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -722,12 +722,12 @@ void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) + return; + } + +- t = cpu->isar.id_aa64mmfr0; ++ t = GET_IDREG(&cpu->isar, ID_AA64MMFR0); + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 2); /* 16k pages w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4, 1); /* 4k pages w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 3); /* 16k stage2 w/ LPA2 */ + t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 3); /* 4k stage2 w/ LPA2 */ +- cpu->isar.id_aa64mmfr0 = t; ++ SET_IDREG(&cpu->isar, ID_AA64MMFR0, t); + } + + static void aarch64_a57_initfn(Object *obj) +@@ -771,7 +771,7 @@ static void aarch64_a57_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +- cpu->isar.id_aa64mmfr0 = 0x00001124; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x2; +@@ -829,7 +829,7 @@ static void aarch64_a53_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +- cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ ++ SET_IDREG(isar, ID_AA64MMFR0, 0x00001122); /* 40 bit physical addr */ + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x00110f13; + cpu->isar.dbgdevid1 = 0x1; +@@ -885,7 +885,7 @@ static void aarch64_a72_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x00011120); +- cpu->isar.id_aa64mmfr0 = 0x00001124; ++ SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ +@@ -914,7 +914,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x11001111); + cpu->isar.id_aa64dfr0 = 0x110305408; + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x10211120); +- cpu->isar.id_aa64mmfr0 = 0x101125; ++ SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x101125); + } + + static void aarch64_host_initfn(Object *obj) +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 970cc890c0..a44c13b2b0 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8495,17 +8495,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64mmfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64MMFR0)}, + { .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64mmfr1 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64MMFR1) }, + { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64mmfr2 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64MMFR2) }, + { .name = "ID_AA64MMFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index 9484d057a2..7bf5276484 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -849,9 +849,9 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, + { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.idregs[ID_AA64ISAR1_EL1_IDX] }, + /* Add ID_AA64ISAR2_EL1 here when HVF supports it */ +- { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 }, +- { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 }, +- { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.id_aa64mmfr2 }, ++ { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.idregs[ID_AA64MMFR0_EL1_IDX] }, ++ { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.idregs[ID_AA64MMFR1_EL1_IDX] }, ++ { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.idregs[ID_AA64MMFR2_EL1_IDX] }, + }; + hv_vcpu_t fd; + hv_return_t r = HV_SUCCESS; +@@ -987,7 +987,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) + + /* We're limited to underlying hardware caps, override internal versions */ + ret = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1, +- &arm_cpu->isar.id_aa64mmfr0); ++ &arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]); + assert_hvf_ok(ret); + + return 0; +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index cf61c18bfc..1d0dc2e2b3 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -365,12 +365,9 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR2_EL1_IDX); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0, +- ARM64_SYS_REG(3, 0, 0, 7, 0)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1, +- ARM64_SYS_REG(3, 0, 0, 7, 1)); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr2, +- ARM64_SYS_REG(3, 0, 0, 7, 2)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64MMFR0_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64MMFR1_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64MMFR2_EL1_IDX); + + /* + * Note that if AArch32 support is not present in the host, +diff --git a/target/arm/ptw.c b/target/arm/ptw.c +index 1762b058ae..0fe20ddea6 100644 +--- a/target/arm/ptw.c ++++ b/target/arm/ptw.c +@@ -100,7 +100,7 @@ unsigned int arm_pamax(ARMCPU *cpu) + { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + unsigned int parange = +- FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); ++ FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE); + + /* + * id_aa64mmfr0 is a read-only register so values outside of the +@@ -313,7 +313,7 @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, + * physical address size is invalid. + */ + pps = FIELD_EX64(gpccr, GPCCR, PPS); +- if (pps > FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE)) { ++ if (pps > FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE)) { + goto fault_walk; + } + pps = pamax_map[pps]; +@@ -1651,7 +1651,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, + * ID_AA64MMFR0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. + */ +- ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE); ++ ps = FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE); + ps = MIN(ps, param.ps); + assert(ps < ARRAY_SIZE(pamax_map)); + outputsize = pamax_map[ps]; +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 39e319e62a..4805af8409 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -94,8 +94,8 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_aa64dfr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + SET_IDREG(isar, ID_AA64ISAR1, 0); +- cpu->isar.id_aa64mmfr0 = 0x00101122; +- cpu->isar.id_aa64mmfr1 = 0; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x00101122); ++ SET_IDREG(isar, ID_AA64MMFR1, 0); + cpu->clidr = 0x0a200023; + cpu->dcz_blocksize = 4; + +@@ -243,9 +243,9 @@ static void aarch64_a55_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); +- cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101122ull); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull); + SET_IDREG(isar, ID_AA64PFR0, 0x0000000010112222ull); + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; +@@ -329,7 +329,7 @@ static void aarch64_a72_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +- cpu->isar.id_aa64mmfr0 = 0x00001124; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x00001124); + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x2; +@@ -368,9 +368,9 @@ static void aarch64_a76_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x0000000010305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); +- cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101122ull); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull); + SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; +@@ -439,9 +439,9 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->isar.id_aa64dfr1 = 0x0000000000000000; + cpu->id_aa64afr0 = 0x0000000000000000; + cpu->id_aa64afr1 = 0x0000000000000000; +- cpu->isar.id_aa64mmfr0 = 0x0000000000001122; +- cpu->isar.id_aa64mmfr1 = 0x0000000011212100; +- cpu->isar.id_aa64mmfr2 = 0x0000000000001011; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000001122); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000011212100); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011); + SET_IDREG(isar, ID_AA64ISAR0, 0x0000000010211120); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000010001); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000000000000000); +@@ -608,9 +608,9 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->isar.id_aa64dfr0 = 0x0000000110305408ull; + SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull); + SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull); +- cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull); + SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; +@@ -683,9 +683,9 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->isar.id_aa64dfr1 = 0x00000000; + SET_IDREG(isar, ID_AA64ISAR0, 0x1011111110212120ull); /* with FEAT_RNG */ + SET_IDREG(&cpu->isar, ID_AA64ISAR1, 0x0111000001211032ull); +- cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x0220011102101011ull; ++ SET_IDREG(&cpu->isar, ID_AA64MMFR0, 0x0000000000101125ull); ++ SET_IDREG(&cpu->isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(&cpu->isar, ID_AA64MMFR2, 0x0220011102101011ull); + SET_IDREG(isar, ID_AA64PFR0, 0x1101110120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; +@@ -928,9 +928,9 @@ static void aarch64_a710_initfn(Object *obj) + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x0221111110212120ull); /* with Crypto */ + SET_IDREG(isar, ID_AA64ISAR1, 0x0010111101211052ull); +- cpu->isar.id_aa64mmfr0 = 0x0000022200101122ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x1221011110101011ull; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000022200101122ull); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x1221011110101011ull); + cpu->clidr = 0x0000001482000023ull; + cpu->gm_blocksize = 4; + cpu->ctr = 0x000000049444c004ull; +@@ -1026,9 +1026,9 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->id_aa64afr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x1221111110212120ull); /* with Crypto and FEAT_RNG */ + SET_IDREG(isar, ID_AA64ISAR1, 0x0011111101211052ull); +- cpu->isar.id_aa64mmfr0 = 0x0000022200101125ull; +- cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; +- cpu->isar.id_aa64mmfr2 = 0x1221011112101011ull; ++ SET_IDREG(isar, ID_AA64MMFR0, 0x0000022200101125ull); ++ SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull); ++ SET_IDREG(isar, ID_AA64MMFR2, 0x1221011112101011ull); + cpu->clidr = 0x0000001482000023ull; + cpu->gm_blocksize = 4; + cpu->ctr = 0x00000004b444c004ull; +@@ -1174,16 +1174,16 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ + SET_IDREG(isar, ID_AA64PFR1, t); + +- t = cpu->isar.id_aa64mmfr0; ++ 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 */ +- cpu->isar.id_aa64mmfr0 = t; ++ SET_IDREG(isar, ID_AA64MMFR0, t); + +- t = cpu->isar.id_aa64mmfr1; ++ 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 */ +@@ -1194,9 +1194,9 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 1); /* FEAT_ETS */ + t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1); /* FEAT_HCX */ + t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1); /* FEAT_TIDCP1 */ +- cpu->isar.id_aa64mmfr1 = t; ++ SET_IDREG(isar, ID_AA64MMFR1, t); + +- t = cpu->isar.id_aa64mmfr2; ++ 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 */ +@@ -1209,7 +1209,7 @@ void aarch64_max_tcg_initfn(Object *obj) + 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 */ +- cpu->isar.id_aa64mmfr2 = t; ++ SET_IDREG(isar, ID_AA64MMFR2, t); + + t = GET_IDREG(isar, ID_AA64ZFR0); + t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1); +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64pfr0-1-into-the-idregs-array.patch b/arm-cpu-Store-aa64pfr0-1-into-the-idregs-array.patch new file mode 100644 index 00000000..d7bb6374 --- /dev/null +++ b/arm-cpu-Store-aa64pfr0-1-into-the-idregs-array.patch @@ -0,0 +1,558 @@ +From c88ddc78ac6d5b986d9fe4d58d60fa40a8f4f5a3 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:47 +0800 +Subject: [PATCH 04/26] arm/cpu: Store aa64pfr0/1 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 38 +++++++++++++++---------------- + target/arm/cpu.c | 27 +++++++--------------- + target/arm/cpu.h | 2 -- + target/arm/cpu64.c | 18 +++++---------- + target/arm/helper.c | 6 ++--- + target/arm/hvf/hvf.c | 6 ++--- + target/arm/kvm64.c | 12 +++++----- + target/arm/tcg/cpu64.c | 47 ++++++++++++++++++--------------------- + 8 files changed, 66 insertions(+), 90 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 06f3666d07..d3935981d1 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -583,68 +583,68 @@ static inline bool isar_feature_aa64_mops(const ARMISARegisters *id) + static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id) + { + /* We always set the AdvSIMD and FP fields identically. */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, FP) != 0xf; + } + + static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) + { + /* We always set the AdvSIMD and FP fields identically wrt FP16. */ +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, FP) == 1; + } + + static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL0) >= 2; + } + + static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL1) >= 2; + } + + static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL2) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, EL2) >= 2; + } + + static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, RAS) != 0; + } + + static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, RAS) >= 2; + } + + static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, SVE) != 0; + } + + static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, SEL2) != 0; + } + + static inline bool isar_feature_aa64_rme(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RME) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, RME) != 0; + } + + static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR0, DIT) != 0; + } + + static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) + { +- int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2); ++ int key = FIELD_EX64_IDREG(id, ID_AA64PFR0, CSV2); + if (key >= 2) { + return true; /* FEAT_CSV2_2 */ + } + if (key == 1) { +- key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC); ++ key = FIELD_EX64_IDREG(id, ID_AA64PFR1, CSV2_FRAC); + return key >= 2; /* FEAT_CSV2_1p2 */ + } + return false; +@@ -652,32 +652,32 @@ static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, SSBS) != 0; + } + + static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, BT) != 0; + } + + static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) != 0; + } + + static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 2; + } + + static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 3; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 3; + } + + static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0; ++ return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0; + } + + static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index a61f081ec5..f708782d00 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1961,14 +1961,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + } + + if (!cpu->has_vfp) { +- uint64_t t; + uint32_t u; + + FIELD_DP64_IDREG(isar, ID_AA64ISAR1, JSCVT, 0); + +- t = cpu->isar.id_aa64pfr0; +- t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, FP, 0xf); + + u = cpu->isar.id_isar6; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0); +@@ -2023,9 +2020,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 0); + SET_IDREG(isar, ID_AA64ISAR1, t); + +- t = cpu->isar.id_aa64pfr0; +- t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf); +- cpu->isar.id_aa64pfr0 = t; ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, ADVSIMD, 0xf); + + u = cpu->isar.id_isar5; + u = FIELD_DP32(u, ID_ISAR5, AES, 0); +@@ -2159,12 +2154,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + */ + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); +- cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, +- ID_AA64PFR0, EL3, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL3, 0); + + /* Disable the realm management extension, which requires EL3. */ +- cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, +- ID_AA64PFR0, RME, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, RME, 0); + } + + if (!cpu->has_el2) { +@@ -2199,8 +2192,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * Disable the hypervisor feature bits in the processor feature + * registers if we don't have EL2. + */ +- cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, +- ID_AA64PFR0, EL2, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL2, 0); + cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, + ID_PFR1, VIRTUALIZATION, 0); + } +@@ -2221,8 +2213,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * This matches Cortex-A710 BROADCASTMTE input being LOW. + */ + if (cpu->tag_memory == NULL) { +- cpu->isar.id_aa64pfr1 = +- FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR1, MTE, 1); + } + #endif + } +@@ -2254,13 +2245,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + cpu->isar.id_dfr0 = + FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, MMAPTRC, 0); + /* FEAT_AMU (Activity Monitors Extension) */ +- cpu->isar.id_aa64pfr0 = +- FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, AMU, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, AMU, 0); + cpu->isar.id_pfr0 = + FIELD_DP32(cpu->isar.id_pfr0, ID_PFR0, AMU, 0); + /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */ +- cpu->isar.id_aa64pfr0 = +- FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, MPAM, 0); ++ FIELD_DP64_IDREG(isar, ID_AA64PFR0, MPAM, 0); + /* FEAT_NV (Nested Virtualization) */ + cpu->isar.id_aa64mmfr2 = + FIELD_DP64(cpu->isar.id_aa64mmfr2, ID_AA64MMFR2, NV, 0); +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index fa5a916c92..057d669075 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,8 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64pfr0; +- uint64_t id_aa64pfr1; + uint64_t id_aa64mmfr0; + uint64_t id_aa64mmfr1; + uint64_t id_aa64mmfr2; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index b646c7bdeb..2c03735a93 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -310,16 +310,13 @@ static bool cpu_arm_get_sve(Object *obj, Error **errp) + static void cpu_arm_set_sve(Object *obj, bool value, Error **errp) + { + ARMCPU *cpu = ARM_CPU(obj); +- uint64_t t; + + if (value && kvm_enabled() && !kvm_arm_sve_supported()) { + error_setg(errp, "'sve' feature not supported by KVM on this host"); + return; + } + +- t = cpu->isar.id_aa64pfr0; +- t = FIELD_DP64(t, ID_AA64PFR0, SVE, value); +- cpu->isar.id_aa64pfr0 = t; ++ FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR0, SVE, value); + } + + void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp) +@@ -370,11 +367,8 @@ static bool cpu_arm_get_sme(Object *obj, Error **errp) + static void cpu_arm_set_sme(Object *obj, bool value, Error **errp) + { + ARMCPU *cpu = ARM_CPU(obj); +- uint64_t t; + +- t = cpu->isar.id_aa64pfr1; +- t = FIELD_DP64(t, ID_AA64PFR1, SME, value); +- cpu->isar.id_aa64pfr1 = t; ++ FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR1, SME, value); + } + + static bool cpu_arm_get_sme_fa64(Object *obj, Error **errp) +@@ -774,7 +768,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; +- cpu->isar.id_aa64pfr0 = 0x00002222; ++ SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; +@@ -832,7 +826,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; + cpu->isar.id_isar6 = 0; +- cpu->isar.id_aa64pfr0 = 0x00002222; ++ SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ +@@ -888,7 +882,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_aa64pfr0 = 0x00002222; ++ SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; +@@ -917,7 +911,7 @@ static void aarch64_kunpeng_920_initfn(Object *obj) + + cpu->midr = 0x480fd010; + cpu->ctr = 0x84448004; +- cpu->isar.id_aa64pfr0 = 0x11001111; ++ SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x11001111); + cpu->isar.id_aa64dfr0 = 0x110305408; + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x10211120); + cpu->isar.id_aa64mmfr0 = 0x101125; +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 6758e82440..970cc890c0 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -7279,7 +7279,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) + static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) + { + ARMCPU *cpu = env_archcpu(env); +- uint64_t pfr0 = cpu->isar.id_aa64pfr0; ++ uint64_t pfr0 = GET_IDREG(&cpu->isar, ID_AA64PFR0); + + if (env->gicv3state) { + pfr0 |= 1 << 24; +@@ -8368,7 +8368,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .access = PL1_R, + #ifdef CONFIG_USER_ONLY + .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_aa64pfr0 ++ .resetvalue = GET_IDREG(isar, ID_AA64PFR0) + #else + .type = ARM_CP_NO_RAW, + .accessfn = access_aa64_tid3, +@@ -8380,7 +8380,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64pfr1}, ++ .resetvalue = GET_IDREG(isar, ID_AA64PFR1)}, + { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c +index 80c1e36d10..9484d057a2 100644 +--- a/target/arm/hvf/hvf.c ++++ b/target/arm/hvf/hvf.c +@@ -842,8 +842,8 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + int reg; + uint64_t *val; + } regs[] = { +- { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.id_aa64pfr0 }, +- { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 }, ++ { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] }, ++ { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] }, + { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 }, + { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 }, + { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, +@@ -892,7 +892,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ahcf->reset_sctlr |= 0x00800000; + + /* Make sure we don't advertise AArch32 support for EL0/EL1 */ +- if ((host_isar.id_aa64pfr0 & 0xff) != 0x11) { ++ if ((GET_IDREG(&host_isar, ID_AA64PFR0) & 0xff) != 0x11) { + return false; + } + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 5ff37ab24d..cf61c18bfc 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -334,8 +334,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ahcf->dtb_compatible = "arm,arm-v8"; + int fd = fdarray[2]; + +- err = read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr0, +- ARM64_SYS_REG(3, 0, 0, 4, 0)); ++ err = get_host_cpu_reg(fd, ahcf, ID_AA64PFR0_EL1_IDX); + if (unlikely(err < 0)) { + /* + * Before v4.15, the kernel only exposed a limited number of system +@@ -353,11 +352,10 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * ??? Either of these sounds like too much effort just + * to work around running a modern host kernel. + */ +- ahcf->isar.id_aa64pfr0 = 0x00000011; /* EL1&0, AArch64 only */ ++ SET_IDREG(&ahcf->isar, ID_AA64PFR0, 0x00000011); /* EL1&0, AArch64 only */ + err = 0; + } else { +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64pfr1, +- ARM64_SYS_REG(3, 0, 0, 4, 1)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64PFR1_EL1_IDX); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, + ARM64_SYS_REG(3, 0, 0, 4, 5)); + err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64dfr0, +@@ -435,14 +433,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * arch/arm64/kvm/sys_regs.c:trap_dbgidr() does. + * We only do this if the CPU supports AArch32 at EL1. + */ +- if (FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL1) >= 2) { ++ if (FIELD_EX32_IDREG(&ahcf->isar, ID_AA64PFR0, EL1) >= 2) { + int wrps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, WRPS); + int brps = FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, BRPS); + int ctx_cmps = + FIELD_EX64(ahcf->isar.id_aa64dfr0, ID_AA64DFR0, CTX_CMPS); + int version = 6; /* ARMv8 debug architecture */ + bool has_el3 = +- !!FIELD_EX32(ahcf->isar.id_aa64pfr0, ID_AA64PFR0, EL3); ++ !!FIELD_EX32_IDREG(&ahcf->isar, ID_AA64PFR0, EL3); + uint32_t dbgdidr = 0; + + dbgdidr = FIELD_DP32(dbgdidr, DBGDIDR, WRPS, wrps); +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index a62d735029..39e319e62a 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -88,8 +88,8 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_aa64pfr0 = 0x00002222; +- cpu->isar.id_aa64pfr1 = 0; ++ SET_IDREG(isar, ID_AA64PFR0, 0x00002222); ++ SET_IDREG(isar, ID_AA64PFR1, 0); + cpu->isar.id_aa64dfr0 = 0x10305106; + cpu->isar.id_aa64dfr1 = 0; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +@@ -180,11 +180,8 @@ static bool cpu_arm_get_rme(Object *obj, Error **errp) + static void cpu_arm_set_rme(Object *obj, bool value, Error **errp) + { + ARMCPU *cpu = ARM_CPU(obj); +- uint64_t t; + +- t = cpu->isar.id_aa64pfr0; +- t = FIELD_DP64(t, ID_AA64PFR0, RME, value); +- cpu->isar.id_aa64pfr0 = t; ++ FIELD_DP64_IDREG(&cpu->isar, ID_AA64PFR0, RME, value); + } + + static void cpu_max_set_l0gptsz(Object *obj, Visitor *v, const char *name, +@@ -249,8 +246,8 @@ static void aarch64_a55_initfn(Object *obj) + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +- cpu->isar.id_aa64pfr0 = 0x0000000010112222ull; +- cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x0000000010112222ull); ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; +@@ -329,7 +326,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_isar3 = 0x01112131; + cpu->isar.id_isar4 = 0x00011142; + cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_aa64pfr0 = 0x00002222; ++ SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + cpu->isar.id_aa64dfr0 = 0x10305106; + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); + cpu->isar.id_aa64mmfr0 = 0x00001124; +@@ -374,8 +371,8 @@ static void aarch64_a76_initfn(Object *obj) + cpu->isar.id_aa64mmfr0 = 0x0000000000101122ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +- cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000010ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; +@@ -436,8 +433,8 @@ static void aarch64_a64fx_initfn(Object *obj) + cpu->revidr = 0x00000000; + cpu->ctr = 0x86668006; + cpu->reset_sctlr = 0x30000180; +- cpu->isar.id_aa64pfr0 = 0x0000000101111111; /* No RAS Extensions */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000000; ++ SET_IDREG(isar, ID_AA64PFR0, 0x0000000101111111); /* No RAS Extensions */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000000); + cpu->isar.id_aa64dfr0 = 0x0000000010305408; + cpu->isar.id_aa64dfr1 = 0x0000000000000000; + cpu->id_aa64afr0 = 0x0000000000000000; +@@ -614,8 +611,8 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0000000000001011ull; +- cpu->isar.id_aa64pfr0 = 0x1100000010111112ull; /* GIC filled in later */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; + cpu->isar.id_isar0 = 0x02101110; +@@ -689,8 +686,8 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull; + cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull; + cpu->isar.id_aa64mmfr2 = 0x0220011102101011ull; +- cpu->isar.id_aa64pfr0 = 0x1101110120111112ull; /* GIC filled in later */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000020ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x1101110120111112ull); /* GIC filled in later */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x15011099; + cpu->isar.id_isar0 = 0x02101110; +@@ -922,8 +919,8 @@ static void aarch64_a710_initfn(Object *obj) + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + cpu->isar.id_pfr2 = 0x00000011; +- cpu->isar.id_aa64pfr0 = 0x1201111120111112ull; /* GIC filled in later */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000221ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ + cpu->isar.id_aa64dfr0 = 0x000011f010305619ull; + cpu->isar.id_aa64dfr1 = 0; +@@ -1020,8 +1017,8 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; + cpu->isar.id_pfr2 = 0x00000011; +- cpu->isar.id_aa64pfr0 = 0x1201111120111112ull; /* GIC filled in later */ +- cpu->isar.id_aa64pfr1 = 0x0000000000000221ull; ++ SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ ++ SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ + cpu->isar.id_aa64dfr0 = 0x000011f210305619ull; + cpu->isar.id_aa64dfr1 = 0; +@@ -1152,7 +1149,7 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */ + SET_IDREG(&cpu->isar, ID_AA64ISAR2, t); + +- t = cpu->isar.id_aa64pfr0; ++ 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 */ +@@ -1161,9 +1158,9 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */ + t = FIELD_DP64(t, ID_AA64PFR0, CSV3, 1); /* FEAT_CSV3 */ +- cpu->isar.id_aa64pfr0 = t; ++ SET_IDREG(isar, ID_AA64PFR0, t); + +- t = cpu->isar.id_aa64pfr1; ++ 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 */ + /* +@@ -1175,7 +1172,7 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */ + t = FIELD_DP64(t, ID_AA64PFR1, SME, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */ +- cpu->isar.id_aa64pfr1 = t; ++ SET_IDREG(isar, ID_AA64PFR1, t); + + t = cpu->isar.id_aa64mmfr0; + t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */ +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-aa64smfr0-into-the-idregs-array.patch b/arm-cpu-Store-aa64smfr0-into-the-idregs-array.patch new file mode 100644 index 00000000..379d3def --- /dev/null +++ b/arm-cpu-Store-aa64smfr0-into-the-idregs-array.patch @@ -0,0 +1,133 @@ +From f5ffb70a17959ae7581dd5f28be0992cad029f4c Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 07/26] arm/cpu: Store aa64smfr0 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-features.h | 6 +++--- + target/arm/cpu.h | 1 - + target/arm/cpu64.c | 7 ++----- + target/arm/helper.c | 2 +- + target/arm/kvm64.c | 3 +-- + target/arm/tcg/cpu64.c | 4 ++-- + 6 files changed, 9 insertions(+), 14 deletions(-) + +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index eea88ea681..9e73c90cae 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -920,17 +920,17 @@ static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) + + static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64); ++ return FIELD_EX64_IDREG(id, ID_AA64SMFR0, F64F64); + } + + static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf; ++ return FIELD_EX64_IDREG(id, ID_AA64SMFR0, I16I64) == 0xf; + } + + static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) + { +- return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64); ++ return FIELD_EX64_IDREG(id, ID_AA64SMFR0, FA64); + } + + /* +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index be5587411f..429b36a248 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1082,7 +1082,6 @@ struct ArchCPU { + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +- uint64_t id_aa64smfr0; + uint64_t reset_pmcr_el0; + uint64_t idregs[NUM_ID_IDX]; + } isar; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 3a7a8861cf..df8fc52af5 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -328,7 +328,7 @@ void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp) + + if (vq_map == 0) { + if (!cpu_isar_feature(aa64_sme, cpu)) { +- cpu->isar.id_aa64smfr0 = 0; ++ SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0); + return; + } + +@@ -381,11 +381,8 @@ static bool cpu_arm_get_sme_fa64(Object *obj, Error **errp) + static void cpu_arm_set_sme_fa64(Object *obj, bool value, Error **errp) + { + ARMCPU *cpu = ARM_CPU(obj); +- uint64_t t; + +- t = cpu->isar.id_aa64smfr0; +- t = FIELD_DP64(t, ID_AA64SMFR0, FA64, value); +- cpu->isar.id_aa64smfr0 = t; ++ FIELD_DP64_IDREG(&cpu->isar, ID_AA64SMFR0, FA64, value); + } + + #ifdef CONFIG_USER_ONLY +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 46f0b4089b..0ed6c4a37e 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8400,7 +8400,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_aa64smfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_AA64SMFR0)}, + { .name = "ID_AA64PFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index e46afd00bb..b50af4acd9 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -356,8 +356,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err = 0; + } else { + err |= get_host_cpu_reg(fd, ahcf, ID_AA64PFR1_EL1_IDX); +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64smfr0, +- ARM64_SYS_REG(3, 0, 0, 4, 5)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_AA64SMFR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64ISAR0_EL1_IDX); +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index b0a020c14e..04deff475e 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -1229,7 +1229,7 @@ void aarch64_max_tcg_initfn(Object *obj) + t = FIELD_DP64(t, ID_AA64DFR0, HPMN0, 1); /* FEAT_HPMN0 */ + SET_IDREG(isar, ID_AA64DFR0, t); + +- t = cpu->isar.id_aa64smfr0; ++ t = GET_IDREG(isar, ID_AA64SMFR0); + t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ + t = FIELD_DP64(t, ID_AA64SMFR0, F16F32, 1); /* FEAT_SME */ +@@ -1237,7 +1237,7 @@ void aarch64_max_tcg_initfn(Object *obj) + 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, FA64, 1); /* FEAT_SME_FA64 */ +- cpu->isar.id_aa64smfr0 = t; ++ SET_IDREG(isar, ID_AA64SMFR0, t); + + /* Replicate the same data to the 32-bit id registers. */ + aa32_max_features(cpu); +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-id_dfr0-1-into-the-idregs-array.patch b/arm-cpu-Store-id_dfr0-1-into-the-idregs-array.patch new file mode 100644 index 00000000..85be67b8 --- /dev/null +++ b/arm-cpu-Store-id_dfr0-1-into-the-idregs-array.patch @@ -0,0 +1,468 @@ +From b8c35cd5e70009f38da4b33386ebd52a20be4d70 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 10/26] arm/cpu: Store id_dfr0/1 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + hw/intc/armv7m_nvic.c | 2 +- + target/arm/cpu-features.h | 16 +++++++-------- + target/arm/cpu.c | 13 +++++------- + target/arm/cpu.h | 2 -- + target/arm/cpu64.c | 6 +++--- + target/arm/helper.c | 4 ++-- + target/arm/kvm64.c | 6 ++---- + target/arm/tcg/cpu32.c | 42 +++++++++++++++++++-------------------- + target/arm/tcg/cpu64.c | 16 +++++++-------- + 9 files changed, 49 insertions(+), 58 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index b613b2cafe..d0415d9acd 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1274,7 +1274,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_dfr0; ++ return GET_IDREG(isar, ID_DFR0); + case 0xd4c: /* AFR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index fe73988141..2af4b258de 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -296,22 +296,22 @@ static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id) + { + /* 0xf means "non-standard IMPDEF PMU" */ +- return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && +- FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++ return FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) >= 4 && ++ FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) != 0xf; + } + + static inline bool isar_feature_aa32_pmuv3p4(const ARMISARegisters *id) + { + /* 0xf means "non-standard IMPDEF PMU" */ +- return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 && +- FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++ return FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) >= 5 && ++ FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) != 0xf; + } + + static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id) + { + /* 0xf means "non-standard IMPDEF PMU" */ +- return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 6 && +- FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; ++ return FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) >= 6 && ++ FIELD_EX32_IDREG(id, ID_DFR0, PERFMON) != 0xf; + } + + static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) +@@ -356,12 +356,12 @@ static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_debugv7p1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 5; ++ return FIELD_EX32_IDREG(id, ID_DFR0, COPDBG) >= 5; + } + + static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8; ++ return FIELD_EX32_IDREG(id, ID_DFR0, COPDBG) >= 8; + } + + static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 60654e8630..08d83c4e1a 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2151,7 +2151,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * feature registers as well. + */ + FIELD_DP32_IDREG(isar, ID_PFR1, SECURITY, 0); +- cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); ++ FIELD_DP32_IDREG(isar, ID_DFR0, COPSDBG, 0); + FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL3, 0); + + /* Disable the realm management extension, which requires EL3. */ +@@ -2179,7 +2179,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + #endif + } else { + FIELD_DP64_IDREG(isar, ID_AA64DFR0, PMUVER, 0); +- cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, PERFMON, 0); ++ FIELD_DP32_IDREG(isar, ID_DFR0, PERFMON, 0); + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; + } +@@ -2227,15 +2227,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEBUFFER, 0); + /* FEAT_TRF (Self-hosted Trace Extension) */ + FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEFILT, 0); +- cpu->isar.id_dfr0 = +- FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, TRACEFILT, 0); ++ FIELD_DP32_IDREG(isar, ID_DFR0, TRACEFILT, 0); + /* Trace Macrocell system register access */ + FIELD_DP64_IDREG(isar, ID_AA64DFR0, TRACEVER, 0); +- cpu->isar.id_dfr0 = +- FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPTRC, 0); ++ FIELD_DP32_IDREG(isar, ID_DFR0, COPTRC, 0); + /* Memory mapped trace */ +- cpu->isar.id_dfr0 = +- FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, MMAPTRC, 0); ++ FIELD_DP32_IDREG(isar, ID_DFR0, MMAPTRC, 0); + /* FEAT_AMU (Activity Monitors Extension) */ + FIELD_DP64_IDREG(isar, ID_AA64PFR0, AMU, 0); + FIELD_DP32_IDREG(isar, ID_PFR0, AMU, 0); +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index e9ef2fd484..7b9d2bfda4 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1067,8 +1067,6 @@ struct ArchCPU { + uint32_t mvfr0; + uint32_t mvfr1; + uint32_t mvfr2; +- uint32_t id_dfr0; +- uint32_t id_dfr1; + uint32_t dbgdidr; + uint32_t dbgdevid; + uint32_t dbgdevid1; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 9d8c617aca..7cabc3c646 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -752,7 +752,7 @@ static void aarch64_a57_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -810,7 +810,7 @@ static void aarch64_a53_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -867,7 +867,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000131); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 9895e8e74f..7e4a222d13 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8248,7 +8248,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_dfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_DFR0)}, + { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -8587,7 +8587,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_dfr1 }, ++ .resetvalue = GET_IDREG(isar, ID_DFR1)}, + { .name = "ID_MMFR5", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 74eba5ce47..56d5aa70a4 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -375,8 +375,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + */ + err |= get_host_cpu_reg(fd, ahcf, ID_PFR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_PFR1_EL1_IDX); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, +- ARM64_SYS_REG(3, 0, 0, 1, 2)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_DFR0_EL1_IDX); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, + ARM64_SYS_REG(3, 0, 0, 1, 4)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, +@@ -402,8 +401,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, + ARM64_SYS_REG(3, 0, 0, 3, 2)); + err |= get_host_cpu_reg(fd, ahcf, ID_PFR2_EL1_IDX); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1, +- ARM64_SYS_REG(3, 0, 0, 3, 5)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_DFR1_EL1_IDX); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5, + ARM64_SYS_REG(3, 0, 0, 3, 6)); + +diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c +index 7830189672..e1a7ad654a 100644 +--- a/target/arm/tcg/cpu32.c ++++ b/target/arm/tcg/cpu32.c +@@ -85,15 +85,13 @@ void aa32_max_features(ARMCPU *cpu) + t = FIELD_DP32(t, ID_PFR2, SSBS, 1); /* FEAT_SSBS */ + SET_IDREG(isar, ID_PFR2, t); + +- t = cpu->isar.id_dfr0; ++ t = GET_IDREG(isar, ID_DFR0); + t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP32(t, ID_DFR0, COPSDBG, 9); /* FEAT_Debugv8p4 */ + t = FIELD_DP32(t, ID_DFR0, PERFMON, 6); /* FEAT_PMUv3p5 */ +- cpu->isar.id_dfr0 = t; ++ SET_IDREG(isar, ID_DFR0, t); + +- t = cpu->isar.id_dfr1; +- t = FIELD_DP32(t, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ +- cpu->isar.id_dfr1 = t; ++ FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */ + } + + /* CPU models. These are not needed for the AArch64 linux-user build. */ +@@ -231,7 +229,7 @@ static void arm1136_r2_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + SET_IDREG(isar, ID_PFR0, 0x111); + SET_IDREG(isar, ID_PFR1, 0x1); +- cpu->isar.id_dfr0 = 0x2; ++ SET_IDREG(isar, ID_DFR0, 0x2); + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; +@@ -263,7 +261,7 @@ static void arm1136_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + SET_IDREG(isar, ID_PFR0, 0x111); + SET_IDREG(isar, ID_PFR1, 0x1); +- cpu->isar.id_dfr0 = 0x2; ++ SET_IDREG(isar, ID_DFR0, 0x2); + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; +@@ -296,7 +294,7 @@ static void arm1176_initfn(Object *obj) + cpu->reset_sctlr = 0x00050078; + SET_IDREG(isar, ID_PFR0, 0x111); + SET_IDREG(isar, ID_PFR1, 0x11); +- cpu->isar.id_dfr0 = 0x33; ++ SET_IDREG(isar, ID_DFR0, 0x33); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; +@@ -326,7 +324,7 @@ static void arm11mpcore_initfn(Object *obj) + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ + SET_IDREG(isar, ID_PFR0, 0x111); + SET_IDREG(isar, ID_PFR1, 0x1); +- cpu->isar.id_dfr0 = 0; ++ SET_IDREG(isar, ID_DFR0, 0); + cpu->id_afr0 = 0x2; + cpu->isar.id_mmfr0 = 0x01100103; + cpu->isar.id_mmfr1 = 0x10020302; +@@ -366,7 +364,7 @@ static void cortex_a8_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + SET_IDREG(isar, ID_PFR0, 0x1031); + SET_IDREG(isar, ID_PFR1, 0x11); +- cpu->isar.id_dfr0 = 0x400; ++ SET_IDREG(isar, ID_DFR0, 0x400); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x31100003; + cpu->isar.id_mmfr1 = 0x20000000; +@@ -442,7 +440,7 @@ static void cortex_a9_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + SET_IDREG(isar, ID_PFR0, 0x1031); + SET_IDREG(isar, ID_PFR1, 0x11); +- cpu->isar.id_dfr0 = 0x000; ++ SET_IDREG(isar, ID_DFR0, 0x000); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x00100103; + cpu->isar.id_mmfr1 = 0x20000000; +@@ -507,7 +505,7 @@ static void cortex_a7_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + SET_IDREG(isar, ID_PFR0, 0x00001131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x02010555; ++ SET_IDREG(isar, ID_DFR0, 0x02010555); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -558,7 +556,7 @@ static void cortex_a15_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50078; + SET_IDREG(isar, ID_PFR0, 0x00001131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x02010555; ++ SET_IDREG(isar, ID_DFR0, 0x02010555); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x20000000; +@@ -600,7 +598,7 @@ static void cortex_m0_initfn(Object *obj) + */ + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); +- cpu->isar.id_dfr0 = 0x00100000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -627,7 +625,7 @@ static void cortex_m3_initfn(Object *obj) + cpu->pmsav7_dregion = 8; + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); +- cpu->isar.id_dfr0 = 0x00100000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -658,7 +656,7 @@ static void cortex_m4_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000000; + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); +- cpu->isar.id_dfr0 = 0x00100000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -689,7 +687,7 @@ static void cortex_m7_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000040; + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); +- cpu->isar.id_dfr0 = 0x00100000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00100030; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -722,7 +720,7 @@ static void cortex_m33_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000040; + SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000210); +- cpu->isar.id_dfr0 = 0x00200000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x00200000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00101F40; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -760,7 +758,7 @@ static void cortex_m55_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000040; + SET_IDREG(&cpu->isar, ID_PFR0, 0x20000030); + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000230); +- cpu->isar.id_dfr0 = 0x10200000; ++ SET_IDREG(&cpu->isar, ID_DFR0, 0x10200000); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00111040; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -799,7 +797,7 @@ static void cortex_r5_initfn(Object *obj) + cpu->midr = 0x411fc153; /* r1p3 */ + SET_IDREG(isar, ID_PFR0, 0x0131); + SET_IDREG(isar, ID_PFR1, 0x001); +- cpu->isar.id_dfr0 = 0x010400; ++ SET_IDREG(isar, ID_DFR0, 0x010400); + cpu->id_afr0 = 0x0; + cpu->isar.id_mmfr0 = 0x0210030; + cpu->isar.id_mmfr1 = 0x00000000; +@@ -838,7 +836,7 @@ static void cortex_r52_initfn(Object *obj) + cpu->reset_sctlr = 0x30c50838; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x10111001); +- cpu->isar.id_dfr0 = 0x03010006; ++ SET_IDREG(isar, ID_DFR0, 0x03010006); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00211040; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -1098,7 +1096,7 @@ static void arm_max_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; + cpu->isar.id_mmfr1 = 0x40000000; +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index dbfeeb92a0..6646f265ee 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -76,7 +76,7 @@ static void aarch64_a35_initfn(Object *obj) + cpu->ctr = 0x84448004; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -249,7 +249,7 @@ static void aarch64_a55_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x0000000010112222ull); + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_dfr0 = 0x04010088; ++ SET_IDREG(isar, ID_DFR0, 0x04010088); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -314,7 +314,7 @@ static void aarch64_a72_initfn(Object *obj) + cpu->reset_sctlr = 0x00c50838; + SET_IDREG(isar, ID_PFR0, 0x00000131); + SET_IDREG(isar, ID_PFR1, 0x00011011); +- cpu->isar.id_dfr0 = 0x03010066; ++ SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -374,7 +374,7 @@ static void aarch64_a76_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_dfr0 = 0x04010088; ++ SET_IDREG(isar, ID_DFR0, 0x04010088); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -614,7 +614,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_dfr0 = 0x04010088; ++ SET_IDREG(isar, ID_DFR0, 0x04010088); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -689,7 +689,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR0, 0x1101110120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_dfr0 = 0x15011099; ++ SET_IDREG(isar, ID_DFR0, 0x15011099); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -901,7 +901,7 @@ static void aarch64_a710_initfn(Object *obj) + cpu->revidr = 0; + SET_IDREG(isar, ID_PFR0, 0x21110131); + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ +- cpu->isar.id_dfr0 = 0x16011099; ++ SET_IDREG(isar, ID_DFR0, 0x16011099); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; +@@ -999,7 +999,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->revidr = 0; + SET_IDREG(isar, ID_PFR0, 0x21110131); + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ +- cpu->isar.id_dfr0 = 0x16011099; ++ SET_IDREG(isar, ID_DFR0, 0x16011099); + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-id_isar0-7-into-the-idregs-array.patch b/arm-cpu-Store-id_isar0-7-into-the-idregs-array.patch new file mode 100644 index 00000000..ff8d8468 --- /dev/null +++ b/arm-cpu-Store-id_isar0-7-into-the-idregs-array.patch @@ -0,0 +1,1093 @@ +From 72b11b40f42ed3d919f355d52b1a77c6b530c7d1 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 08/26] arm/cpu: Store id_isar0-7 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + hw/intc/armv7m_nvic.c | 12 +- + target/arm/cpu-features.h | 36 +++--- + target/arm/cpu.c | 24 ++-- + target/arm/cpu.h | 7 -- + target/arm/cpu64.c | 40 +++---- + target/arm/helper.c | 14 +-- + target/arm/kvm64.c | 21 ++-- + target/arm/tcg/cpu32.c | 236 +++++++++++++++++++++----------------- + target/arm/tcg/cpu64.c | 108 ++++++++--------- + 9 files changed, 251 insertions(+), 247 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index 942be7bd11..5f68b0e711 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1303,32 +1303,32 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar0; ++ return GET_IDREG(&cpu->isar, ID_ISAR0); + case 0xd64: /* ISAR1. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar1; ++ return GET_IDREG(&cpu->isar, ID_ISAR1); + case 0xd68: /* ISAR2. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar2; ++ return GET_IDREG(&cpu->isar, ID_ISAR2); + case 0xd6c: /* ISAR3. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar3; ++ return GET_IDREG(&cpu->isar, ID_ISAR3); + case 0xd70: /* ISAR4. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar4; ++ return GET_IDREG(&cpu->isar, ID_ISAR4); + case 0xd74: /* ISAR5. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_isar5; ++ return GET_IDREG(&cpu->isar, ID_ISAR5); + case 0xd78: /* CLIDR */ + return cpu->clidr; + case 0xd7c: /* CTR */ +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 9e73c90cae..25180e4b77 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -42,93 +42,93 @@ + */ + static inline bool isar_feature_aa32_thumb_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR0, DIVIDE) != 0; + } + + static inline bool isar_feature_aa32_arm_div(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1; ++ return FIELD_EX32_IDREG(id, ID_ISAR0, DIVIDE) > 1; + } + + static inline bool isar_feature_aa32_lob(const ARMISARegisters *id) + { + /* (M-profile) low-overhead loops and branch future */ +- return FIELD_EX32(id->id_isar0, ID_ISAR0, CMPBRANCH) >= 3; ++ return FIELD_EX32_IDREG(id, ID_ISAR0, CMPBRANCH) >= 3; + } + + static inline bool isar_feature_aa32_jazelle(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR1, JAZELLE) != 0; + } + + static inline bool isar_feature_aa32_aes(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, AES) != 0; + } + + static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, AES) > 1; + } + + static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, SHA1) != 0; + } + + static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, SHA2) != 0; + } + + static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, CRC32) != 0; + } + + static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, RDM) != 0; + } + + static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR5, VCMA) != 0; + } + + static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, JSCVT) != 0; + } + + static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, DP) != 0; + } + + static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, FHM) != 0; + } + + static inline bool isar_feature_aa32_sb(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, SB) != 0; + } + + static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, SPECRES) != 0; + } + + static inline bool isar_feature_aa32_bf16(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, BF16) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, BF16) != 0; + } + + static inline bool isar_feature_aa32_i8mm(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_isar6, ID_ISAR6, I8MM) != 0; ++ return FIELD_EX32_IDREG(id, ID_ISAR6, I8MM) != 0; + } + + static inline bool isar_feature_aa32_ras(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 22c3335522..7667530e9d 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1967,10 +1967,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + FIELD_DP64_IDREG(isar, ID_AA64PFR0, FP, 0xf); + +- u = cpu->isar.id_isar6; ++ u = GET_IDREG(isar, ID_ISAR6); + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0); + u = FIELD_DP32(u, ID_ISAR6, BF16, 0); +- cpu->isar.id_isar6 = u; ++ SET_IDREG(isar, ID_ISAR6, u); + + u = cpu->isar.mvfr0; + u = FIELD_DP32(u, MVFR0, FPSP, 0); +@@ -2022,20 +2022,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + FIELD_DP64_IDREG(isar, ID_AA64PFR0, ADVSIMD, 0xf); + +- u = cpu->isar.id_isar5; ++ u = GET_IDREG(isar, ID_ISAR5); + u = FIELD_DP32(u, ID_ISAR5, AES, 0); + u = FIELD_DP32(u, ID_ISAR5, SHA1, 0); + u = FIELD_DP32(u, ID_ISAR5, SHA2, 0); + u = FIELD_DP32(u, ID_ISAR5, RDM, 0); + u = FIELD_DP32(u, ID_ISAR5, VCMA, 0); +- cpu->isar.id_isar5 = u; ++ SET_IDREG(isar, ID_ISAR5, u); + +- u = cpu->isar.id_isar6; ++ u = GET_IDREG(isar, ID_ISAR6); + u = FIELD_DP32(u, ID_ISAR6, DP, 0); + u = FIELD_DP32(u, ID_ISAR6, FHM, 0); + u = FIELD_DP32(u, ID_ISAR6, BF16, 0); + u = FIELD_DP32(u, ID_ISAR6, I8MM, 0); +- cpu->isar.id_isar6 = u; ++ SET_IDREG(isar, ID_ISAR6, u); + + if (!arm_feature(env, ARM_FEATURE_M)) { + u = cpu->isar.mvfr1; +@@ -2073,19 +2073,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + + unset_feature(env, ARM_FEATURE_THUMB_DSP); + +- u = cpu->isar.id_isar1; +- u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1); +- cpu->isar.id_isar1 = u; ++ FIELD_DP32_IDREG(isar, ID_ISAR1, EXTEND, 1); + +- u = cpu->isar.id_isar2; ++ u = GET_IDREG(isar, ID_ISAR2); + u = FIELD_DP32(u, ID_ISAR2, MULTU, 1); + u = FIELD_DP32(u, ID_ISAR2, MULTS, 1); +- cpu->isar.id_isar2 = u; ++ SET_IDREG(isar, ID_ISAR2, u); + +- u = cpu->isar.id_isar3; ++ u = GET_IDREG(isar, ID_ISAR3); + u = FIELD_DP32(u, ID_ISAR3, SIMD, 1); + u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0); +- cpu->isar.id_isar3 = u; ++ SET_IDREG(isar, ID_ISAR3, u); + } + + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 429b36a248..4c29657ec7 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1058,13 +1058,6 @@ struct ArchCPU { + * field by reading the value from the KVM vCPU. + */ + struct ARMISARegisters { +- uint32_t id_isar0; +- uint32_t id_isar1; +- uint32_t id_isar2; +- uint32_t id_isar3; +- uint32_t id_isar4; +- uint32_t id_isar5; +- uint32_t id_isar6; + uint32_t id_mmfr0; + uint32_t id_mmfr1; + uint32_t id_mmfr2; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index df8fc52af5..9495bc418e 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -758,13 +758,13 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_isar6 = 0; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x00011121); ++ SET_IDREG(isar, ID_ISAR6, 0); + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +@@ -816,13 +816,13 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_isar6 = 0; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x00011121); ++ SET_IDREG(isar, ID_ISAR6, 0); + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +@@ -873,12 +873,12 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; ++ SET_IDREG(&cpu->isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(&cpu->isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(&cpu->isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(&cpu->isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(&cpu->isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(&cpu->isar, ID_ISAR5, 0x00011121); + SET_IDREG(&cpu->isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(&cpu->isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(&cpu->isar, ID_AA64ISAR0, 0x00011120); +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 0ed6c4a37e..d2d9de8b0b 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8278,32 +8278,32 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar0 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR0)}, + { .name = "ID_ISAR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 1, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar1 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR1)}, + { .name = "ID_ISAR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar2 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR2)}, + { .name = "ID_ISAR3", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar3 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR3) }, + { .name = "ID_ISAR4", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar4 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR4) }, + { .name = "ID_ISAR5", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar5 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR5) }, + { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -8313,7 +8313,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_isar6 }, ++ .resetvalue = GET_IDREG(isar, ID_ISAR6) }, + }; + define_arm_cp_regs(cpu, v6_idregs); + define_arm_cp_regs(cpu, v6_cp_reginfo); +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index b50af4acd9..2e57ba4224 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -387,22 +387,15 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 1, 6)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, + ARM64_SYS_REG(3, 0, 0, 1, 7)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar0, +- ARM64_SYS_REG(3, 0, 0, 2, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar1, +- ARM64_SYS_REG(3, 0, 0, 2, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar2, +- ARM64_SYS_REG(3, 0, 0, 2, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar3, +- ARM64_SYS_REG(3, 0, 0, 2, 3)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar4, +- ARM64_SYS_REG(3, 0, 0, 2, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar5, +- ARM64_SYS_REG(3, 0, 0, 2, 5)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR0_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR1_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR2_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR3_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR4_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR5_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_ISAR6_EL1_IDX); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, + ARM64_SYS_REG(3, 0, 0, 2, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_isar6, +- ARM64_SYS_REG(3, 0, 0, 2, 7)); + + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, + ARM64_SYS_REG(3, 0, 0, 3, 0)); +diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c +index d9e0e2a4dd..dbf2070a81 100644 +--- a/target/arm/tcg/cpu32.c ++++ b/target/arm/tcg/cpu32.c +@@ -26,18 +26,19 @@ + void aa32_max_features(ARMCPU *cpu) + { + uint32_t t; ++ ARMISARegisters *isar = &cpu->isar; + + /* Add additional features supported by QEMU */ +- t = cpu->isar.id_isar5; ++ 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 */ +- cpu->isar.id_isar5 = t; ++ SET_IDREG(isar, ID_ISAR5, t); + +- t = cpu->isar.id_isar6; ++ 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 */ +@@ -45,7 +46,7 @@ void aa32_max_features(ARMCPU *cpu) + 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 */ +- cpu->isar.id_isar6 = t; ++ SET_IDREG(isar, ID_ISAR6, t); + + t = cpu->isar.mvfr1; + t = FIELD_DP32(t, MVFR1, FPHP, 3); /* FEAT_FP16 */ +@@ -141,7 +142,7 @@ static void arm926_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ FIELD_DP32_IDREG(&cpu->isar, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. +@@ -183,7 +184,7 @@ static void arm1026_initfn(Object *obj) + * ARMv5 does not have the ID_ISAR registers, but we can still + * set the field to indicate Jazelle support within QEMU. + */ +- cpu->isar.id_isar1 = FIELD_DP32(cpu->isar.id_isar1, ID_ISAR1, JAZELLE, 1); ++ FIELD_DP32_IDREG(&cpu->isar, ID_ISAR1, JAZELLE, 1); + /* + * Similarly, we need to set MVFR0 fields to enable vfp and short vector + * support even though ARMv5 doesn't have this register. +@@ -207,6 +208,7 @@ static void arm1026_initfn(Object *obj) + static void arm1136_r2_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + /* + * What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an + * older core than plain "arm1136". In particular this does not +@@ -234,17 +236,18 @@ static void arm1136_r2_initfn(Object *obj) + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ SET_IDREG(isar, ID_ISAR0, 0x00140011); ++ SET_IDREG(isar, ID_ISAR1, 0x12002111); ++ SET_IDREG(isar, ID_ISAR2, 0x11231111); ++ SET_IDREG(isar, ID_ISAR3, 0x01102131); ++ SET_IDREG(isar, ID_ISAR4, 0x141); + cpu->reset_auxcr = 7; + } + + static void arm1136_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,arm1136"; + set_feature(&cpu->env, ARM_FEATURE_V6K); +@@ -265,17 +268,18 @@ static void arm1136_initfn(Object *obj) + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222110; +- cpu->isar.id_isar0 = 0x00140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231111; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ SET_IDREG(isar, ID_ISAR0, 0x00140011); ++ SET_IDREG(isar, ID_ISAR1, 0x12002111); ++ SET_IDREG(isar, ID_ISAR2, 0x11231111); ++ SET_IDREG(isar, ID_ISAR3, 0x01102131); ++ SET_IDREG(isar, ID_ISAR4, 0x141); + cpu->reset_auxcr = 7; + } + + static void arm1176_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,arm1176"; + set_feature(&cpu->env, ARM_FEATURE_V6K); +@@ -297,17 +301,18 @@ static void arm1176_initfn(Object *obj) + cpu->isar.id_mmfr0 = 0x01130003; + cpu->isar.id_mmfr1 = 0x10030302; + cpu->isar.id_mmfr2 = 0x01222100; +- cpu->isar.id_isar0 = 0x0140011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11231121; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x01141; ++ SET_IDREG(isar, ID_ISAR0, 0x0140011); ++ SET_IDREG(isar, ID_ISAR1, 0x12002111); ++ SET_IDREG(isar, ID_ISAR2, 0x11231121); ++ SET_IDREG(isar, ID_ISAR3, 0x01102131); ++ SET_IDREG(isar, ID_ISAR4, 0x01141); + cpu->reset_auxcr = 7; + } + + static void arm11mpcore_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,arm11mpcore"; + set_feature(&cpu->env, ARM_FEATURE_V6K); +@@ -326,11 +331,11 @@ static void arm11mpcore_initfn(Object *obj) + cpu->isar.id_mmfr0 = 0x01100103; + cpu->isar.id_mmfr1 = 0x10020302; + cpu->isar.id_mmfr2 = 0x01222000; +- cpu->isar.id_isar0 = 0x00100011; +- cpu->isar.id_isar1 = 0x12002111; +- cpu->isar.id_isar2 = 0x11221011; +- cpu->isar.id_isar3 = 0x01102131; +- cpu->isar.id_isar4 = 0x141; ++ SET_IDREG(isar, ID_ISAR0, 0x00100011); ++ SET_IDREG(isar, ID_ISAR1, 0x12002111); ++ SET_IDREG(isar, ID_ISAR2, 0x11221011); ++ SET_IDREG(isar, ID_ISAR3, 0x01102131); ++ SET_IDREG(isar, ID_ISAR4, 0x141); + cpu->reset_auxcr = 1; + } + +@@ -344,6 +349,7 @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = { + static void cortex_a8_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a8"; + set_feature(&cpu->env, ARM_FEATURE_V7); +@@ -366,11 +372,11 @@ static void cortex_a8_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01202000; + cpu->isar.id_mmfr3 = 0x11; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x12112111; +- cpu->isar.id_isar2 = 0x21232031; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; ++ SET_IDREG(isar, ID_ISAR0, 0x00101111); ++ SET_IDREG(isar, ID_ISAR1, 0x12112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232031); ++ SET_IDREG(isar, ID_ISAR3, 0x11112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00111142); + cpu->isar.dbgdidr = 0x15141000; + cpu->clidr = (1 << 27) | (2 << 24) | 3; + cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */ +@@ -413,6 +419,7 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = { + static void cortex_a9_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a9"; + set_feature(&cpu->env, ARM_FEATURE_V7); +@@ -441,11 +448,11 @@ static void cortex_a9_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01230000; + cpu->isar.id_mmfr3 = 0x00002111; +- cpu->isar.id_isar0 = 0x00101111; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x00111142; ++ SET_IDREG(isar, ID_ISAR0, 0x00101111); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232041); ++ SET_IDREG(isar, ID_ISAR3, 0x11112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00111142); + cpu->isar.dbgdidr = 0x35141000; + cpu->clidr = (1 << 27) | (1 << 24) | 3; + cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */ +@@ -480,6 +487,7 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = { + static void cortex_a7_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a7"; + set_feature(&cpu->env, ARM_FEATURE_V7VE); +@@ -509,11 +517,11 @@ static void cortex_a7_initfn(Object *obj) + * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232041); ++ SET_IDREG(isar, ID_ISAR3, 0x11112131); ++ SET_IDREG(isar, ID_ISAR4, 0x10011142); + cpu->isar.dbgdidr = 0x3515f005; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x1; +@@ -528,6 +536,7 @@ static void cortex_a7_initfn(Object *obj) + static void cortex_a15_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + cpu->dtb_compatible = "arm,cortex-a15"; + set_feature(&cpu->env, ARM_FEATURE_V7VE); +@@ -555,11 +564,11 @@ static void cortex_a15_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x20000000; + cpu->isar.id_mmfr2 = 0x01240000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232041; +- cpu->isar.id_isar3 = 0x11112131; +- cpu->isar.id_isar4 = 0x10011142; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232041); ++ SET_IDREG(isar, ID_ISAR3, 0x11112131); ++ SET_IDREG(isar, ID_ISAR4, 0x10011142); + cpu->isar.dbgdidr = 0x3515f021; + cpu->isar.dbgdevid = 0x01110f13; + cpu->isar.dbgdevid1 = 0x0; +@@ -574,6 +583,8 @@ static void cortex_a15_initfn(Object *obj) + static void cortex_m0_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; ++ + set_feature(&cpu->env, ARM_FEATURE_V6); + set_feature(&cpu->env, ARM_FEATURE_M); + +@@ -595,18 +606,20 @@ static void cortex_m0_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x00000000; + cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01141110); ++ SET_IDREG(isar, ID_ISAR1, 0x02111000); ++ SET_IDREG(isar, ID_ISAR2, 0x21112231); ++ SET_IDREG(isar, ID_ISAR3, 0x01111110); ++ SET_IDREG(isar, ID_ISAR4, 0x01310102); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + } + + static void cortex_m3_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; ++ + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); +@@ -620,18 +633,19 @@ static void cortex_m3_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x00000000; + cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01141110); ++ SET_IDREG(isar, ID_ISAR1, 0x02111000); ++ SET_IDREG(isar, ID_ISAR2, 0x21112231); ++ SET_IDREG(isar, ID_ISAR3, 0x01111110); ++ SET_IDREG(isar, ID_ISAR4, 0x01310102); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + } + + static void cortex_m4_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); +@@ -650,18 +664,19 @@ static void cortex_m4_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x00000000; + cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01141110; +- cpu->isar.id_isar1 = 0x02111000; +- cpu->isar.id_isar2 = 0x21112231; +- cpu->isar.id_isar3 = 0x01111110; +- cpu->isar.id_isar4 = 0x01310102; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01141110); ++ SET_IDREG(isar, ID_ISAR1, 0x02111000); ++ SET_IDREG(isar, ID_ISAR2, 0x21112231); ++ SET_IDREG(isar, ID_ISAR3, 0x01111110); ++ SET_IDREG(isar, ID_ISAR4, 0x01310102); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + } + + static void cortex_m7_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_M); +@@ -680,18 +695,19 @@ static void cortex_m7_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01000000; + cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01101110; +- cpu->isar.id_isar1 = 0x02112000; +- cpu->isar.id_isar2 = 0x20232231; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01101110); ++ SET_IDREG(isar, ID_ISAR1, 0x02112000); ++ SET_IDREG(isar, ID_ISAR2, 0x20232231); ++ SET_IDREG(isar, ID_ISAR3, 0x01111131); ++ SET_IDREG(isar, ID_ISAR4, 0x01310132); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + } + + static void cortex_m33_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_M); +@@ -712,13 +728,13 @@ static void cortex_m33_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01000000; + cpu->isar.id_mmfr3 = 0x00000000; +- cpu->isar.id_isar0 = 0x01101110; +- cpu->isar.id_isar1 = 0x02212000; +- cpu->isar.id_isar2 = 0x20232232; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01101110); ++ SET_IDREG(isar, ID_ISAR1, 0x02212000); ++ SET_IDREG(isar, ID_ISAR2, 0x20232232); ++ SET_IDREG(isar, ID_ISAR3, 0x01111131); ++ SET_IDREG(isar, ID_ISAR4, 0x01310132); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + cpu->clidr = 0x00000000; + cpu->ctr = 0x8000c000; + } +@@ -726,6 +742,7 @@ static void cortex_m33_initfn(Object *obj) + static void cortex_m55_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_V8_1M); +@@ -749,13 +766,13 @@ static void cortex_m55_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01000000; + cpu->isar.id_mmfr3 = 0x00000011; +- cpu->isar.id_isar0 = 0x01103110; +- cpu->isar.id_isar1 = 0x02212000; +- cpu->isar.id_isar2 = 0x20232232; +- cpu->isar.id_isar3 = 0x01111131; +- cpu->isar.id_isar4 = 0x01310132; +- cpu->isar.id_isar5 = 0x00000000; +- cpu->isar.id_isar6 = 0x00000000; ++ SET_IDREG(isar, ID_ISAR0, 0x01103110); ++ SET_IDREG(isar, ID_ISAR1, 0x02212000); ++ SET_IDREG(isar, ID_ISAR2, 0x20232232); ++ SET_IDREG(isar, ID_ISAR3, 0x01111131); ++ SET_IDREG(isar, ID_ISAR4, 0x01310132); ++ SET_IDREG(isar, ID_ISAR5, 0); ++ SET_IDREG(isar, ID_ISAR6, 0); + cpu->clidr = 0x00000000; /* caches not implemented */ + cpu->ctr = 0x8303c003; + } +@@ -773,6 +790,7 @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = { + static void cortex_r5_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V7); + set_feature(&cpu->env, ARM_FEATURE_V7MP); +@@ -787,13 +805,13 @@ static void cortex_r5_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x00000000; + cpu->isar.id_mmfr2 = 0x01200000; + cpu->isar.id_mmfr3 = 0x0211; +- cpu->isar.id_isar0 = 0x02101111; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232141; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x0010142; +- cpu->isar.id_isar5 = 0x0; +- cpu->isar.id_isar6 = 0x0; ++ SET_IDREG(isar, ID_ISAR0, 0x02101111); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232141); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x0010142); ++ SET_IDREG(isar, ID_ISAR5, 0x0); ++ SET_IDREG(isar, ID_ISAR6, 0x0); + cpu->mp_is_up = true; + cpu->pmsav7_dregion = 16; + cpu->isar.reset_pmcr_el0 = 0x41151800; +@@ -803,6 +821,7 @@ static void cortex_r5_initfn(Object *obj) + static void cortex_r52_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_EL2); +@@ -826,12 +845,12 @@ static void cortex_r52_initfn(Object *obj) + cpu->isar.id_mmfr2 = 0x01200000; + cpu->isar.id_mmfr3 = 0xf0102211; + cpu->isar.id_mmfr4 = 0x00000010; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232142; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x00010001; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232142); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x00010001); + cpu->isar.dbgdidr = 0x77168000; + cpu->clidr = (1 << 27) | (1 << 24) | 0x3; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ +@@ -1058,6 +1077,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) + static void arm_max_initfn(Object *obj) + { + ARMCPU *cpu = ARM_CPU(obj); ++ ARMISARegisters *isar = &cpu->isar; + + /* aarch64_a57_initfn, advertising none of the aarch64 features */ + cpu->dtb_compatible = "arm,cortex-a57"; +@@ -1084,13 +1104,13 @@ static void arm_max_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; +- cpu->isar.id_isar6 = 0; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x00011121); ++ SET_IDREG(isar, ID_ISAR6, 0); + cpu->isar.dbgdidr = 0x3516d000; + cpu->isar.dbgdevid = 0x00110f13; + cpu->isar.dbgdevid1 = 0x2; +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 04deff475e..6be05f87f6 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -82,12 +82,12 @@ static void aarch64_a35_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x00011121); + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(isar, ID_AA64PFR1, 0); + SET_IDREG(isar, ID_AA64DFR0, 0x10305106); +@@ -250,13 +250,13 @@ static void aarch64_a55_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x01011121; +- cpu->isar.id_isar6 = 0x00000010; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x01011121); ++ SET_IDREG(isar, ID_ISAR6, 0x00000010); + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; +@@ -320,12 +320,12 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02102211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00011142; +- cpu->isar.id_isar5 = 0x00011121; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00011142); ++ SET_IDREG(isar, ID_ISAR5, 0x00011121); + SET_IDREG(isar, ID_AA64PFR0, 0x00002222); + SET_IDREG(isar, ID_AA64DFR0, 0x10305106); + SET_IDREG(isar, ID_AA64ISAR0, 0x00011120); +@@ -375,13 +375,13 @@ static void aarch64_a76_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x01011121; +- cpu->isar.id_isar6 = 0x00000010; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x01011121); ++ SET_IDREG(isar, ID_ISAR6, 0x00000010); + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; +@@ -615,13 +615,13 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x04010088; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x01011121; +- cpu->isar.id_isar6 = 0x00000010; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x01011121); ++ SET_IDREG(isar, ID_ISAR6, 0x00000010); + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; +@@ -690,13 +690,13 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull); + cpu->id_afr0 = 0x00000000; + cpu->isar.id_dfr0 = 0x15011099; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x11011121; +- cpu->isar.id_isar6 = 0x01100111; ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x11011121); ++ SET_IDREG(isar, ID_ISAR6, 0x01100111); + cpu->isar.id_mmfr0 = 0x10201105; + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; +@@ -907,14 +907,14 @@ static void aarch64_a710_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x11011121; /* with Crypto */ ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x11011121); /* with Crypto */ + cpu->isar.id_mmfr4 = 0x21021110; +- cpu->isar.id_isar6 = 0x01111111; ++ SET_IDREG(isar, ID_ISAR6, 0x01111111); + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +@@ -1005,14 +1005,14 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->isar.id_mmfr1 = 0x40000000; + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_isar0 = 0x02101110; +- cpu->isar.id_isar1 = 0x13112111; +- cpu->isar.id_isar2 = 0x21232042; +- cpu->isar.id_isar3 = 0x01112131; +- cpu->isar.id_isar4 = 0x00010142; +- cpu->isar.id_isar5 = 0x11011121; /* with Crypto */ ++ SET_IDREG(isar, ID_ISAR0, 0x02101110); ++ SET_IDREG(isar, ID_ISAR1, 0x13112111); ++ SET_IDREG(isar, ID_ISAR2, 0x21232042); ++ SET_IDREG(isar, ID_ISAR3, 0x01112131); ++ SET_IDREG(isar, ID_ISAR4, 0x00010142); ++ SET_IDREG(isar, ID_ISAR5, 0x11011121); /* with Crypto */ + cpu->isar.id_mmfr4 = 0x01021110; +- cpu->isar.id_isar6 = 0x01111111; ++ SET_IDREG(isar, ID_ISAR6, 0x01111111); + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-id_mmfr0-5-into-the-idregs-array.patch b/arm-cpu-Store-id_mmfr0-5-into-the-idregs-array.patch new file mode 100644 index 00000000..980da3a3 --- /dev/null +++ b/arm-cpu-Store-id_mmfr0-5-into-the-idregs-array.patch @@ -0,0 +1,703 @@ +From 34b052184fc29389babae9bd30208133a73a51a6 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 11/26] arm/cpu: Store id_mmfr0-5 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + hw/intc/armv7m_nvic.c | 8 +-- + target/arm/cpu-features.h | 18 ++--- + target/arm/cpu.h | 6 -- + target/arm/cpu64.c | 24 +++---- + target/arm/helper.c | 12 ++-- + target/arm/kvm64.c | 18 ++--- + target/arm/tcg/cpu32.c | 142 ++++++++++++++++++-------------------- + target/arm/tcg/cpu64.c | 76 ++++++++++---------- + 8 files changed, 144 insertions(+), 160 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index d0415d9acd..e34ca591f0 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -1284,22 +1284,22 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_mmfr0; ++ return GET_IDREG(isar, ID_MMFR0); + case 0xd54: /* MMFR1. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_mmfr1; ++ return GET_IDREG(isar, ID_MMFR1); + case 0xd58: /* MMFR2. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_mmfr2; ++ return GET_IDREG(isar, ID_MMFR2); + case 0xd5c: /* MMFR3. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_mmfr3; ++ return GET_IDREG(isar, ID_MMFR3); + case 0xd60: /* ISAR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 2af4b258de..46a1016302 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -280,17 +280,17 @@ static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_pxn(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr0, ID_MMFR0, VMSA) >= 4; ++ return FIELD_EX32_IDREG(id, ID_MMFR0, VMSA) >= 4; + } + + static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; ++ return FIELD_EX32_IDREG(id, ID_MMFR3, PAN) != 0; + } + + static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; ++ return FIELD_EX32_IDREG(id, ID_MMFR3, PAN) >= 2; + } + + static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id) +@@ -316,32 +316,32 @@ static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, HPDS) != 0; + } + + static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, AC2) != 0; + } + + static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, CCIDX) != 0; + } + + static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, XNX) != 0; + } + + static inline bool isar_feature_aa32_half_evt(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 1; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, EVT) >= 1; + } + + static inline bool isar_feature_aa32_evt(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 2; ++ return FIELD_EX32_IDREG(id, ID_MMFR4, EVT) >= 2; + } + + static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 7b9d2bfda4..2c8f2ffd45 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1058,12 +1058,6 @@ struct ArchCPU { + * field by reading the value from the KVM vCPU. + */ + struct ARMISARegisters { +- uint32_t id_mmfr0; +- uint32_t id_mmfr1; +- uint32_t id_mmfr2; +- uint32_t id_mmfr3; +- uint32_t id_mmfr4; +- uint32_t id_mmfr5; + uint32_t mvfr0; + uint32_t mvfr1; + uint32_t mvfr2; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 7cabc3c646..0942bb7a60 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -754,10 +754,10 @@ static void aarch64_a57_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10101105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -812,10 +812,10 @@ static void aarch64_a53_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10101105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -869,10 +869,10 @@ static void aarch64_a72_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00011011); + SET_IDREG(&cpu->isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x02102211); + SET_IDREG(&cpu->isar, ID_ISAR0, 0x02101110); + SET_IDREG(&cpu->isar, ID_ISAR1, 0x13112111); + SET_IDREG(&cpu->isar, ID_ISAR2, 0x21232042); +diff --git a/target/arm/helper.c b/target/arm/helper.c +index 7e4a222d13..f50baa0f7b 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -8258,22 +8258,22 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_mmfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR0)}, + { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_mmfr1 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR1)}, + { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_mmfr2 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR2)}, + { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_mmfr3 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR3)}, + { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -8308,7 +8308,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_mmfr4 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR4)}, + { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +@@ -8592,7 +8592,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_mmfr5 }, ++ .resetvalue = GET_IDREG(isar, ID_MMFR5)}, + { .name = "RES_0_C0_C3_7", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 56d5aa70a4..4e184fe1d5 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -376,14 +376,10 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_PFR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_PFR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_DFR0_EL1_IDX); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, +- ARM64_SYS_REG(3, 0, 0, 1, 4)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr1, +- ARM64_SYS_REG(3, 0, 0, 1, 5)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr2, +- ARM64_SYS_REG(3, 0, 0, 1, 6)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr3, +- ARM64_SYS_REG(3, 0, 0, 1, 7)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR0_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR1_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR2_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR3_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR0_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR2_EL1_IDX); +@@ -391,8 +387,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR4_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR5_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR6_EL1_IDX); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr4, +- ARM64_SYS_REG(3, 0, 0, 2, 6)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR4_EL1_IDX); + + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, + ARM64_SYS_REG(3, 0, 0, 3, 0)); +@@ -402,8 +397,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 3, 2)); + err |= get_host_cpu_reg(fd, ahcf, ID_PFR2_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_DFR1_EL1_IDX); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5, +- ARM64_SYS_REG(3, 0, 0, 3, 6)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_MMFR5_EL1_IDX); + + /* + * DBGDIDR is a bit complicated because the kernel doesn't +diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c +index e1a7ad654a..38e516a236 100644 +--- a/target/arm/tcg/cpu32.c ++++ b/target/arm/tcg/cpu32.c +@@ -58,21 +58,17 @@ void aa32_max_features(ARMCPU *cpu) + t = FIELD_DP32(t, MVFR2, FPMISC, 4); /* FP MaxNum */ + cpu->isar.mvfr2 = t; + +- t = cpu->isar.id_mmfr3; +- t = FIELD_DP32(t, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ +- cpu->isar.id_mmfr3 = t; ++ FIELD_DP32_IDREG(isar, ID_MMFR3, PAN, 2); /* FEAT_PAN2 */ + +- t = cpu->isar.id_mmfr4; ++ 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_EVT */ +- cpu->isar.id_mmfr4 = t; ++ SET_IDREG(isar, ID_MMFR4, t); + +- t = cpu->isar.id_mmfr5; +- t = FIELD_DP32(t, ID_MMFR5, ETS, 1); /* FEAT_ETS */ +- cpu->isar.id_mmfr5 = t; ++ FIELD_DP32_IDREG(isar, ID_MMFR5, ETS, 1); /* FEAT_ETS */ + + t = GET_IDREG(isar, ID_PFR0); + t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ +@@ -231,9 +227,9 @@ static void arm1136_r2_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x1); + SET_IDREG(isar, ID_DFR0, 0x2); + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; ++ SET_IDREG(isar, ID_MMFR0, 0x01130003); ++ SET_IDREG(isar, ID_MMFR1, 0x10030302); ++ SET_IDREG(isar, ID_MMFR2, 0x01222110); + SET_IDREG(isar, ID_ISAR0, 0x00140011); + SET_IDREG(isar, ID_ISAR1, 0x12002111); + SET_IDREG(isar, ID_ISAR2, 0x11231111); +@@ -263,9 +259,9 @@ static void arm1136_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x1); + SET_IDREG(isar, ID_DFR0, 0x2); + cpu->id_afr0 = 0x3; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222110; ++ SET_IDREG(isar, ID_MMFR0, 0x01130003); ++ SET_IDREG(isar, ID_MMFR1, 0x10030302); ++ SET_IDREG(isar, ID_MMFR2, 0x01222110); + SET_IDREG(isar, ID_ISAR0, 0x00140011); + SET_IDREG(isar, ID_ISAR1, 0x12002111); + SET_IDREG(isar, ID_ISAR2, 0x11231111); +@@ -296,9 +292,9 @@ static void arm1176_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x11); + SET_IDREG(isar, ID_DFR0, 0x33); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x01130003; +- cpu->isar.id_mmfr1 = 0x10030302; +- cpu->isar.id_mmfr2 = 0x01222100; ++ SET_IDREG(isar, ID_MMFR0, 0x01130003); ++ SET_IDREG(isar, ID_MMFR1, 0x10030302); ++ SET_IDREG(isar, ID_MMFR2, 0x01222100); + SET_IDREG(isar, ID_ISAR0, 0x0140011); + SET_IDREG(isar, ID_ISAR1, 0x12002111); + SET_IDREG(isar, ID_ISAR2, 0x11231121); +@@ -326,9 +322,9 @@ static void arm11mpcore_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x1); + SET_IDREG(isar, ID_DFR0, 0); + cpu->id_afr0 = 0x2; +- cpu->isar.id_mmfr0 = 0x01100103; +- cpu->isar.id_mmfr1 = 0x10020302; +- cpu->isar.id_mmfr2 = 0x01222000; ++ SET_IDREG(isar, ID_MMFR0, 0x01100103); ++ SET_IDREG(isar, ID_MMFR1, 0x10020302); ++ SET_IDREG(isar, ID_MMFR2, 0x01222000); + SET_IDREG(isar, ID_ISAR0, 0x00100011); + SET_IDREG(isar, ID_ISAR1, 0x12002111); + SET_IDREG(isar, ID_ISAR2, 0x11221011); +@@ -366,10 +362,10 @@ static void cortex_a8_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x11); + SET_IDREG(isar, ID_DFR0, 0x400); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x31100003; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01202000; +- cpu->isar.id_mmfr3 = 0x11; ++ SET_IDREG(isar, ID_MMFR0, 0x31100003); ++ SET_IDREG(isar, ID_MMFR1, 0x20000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01202000); ++ SET_IDREG(isar, ID_MMFR3, 0x11); + SET_IDREG(isar, ID_ISAR0, 0x00101111); + SET_IDREG(isar, ID_ISAR1, 0x12112111); + SET_IDREG(isar, ID_ISAR2, 0x21232031); +@@ -442,10 +438,10 @@ static void cortex_a9_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x11); + SET_IDREG(isar, ID_DFR0, 0x000); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x00100103; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01230000; +- cpu->isar.id_mmfr3 = 0x00002111; ++ SET_IDREG(isar, ID_MMFR0, 0x00100103); ++ SET_IDREG(isar, ID_MMFR1, 0x20000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01230000); ++ SET_IDREG(isar, ID_MMFR3, 0x00002111); + SET_IDREG(isar, ID_ISAR0, 0x00101111); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232041); +@@ -507,10 +503,10 @@ static void cortex_a7_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x02010555); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01240000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10101105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01240000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + /* + * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. +@@ -558,10 +554,10 @@ static void cortex_a15_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x02010555); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x20000000; +- cpu->isar.id_mmfr2 = 0x01240000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x20000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01240000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232041); +@@ -600,10 +596,10 @@ static void cortex_m0_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000000); + SET_IDREG(isar, ID_ISAR0, 0x01141110); + SET_IDREG(isar, ID_ISAR1, 0x02111000); + SET_IDREG(isar, ID_ISAR2, 0x21112231); +@@ -627,10 +623,10 @@ static void cortex_m3_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000000); + SET_IDREG(isar, ID_ISAR0, 0x01141110); + SET_IDREG(isar, ID_ISAR1, 0x02111000); + SET_IDREG(isar, ID_ISAR2, 0x21112231); +@@ -658,10 +654,10 @@ static void cortex_m4_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00000030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x00000000; +- cpu->isar.id_mmfr3 = 0x00000000; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000000); + SET_IDREG(isar, ID_ISAR0, 0x01141110); + SET_IDREG(isar, ID_ISAR1, 0x02111000); + SET_IDREG(isar, ID_ISAR2, 0x21112231); +@@ -689,10 +685,10 @@ static void cortex_m7_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + SET_IDREG(&cpu->isar, ID_DFR0, 0x00100000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00100030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000000; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00100030); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x01000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000000); + SET_IDREG(isar, ID_ISAR0, 0x01101110); + SET_IDREG(isar, ID_ISAR1, 0x02112000); + SET_IDREG(isar, ID_ISAR2, 0x20232231); +@@ -722,10 +718,10 @@ static void cortex_m33_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000210); + SET_IDREG(&cpu->isar, ID_DFR0, 0x00200000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00101F40; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000000; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00101F40); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x01000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000000); + SET_IDREG(isar, ID_ISAR0, 0x01101110); + SET_IDREG(isar, ID_ISAR1, 0x02212000); + SET_IDREG(isar, ID_ISAR2, 0x20232232); +@@ -760,10 +756,10 @@ static void cortex_m55_initfn(Object *obj) + SET_IDREG(&cpu->isar, ID_PFR1, 0x00000230); + SET_IDREG(&cpu->isar, ID_DFR0, 0x10200000); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00111040; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01000000; +- cpu->isar.id_mmfr3 = 0x00000011; ++ SET_IDREG(&cpu->isar, ID_MMFR0, 0x00111040); ++ SET_IDREG(&cpu->isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(&cpu->isar, ID_MMFR2, 0x01000000); ++ SET_IDREG(&cpu->isar, ID_MMFR3, 0x00000011); + SET_IDREG(isar, ID_ISAR0, 0x01103110); + SET_IDREG(isar, ID_ISAR1, 0x02212000); + SET_IDREG(isar, ID_ISAR2, 0x20232232); +@@ -799,10 +795,10 @@ static void cortex_r5_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x001); + SET_IDREG(isar, ID_DFR0, 0x010400); + cpu->id_afr0 = 0x0; +- cpu->isar.id_mmfr0 = 0x0210030; +- cpu->isar.id_mmfr1 = 0x00000000; +- cpu->isar.id_mmfr2 = 0x01200000; +- cpu->isar.id_mmfr3 = 0x0211; ++ SET_IDREG(isar, ID_MMFR0, 0x0210030); ++ SET_IDREG(isar, ID_MMFR1, 0x00000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01200000); ++ SET_IDREG(isar, ID_MMFR3, 0x0211); + SET_IDREG(isar, ID_ISAR0, 0x02101111); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232141); +@@ -838,11 +834,11 @@ static void cortex_r52_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x10111001); + SET_IDREG(isar, ID_DFR0, 0x03010006); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x00211040; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01200000; +- cpu->isar.id_mmfr3 = 0xf0102211; +- cpu->isar.id_mmfr4 = 0x00000010; ++ SET_IDREG(isar, ID_MMFR0, 0x00211040); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01200000); ++ SET_IDREG(isar, ID_MMFR3, 0xf0102211); ++ SET_IDREG(isar, ID_MMFR4, 0x00000010); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232142); +@@ -1098,10 +1094,10 @@ static void arm_max_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10101105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10101105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 6646f265ee..31a5a6b9c5 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -78,10 +78,10 @@ static void aarch64_a35_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -257,11 +257,11 @@ static void aarch64_a55_initfn(Object *obj) + SET_IDREG(isar, ID_ISAR4, 0x00011142); + SET_IDREG(isar, ID_ISAR5, 0x01011121); + SET_IDREG(isar, ID_ISAR6, 0x00000010); +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_mmfr4 = 0x00021110; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); ++ SET_IDREG(isar, ID_MMFR4, 0x00021110); + SET_IDREG(isar, ID_PFR0, 0x10010131); + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_PFR2, 0x00000011); +@@ -316,10 +316,10 @@ static void aarch64_a72_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00011011); + SET_IDREG(isar, ID_DFR0, 0x03010066); + cpu->id_afr0 = 0x00000000; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02102211; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02102211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); +@@ -382,11 +382,11 @@ static void aarch64_a76_initfn(Object *obj) + SET_IDREG(isar, ID_ISAR4, 0x00010142); + SET_IDREG(isar, ID_ISAR5, 0x01011121); + SET_IDREG(isar, ID_ISAR6, 0x00000010); +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_mmfr4 = 0x00021110; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); ++ SET_IDREG(isar, ID_MMFR4, 0x00021110); + SET_IDREG(isar, ID_PFR0, 0x10010131); + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + SET_IDREG(isar, ID_PFR2, 0x00000011); +@@ -622,11 +622,11 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + SET_IDREG(isar, ID_ISAR4, 0x00010142); + SET_IDREG(isar, ID_ISAR5, 0x01011121); + SET_IDREG(isar, ID_ISAR6, 0x00000010); +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_mmfr4 = 0x00021110; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); ++ SET_IDREG(isar, ID_MMFR4, 0x00021110); + SET_IDREG(isar, ID_PFR0, 0x10010131); + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + SET_IDREG(isar, ID_PFR2, 0x00000011); +@@ -697,11 +697,11 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + SET_IDREG(isar, ID_ISAR4, 0x00010142); + SET_IDREG(isar, ID_ISAR5, 0x11011121); + SET_IDREG(isar, ID_ISAR6, 0x01100111); +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; +- cpu->isar.id_mmfr4 = 0x01021110; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); ++ SET_IDREG(isar, ID_MMFR4, 0x01021110); + SET_IDREG(isar, ID_PFR0, 0x21110131); + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + SET_IDREG(isar, ID_PFR2, 0x00000011); +@@ -903,17 +903,17 @@ static void aarch64_a710_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + SET_IDREG(isar, ID_DFR0, 0x16011099); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); + SET_IDREG(isar, ID_ISAR3, 0x01112131); + SET_IDREG(isar, ID_ISAR4, 0x00010142); + SET_IDREG(isar, ID_ISAR5, 0x11011121); /* with Crypto */ +- cpu->isar.id_mmfr4 = 0x21021110; ++ SET_IDREG(isar, ID_MMFR4, 0x21021110); + SET_IDREG(isar, ID_ISAR6, 0x01111111); + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; +@@ -1001,17 +1001,17 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + SET_IDREG(isar, ID_DFR0, 0x16011099); + cpu->id_afr0 = 0; +- cpu->isar.id_mmfr0 = 0x10201105; +- cpu->isar.id_mmfr1 = 0x40000000; +- cpu->isar.id_mmfr2 = 0x01260000; +- cpu->isar.id_mmfr3 = 0x02122211; ++ SET_IDREG(isar, ID_MMFR0, 0x10201105); ++ SET_IDREG(isar, ID_MMFR1, 0x40000000); ++ SET_IDREG(isar, ID_MMFR2, 0x01260000); ++ SET_IDREG(isar, ID_MMFR3, 0x02122211); + SET_IDREG(isar, ID_ISAR0, 0x02101110); + SET_IDREG(isar, ID_ISAR1, 0x13112111); + SET_IDREG(isar, ID_ISAR2, 0x21232042); + SET_IDREG(isar, ID_ISAR3, 0x01112131); + SET_IDREG(isar, ID_ISAR4, 0x00010142); + SET_IDREG(isar, ID_ISAR5, 0x11011121); /* with Crypto */ +- cpu->isar.id_mmfr4 = 0x01021110; ++ SET_IDREG(isar, ID_MMFR4, 0x01021110); + SET_IDREG(isar, ID_ISAR6, 0x01111111); + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; +-- +2.51.0.windows.1 + diff --git a/arm-cpu-Store-id_pfr0-1-2-into-the-idregs-array.patch b/arm-cpu-Store-id_pfr0-1-2-into-the-idregs-array.patch new file mode 100644 index 00000000..d058de5d --- /dev/null +++ b/arm-cpu-Store-id_pfr0-1-2-into-the-idregs-array.patch @@ -0,0 +1,575 @@ +From 9ce1df8b42d48a6d733ecff04f029e0198c25646 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 09/26] arm/cpu: Store id_pfr0/1/2 into the idregs array + +Reviewed-by: Richard Henderson +Reviewed-by: Sebastian Ott +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + hw/intc/armv7m_nvic.c | 5 +-- + target/arm/cpu-features.h | 10 +++--- + target/arm/cpu.c | 8 ++--- + target/arm/cpu.h | 3 -- + target/arm/cpu64.c | 12 +++---- + target/arm/helper.c | 8 ++--- + target/arm/kvm64.c | 9 ++--- + target/arm/tcg/cpu32.c | 76 +++++++++++++++++++-------------------- + target/arm/tcg/cpu64.c | 44 +++++++++++------------ + 9 files changed, 84 insertions(+), 91 deletions(-) + +diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c +index 5f68b0e711..b613b2cafe 100644 +--- a/hw/intc/armv7m_nvic.c ++++ b/hw/intc/armv7m_nvic.c +@@ -988,6 +988,7 @@ static void nvic_nmi_trigger(void *opaque, int n, int level) + static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + { + ARMCPU *cpu = s->cpu; ++ ARMISARegisters *isar = &cpu->isar; + uint32_t val; + + switch (offset) { +@@ -1263,12 +1264,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_pfr0; ++ return GET_IDREG(isar, ID_PFR0); + case 0xd44: /* PFR1. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } +- return cpu->isar.id_pfr1; ++ return GET_IDREG(isar, ID_PFR1); + case 0xd48: /* DFR0. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; +diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h +index 25180e4b77..fe73988141 100644 +--- a/target/arm/cpu-features.h ++++ b/target/arm/cpu-features.h +@@ -133,12 +133,12 @@ static inline bool isar_feature_aa32_i8mm(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_ras(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr0, ID_PFR0, RAS) != 0; ++ return FIELD_EX32_IDREG(id, ID_PFR0, RAS) != 0; + } + + static inline bool isar_feature_aa32_mprofile(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr1, ID_PFR1, MPROGMOD) != 0; ++ return FIELD_EX32_IDREG(id, ID_PFR1, MPROGMOD) != 0; + } + + static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) +@@ -147,7 +147,7 @@ static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) + * Return true if M-profile state handling insns + * (VSCCLRM, CLRM, FPCTX access insns) are implemented + */ +- return FIELD_EX32(id->id_pfr1, ID_PFR1, SECURITY) >= 3; ++ return FIELD_EX32_IDREG(id, ID_PFR1, SECURITY) >= 3; + } + + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) +@@ -346,12 +346,12 @@ static inline bool isar_feature_aa32_evt(const ARMISARegisters *id) + + static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0; ++ return FIELD_EX32_IDREG(id, ID_PFR0, DIT) != 0; + } + + static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) + { +- return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0; ++ return FIELD_EX32_IDREG(id, ID_PFR2, SSBS) != 0; + } + + static inline bool isar_feature_aa32_debugv7p1(const ARMISARegisters *id) +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 7667530e9d..60654e8630 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2150,7 +2150,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * Disable the security extension feature bits in the processor + * feature registers as well. + */ +- cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, ID_PFR1, SECURITY, 0); ++ FIELD_DP32_IDREG(isar, ID_PFR1, SECURITY, 0); + cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); + FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL3, 0); + +@@ -2190,8 +2190,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + * registers if we don't have EL2. + */ + FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL2, 0); +- cpu->isar.id_pfr1 = FIELD_DP32(cpu->isar.id_pfr1, +- ID_PFR1, VIRTUALIZATION, 0); ++ FIELD_DP32_IDREG(isar, ID_PFR1, VIRTUALIZATION, 0); + } + + if (cpu_isar_feature(aa64_mte, cpu)) { +@@ -2239,8 +2238,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, MMAPTRC, 0); + /* FEAT_AMU (Activity Monitors Extension) */ + FIELD_DP64_IDREG(isar, ID_AA64PFR0, AMU, 0); +- cpu->isar.id_pfr0 = +- FIELD_DP32(cpu->isar.id_pfr0, ID_PFR0, AMU, 0); ++ FIELD_DP32_IDREG(isar, ID_PFR0, AMU, 0); + /* FEAT_MPAM (Memory Partitioning and Monitoring Extension) */ + FIELD_DP64_IDREG(isar, ID_AA64PFR0, MPAM, 0); + /* FEAT_NV (Nested Virtualization) */ +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 4c29657ec7..e9ef2fd484 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1064,9 +1064,6 @@ struct ArchCPU { + uint32_t id_mmfr3; + uint32_t id_mmfr4; + uint32_t id_mmfr5; +- uint32_t id_pfr0; +- uint32_t id_pfr1; +- uint32_t id_pfr2; + uint32_t mvfr0; + uint32_t mvfr1; + uint32_t mvfr2; +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 9495bc418e..9d8c617aca 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -750,8 +750,8 @@ static void aarch64_a57_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; +@@ -808,8 +808,8 @@ static void aarch64_a53_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; +@@ -865,8 +865,8 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000131); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; +diff --git a/target/arm/helper.c b/target/arm/helper.c +index d2d9de8b0b..9895e8e74f 100644 +--- a/target/arm/helper.c ++++ b/target/arm/helper.c +@@ -7268,7 +7268,7 @@ static void define_pmu_regs(ARMCPU *cpu) + static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) + { + ARMCPU *cpu = env_archcpu(env); +- uint64_t pfr1 = cpu->isar.id_pfr1; ++ uint64_t pfr1 = GET_IDREG(&cpu->isar, ID_PFR1); + + if (env->gicv3state) { + pfr1 |= 1 << 28; +@@ -8225,7 +8225,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa32_tid3, +- .resetvalue = cpu->isar.id_pfr0 }, ++ .resetvalue = GET_IDREG(isar, ID_PFR0)}, + /* + * ID_PFR1 is not a plain ARM_CP_CONST because we don't know + * the value of the GIC field until after we define these regs. +@@ -8236,7 +8236,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .accessfn = access_aa32_tid3, + #ifdef CONFIG_USER_ONLY + .type = ARM_CP_CONST, +- .resetvalue = cpu->isar.id_pfr1, ++ .resetvalue = GET_IDREG(isar, ID_PFR1), + #else + .type = ARM_CP_NO_RAW, + .accessfn = access_aa32_tid3, +@@ -8582,7 +8582,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 4, + .access = PL1_R, .type = ARM_CP_CONST, + .accessfn = access_aa64_tid3, +- .resetvalue = cpu->isar.id_pfr2 }, ++ .resetvalue = GET_IDREG(isar, ID_PFR2)}, + { .name = "ID_DFR1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, + .access = PL1_R, .type = ARM_CP_CONST, +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 2e57ba4224..74eba5ce47 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -373,10 +373,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + * than skipping the reads and leaving 0, as we must avoid + * considering the values in every case. + */ +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr0, +- ARM64_SYS_REG(3, 0, 0, 1, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1, +- ARM64_SYS_REG(3, 0, 0, 1, 1)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_PFR0_EL1_IDX); ++ err |= get_host_cpu_reg(fd, ahcf, ID_PFR1_EL1_IDX); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0, + ARM64_SYS_REG(3, 0, 0, 1, 2)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0, +@@ -403,8 +401,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + ARM64_SYS_REG(3, 0, 0, 3, 1)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, + ARM64_SYS_REG(3, 0, 0, 3, 2)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2, +- ARM64_SYS_REG(3, 0, 0, 3, 4)); ++ err |= get_host_cpu_reg(fd, ahcf, ID_PFR2_EL1_IDX); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr1, + ARM64_SYS_REG(3, 0, 0, 3, 5)); + err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr5, +diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c +index dbf2070a81..7830189672 100644 +--- a/target/arm/tcg/cpu32.c ++++ b/target/arm/tcg/cpu32.c +@@ -74,16 +74,16 @@ void aa32_max_features(ARMCPU *cpu) + t = FIELD_DP32(t, ID_MMFR5, ETS, 1); /* FEAT_ETS */ + cpu->isar.id_mmfr5 = t; + +- t = cpu->isar.id_pfr0; ++ t = GET_IDREG(isar, ID_PFR0); + t = FIELD_DP32(t, ID_PFR0, CSV2, 2); /* FEAT_CVS2 */ + t = FIELD_DP32(t, ID_PFR0, DIT, 1); /* FEAT_DIT */ + t = FIELD_DP32(t, ID_PFR0, RAS, 1); /* FEAT_RAS */ +- cpu->isar.id_pfr0 = t; ++ SET_IDREG(isar, ID_PFR0, t); + +- t = cpu->isar.id_pfr2; ++ 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 */ +- cpu->isar.id_pfr2 = t; ++ SET_IDREG(isar, ID_PFR2, t); + + t = cpu->isar.id_dfr0; + t = FIELD_DP32(t, ID_DFR0, COPDBG, 9); /* FEAT_Debugv8p4 */ +@@ -229,8 +229,8 @@ static void arm1136_r2_initfn(Object *obj) + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; ++ SET_IDREG(isar, ID_PFR0, 0x111); ++ SET_IDREG(isar, ID_PFR1, 0x1); + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; +@@ -261,8 +261,8 @@ static void arm1136_initfn(Object *obj) + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; ++ SET_IDREG(isar, ID_PFR0, 0x111); ++ SET_IDREG(isar, ID_PFR1, 0x1); + cpu->isar.id_dfr0 = 0x2; + cpu->id_afr0 = 0x3; + cpu->isar.id_mmfr0 = 0x01130003; +@@ -294,8 +294,8 @@ static void arm1176_initfn(Object *obj) + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1dd20d2; + cpu->reset_sctlr = 0x00050078; +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x11; ++ SET_IDREG(isar, ID_PFR0, 0x111); ++ SET_IDREG(isar, ID_PFR1, 0x11); + cpu->isar.id_dfr0 = 0x33; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x01130003; +@@ -324,8 +324,8 @@ static void arm11mpcore_initfn(Object *obj) + cpu->isar.mvfr0 = 0x11111111; + cpu->isar.mvfr1 = 0x00000000; + cpu->ctr = 0x1d192992; /* 32K icache 32K dcache */ +- cpu->isar.id_pfr0 = 0x111; +- cpu->isar.id_pfr1 = 0x1; ++ SET_IDREG(isar, ID_PFR0, 0x111); ++ SET_IDREG(isar, ID_PFR1, 0x1); + cpu->isar.id_dfr0 = 0; + cpu->id_afr0 = 0x2; + cpu->isar.id_mmfr0 = 0x01100103; +@@ -364,8 +364,8 @@ static void cortex_a8_initfn(Object *obj) + cpu->isar.mvfr1 = 0x00011111; + cpu->ctr = 0x82048004; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x1031; +- cpu->isar.id_pfr1 = 0x11; ++ SET_IDREG(isar, ID_PFR0, 0x1031); ++ SET_IDREG(isar, ID_PFR1, 0x11); + cpu->isar.id_dfr0 = 0x400; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x31100003; +@@ -440,8 +440,8 @@ static void cortex_a9_initfn(Object *obj) + cpu->isar.mvfr1 = 0x01111111; + cpu->ctr = 0x80038003; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x1031; +- cpu->isar.id_pfr1 = 0x11; ++ SET_IDREG(isar, ID_PFR0, 0x1031); ++ SET_IDREG(isar, ID_PFR1, 0x11); + cpu->isar.id_dfr0 = 0x000; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x00100103; +@@ -505,8 +505,8 @@ static void cortex_a7_initfn(Object *obj) + cpu->isar.mvfr1 = 0x11111111; + cpu->ctr = 0x84448003; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x00001131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00001131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; +@@ -556,8 +556,8 @@ static void cortex_a15_initfn(Object *obj) + cpu->isar.mvfr1 = 0x11111111; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50078; +- cpu->isar.id_pfr0 = 0x00001131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00001131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x02010555; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; +@@ -598,8 +598,8 @@ static void cortex_m0_initfn(Object *obj) + * by looking at ID register fields. We use the same values as + * for the M3. + */ +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; +@@ -625,8 +625,8 @@ static void cortex_m3_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_M_MAIN); + cpu->midr = 0x410fc231; + cpu->pmsav7_dregion = 8; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; +@@ -656,8 +656,8 @@ static void cortex_m4_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000000; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00000030; +@@ -687,8 +687,8 @@ static void cortex_m7_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110221; + cpu->isar.mvfr1 = 0x12000011; + cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000200; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000200); + cpu->isar.id_dfr0 = 0x00100000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00100030; +@@ -720,8 +720,8 @@ static void cortex_m33_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110021; + cpu->isar.mvfr1 = 0x11000011; + cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x00000030; +- cpu->isar.id_pfr1 = 0x00000210; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x00000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000210); + cpu->isar.id_dfr0 = 0x00200000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00101F40; +@@ -758,8 +758,8 @@ static void cortex_m55_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110221; + cpu->isar.mvfr1 = 0x12100211; + cpu->isar.mvfr2 = 0x00000040; +- cpu->isar.id_pfr0 = 0x20000030; +- cpu->isar.id_pfr1 = 0x00000230; ++ SET_IDREG(&cpu->isar, ID_PFR0, 0x20000030); ++ SET_IDREG(&cpu->isar, ID_PFR1, 0x00000230); + cpu->isar.id_dfr0 = 0x10200000; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00111040; +@@ -797,8 +797,8 @@ static void cortex_r5_initfn(Object *obj) + set_feature(&cpu->env, ARM_FEATURE_PMSA); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x411fc153; /* r1p3 */ +- cpu->isar.id_pfr0 = 0x0131; +- cpu->isar.id_pfr1 = 0x001; ++ SET_IDREG(isar, ID_PFR0, 0x0131); ++ SET_IDREG(isar, ID_PFR1, 0x001); + cpu->isar.id_dfr0 = 0x010400; + cpu->id_afr0 = 0x0; + cpu->isar.id_mmfr0 = 0x0210030; +@@ -836,8 +836,8 @@ static void cortex_r52_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8144c004; + cpu->reset_sctlr = 0x30c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x10111001; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x10111001); + cpu->isar.id_dfr0 = 0x03010006; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x00211040; +@@ -1096,8 +1096,8 @@ static void arm_max_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10101105; +diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c +index 6be05f87f6..dbfeeb92a0 100644 +--- a/target/arm/tcg/cpu64.c ++++ b/target/arm/tcg/cpu64.c +@@ -74,8 +74,8 @@ static void aarch64_a35_initfn(Object *obj) + cpu->midr = 0x411fd040; + cpu->revidr = 0; + cpu->ctr = 0x84448004; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; +@@ -262,9 +262,9 @@ static void aarch64_a55_initfn(Object *obj) + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; +- cpu->isar.id_pfr0 = 0x10010131; +- cpu->isar.id_pfr1 = 0x00011011; +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR0, 0x10010131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + cpu->midr = 0x412FD050; /* r2p0 */ + cpu->revidr = 0; + +@@ -312,8 +312,8 @@ static void aarch64_a72_initfn(Object *obj) + cpu->isar.mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; +- cpu->isar.id_pfr0 = 0x00000131; +- cpu->isar.id_pfr1 = 0x00011011; ++ SET_IDREG(isar, ID_PFR0, 0x00000131); ++ SET_IDREG(isar, ID_PFR1, 0x00011011); + cpu->isar.id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->isar.id_mmfr0 = 0x10201105; +@@ -387,9 +387,9 @@ static void aarch64_a76_initfn(Object *obj) + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; +- cpu->isar.id_pfr0 = 0x10010131; +- cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR0, 0x10010131); ++ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + cpu->midr = 0x414fd0b1; /* r4p1 */ + cpu->revidr = 0; + +@@ -627,9 +627,9 @@ static void aarch64_neoverse_n1_initfn(Object *obj) + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x00021110; +- cpu->isar.id_pfr0 = 0x10010131; +- cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR0, 0x10010131); ++ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + cpu->midr = 0x414fd0c1; /* r4p1 */ + cpu->revidr = 0; + +@@ -702,9 +702,9 @@ static void aarch64_neoverse_v1_initfn(Object *obj) + cpu->isar.id_mmfr2 = 0x01260000; + cpu->isar.id_mmfr3 = 0x02122211; + cpu->isar.id_mmfr4 = 0x01021110; +- cpu->isar.id_pfr0 = 0x21110131; +- cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR0, 0x21110131); ++ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + cpu->midr = 0x411FD402; /* r1p2 */ + cpu->revidr = 0; + +@@ -899,8 +899,8 @@ static void aarch64_a710_initfn(Object *obj) + /* Ordered by Section B.4: AArch64 registers */ + cpu->midr = 0x412FD471; /* r2p1 */ + cpu->revidr = 0; +- cpu->isar.id_pfr0 = 0x21110131; +- cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ ++ SET_IDREG(isar, ID_PFR0, 0x21110131); ++ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + cpu->isar.id_dfr0 = 0x16011099; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; +@@ -918,7 +918,7 @@ static void aarch64_a710_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ +@@ -997,8 +997,8 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + /* Ordered by Section B.5: AArch64 ID registers */ + cpu->midr = 0x410FD493; /* r0p3 */ + cpu->revidr = 0; +- cpu->isar.id_pfr0 = 0x21110131; +- cpu->isar.id_pfr1 = 0x00010000; /* GIC filled in later */ ++ SET_IDREG(isar, ID_PFR0, 0x21110131); ++ SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */ + cpu->isar.id_dfr0 = 0x16011099; + cpu->id_afr0 = 0; + cpu->isar.id_mmfr0 = 0x10201105; +@@ -1016,7 +1016,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj) + cpu->isar.mvfr0 = 0x10110222; + cpu->isar.mvfr1 = 0x13211111; + cpu->isar.mvfr2 = 0x00000043; +- cpu->isar.id_pfr2 = 0x00000011; ++ SET_IDREG(isar, ID_PFR2, 0x00000011); + SET_IDREG(isar, ID_AA64PFR0, 0x1201111120111112ull); /* GIC filled in later */ + SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000221ull); + SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */ +-- +2.51.0.windows.1 + diff --git a/arm-cpu-accessors-for-writable-id-registers.patch b/arm-cpu-accessors-for-writable-id-registers.patch new file mode 100644 index 00000000..55b79ced --- /dev/null +++ b/arm-cpu-accessors-for-writable-id-registers.patch @@ -0,0 +1,51 @@ +From 36a23693d442edbcd4a610daf36265a3a113e11e Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 19/26] arm/cpu: accessors for writable id registers + +Also add conversion between the different indices. + +Signed-off-by: Cornelia Huck +--- + target/arm/cpu.h | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 3f57363baf..a75f057430 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -866,6 +866,13 @@ typedef struct IdRegMap { + uint64_t regs[NR_ID_REGS]; + } IdRegMap; + ++#define ARM_FEATURE_ID_RANGE_IDX(op0, op1, crn, crm, op2) \ ++ ({ \ ++ __u64 __op1 = (op1) & 3; \ ++ __op1 -= (__op1 == 3); \ ++ (__op1 << 6 | ((crm) & 7) << 3 | (op2)); \ ++ }) ++ + /* REG is ID_XXX */ + #define FIELD_DP64_IDREG(ISAR, REG, FIELD, VALUE) \ + ({ \ +@@ -913,6 +920,17 @@ typedef struct IdRegMap { + i_->idregs[REG ## _EL1_IDX]; \ + }) + ++#define GET_IDREG_WRITABLE(MAP, REG) \ ++ ({ \ ++ const IdRegMap *m_ = (MAP); \ ++ int index = ARM_FEATURE_ID_RANGE_IDX((sysreg >> 14) & 0x0000c000, \ ++ (sysreg >> 11) & 0x00003800, \ ++ (sysreg >> 7) & 0x00000780, \ ++ (sysreg >> 3) & 0x00000078, \ ++ sysreg & 0x00000007); \ ++ m_->regs[index]; \ ++ }) ++ + /** + * ARMCPU: + * @env: #CPUARMState +-- +2.51.0.windows.1 + diff --git a/arm-cpu-enable-MIDR-writable.patch b/arm-cpu-enable-MIDR-writable.patch new file mode 100644 index 00000000..c5db976b --- /dev/null +++ b/arm-cpu-enable-MIDR-writable.patch @@ -0,0 +1,34 @@ +From e9f40ad8e41fa8ac2653ea4cc11f6f2ea66e6ca3 Mon Sep 17 00:00:00 2001 +From: Qingtong Jia +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 26/26] arm/cpu: enable MIDR writable + +For now we support writable imp id feature. Let's check and enable +KVM_CAP_ARM_WRITABLE_IMP_ID_REGS if kvm supports it. + +Signed-off-by: Qingtong Jia +--- + accel/kvm/kvm-all.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 6e3a3f14a1..a321bf514c 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2680,6 +2680,13 @@ static int kvm_init(MachineState *ms) + query_stats_schemas_cb); + } + ++ if (kvm_check_extension(kvm_state, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS)) { ++ ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0); ++ if (ret) { ++ fprintf(stderr, "Could not enable KVM_CAP_ARM_WRITABLE_IMP_ID_REGS: %d\n", ret); ++ } ++ } ++ + return 0; + + err: +-- +2.51.0.windows.1 + diff --git a/arm-cpu-features-document-ID-reg-properties.patch b/arm-cpu-features-document-ID-reg-properties.patch new file mode 100644 index 00000000..eaa616a6 --- /dev/null +++ b/arm-cpu-features-document-ID-reg-properties.patch @@ -0,0 +1,159 @@ +From 974c2e6edd683c96054343541d388ed48ad754af Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 24/26] arm/cpu-features: document ID reg properties + +Add some documentation for how individual ID registers can be +configured with the host cpu model. + +[CH: adapt to removal of the 'custom' model, added some more + explanations about using the ID register props] +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + docs/system/arm/cpu-features.rst | 104 ++++++++++++++++++++++++++++--- + 1 file changed, 96 insertions(+), 8 deletions(-) + +diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst +index a5fb929243..8b497134ab 100644 +--- a/docs/system/arm/cpu-features.rst ++++ b/docs/system/arm/cpu-features.rst +@@ -2,7 +2,10 @@ Arm CPU Features + ================ + + CPU features are optional features that a CPU of supporting type may +-choose to implement or not. In QEMU, optional CPU features have ++choose to implement or not. QEMU provides two different mechanisms ++to configure those features: ++ ++1. For most CPU models, optional CPU features may have + corresponding boolean CPU proprieties that, when enabled, indicate + that the feature is implemented, and, conversely, when disabled, + indicate that it is not implemented. An example of an Arm CPU feature +@@ -29,6 +32,16 @@ supports the feature. While ``aarch64`` currently only works with KVM, + it could work with TCG. CPU features that are specific to KVM are + prefixed with "kvm-" and are described in "KVM VCPU Features". + ++2. Additionally, the ``host`` CPU model on KVM allows to configure optional ++CPU features via the corresponding ID registers. The host kernel allows ++to write a subset of ID register fields. The host model exposes ++properties for each writable ID register field. Those options are named ++SYSREG__. IDREG and FIELD names are those used in the ++ARM ARM Reference Manual. They can also be found in the Linux ++arch/arm64/tool/sysreg file which is used to automatically generate the ++description for those registers and fields. This currently only has been ++implemented for KVM. ++ + CPU Feature Probing + =================== + +@@ -124,13 +137,20 @@ A note about CPU models and KVM + + Named CPU models generally do not work with KVM. There are a few cases + that do work, e.g. using the named CPU model ``cortex-a57`` with KVM on a +-seattle host, but mostly if KVM is enabled the ``host`` CPU type must be +-used. This means the guest is provided all the same CPU features as the +-host CPU type has. And, for this reason, the ``host`` CPU type should +-enable all CPU features that the host has by default. Indeed it's even +-a bit strange to allow disabling CPU features that the host has when using +-the ``host`` CPU type, but in the absence of CPU models it's the best we can +-do if we want to launch guests without all the host's CPU features enabled. ++seattle host, but mostly if KVM is enabled, the ``host`` CPU model must be ++used. ++ ++Using the ``host`` type means the guest is provided all the same CPU ++features as the host CPU type has. And, for this reason, the ``host`` ++CPU type should enable all CPU features that the host has by default. ++ ++In case some features need to be hidden to the guest, and the host kernel ++supports it, the ``host`` model can be instructed to disable individual ++ID register values. This is especially useful for migration purposes. ++However, this interface will not allow configuring an arbitrary set of ++features; the ID registers must describe a subset of the host's features, ++and all differences to the host's configuration must actually be supported ++by the kernel to be deconfigured. + + Enabling KVM also affects the ``query-cpu-model-expansion`` QMP command. The + affect is not only limited to specific features, as pointed out in example +@@ -167,6 +187,13 @@ disabling many SVE vector lengths would be quite verbose, the ``sve`` CPU + properties have special semantics (see "SVE CPU Property Parsing + Semantics"). + ++Additionally, if supported by KVM on the host kernel, the ``host`` CPU model ++may be configured via individual ID register field properties, for example:: ++ ++ $ qemu-system-aarch64 -M virt -cpu host,SYSREG_ID_AA64ISAR0_EL1_DP=0x0 ++ ++This forces ID_AA64ISAR0_EL1 DP field to 0. ++ + KVM VCPU Features + ================= + +@@ -463,3 +490,64 @@ Legal values for ``S`` are 30, 34, 36, and 39; the default is 30. + + As with ``x-rme``, the ``x-l0gptsz`` property may be renamed or + removed in some future QEMU release. ++ ++Configuring CPU features via ID register fields ++=============================================== ++ ++Note that this is currently only supported under KVM, and with the ++``host`` CPU model. ++ ++Querying available ID register fields ++------------------------------------- ++ ++QEMU will create properties for all ID register fields that are ++reported as being writable by the kernel, and that are known to the ++QEMU instance. Therefore, the same QEMU binary may expose different ++properties when run under a different kernel. ++ ++To find out all available writable ID register fields, use the ++``query-cpu-model-expansion`` QMP command:: ++ ++ (QEMU) query-cpu-model-expansion type=full model={"name":"host"} ++ {"return": { ++ "model": {"name": "host", "props": { ++ "SYSREG_ID_AA64PFR0_EL1_EL3": 1, "SYSREG_ID_AA64ISAR2_EL1_CLRBHB": 0, ++ "SYSREG_CTR_EL0_L1Ip": 3, "SYSREG_CTR_EL0_DminLine": 4, ++ "SYSREG_ID_AA64MMFR0_EL1_BIGEND": 1, "SYSREG_ID_AA64MMFR1_EL1_ECBHB": 0, ++ "SYSREG_ID_AA64MMFR2_EL1_CnP": 1, "SYSREG_ID_DFR0_EL1_PerfMon": 4, ++ "SYSREG_ID_AA64PFR0_EL1_DIT": 0, "SYSREG_ID_AA64MMFR1_EL1_HAFDBS": 2, ++ "SYSREG_ID_AA64ISAR0_EL1_FHM": 0, "SYSREG_ID_AA64ISAR2_EL1_CSSC": 0, ++ "SYSREG_ID_AA64ISAR0_EL1_DP": 1, (...) ++ }}}} ++ ++If a certain field in an ID register does not show up in this list, it ++is not writable with the specific host kernel. ++ ++A note on compatibility ++----------------------- ++ ++A common use case for providing a defined set of ID register values is ++to be able to present a fixed set of features to a guest, often referred ++to as "stable guest ABI". This may take the form of ironing out differences ++between two similar CPUs with the intention of being able to migrate ++between machines with those CPUs, or providing the same CPU across Linux ++kernel updates on the host. ++ ++Over the course of time, the Linux kernel is changing the set of ID register ++fields that are writable by userspace. Newly introduced writable ID ++registers should be initialized to 0 to ensure compatibility. However, ID ++registers that have already been introduced that undergo a change as to ++which fields are writable may introduce incompatibities that need to be ++addressed on a case-by-case basis for the systems that you wish to migrate ++inbetween. ++ ++A note on Arm CPU features (FEAT_xxx) ++------------------------------------- ++ ++Configuring CPUs is done on a feature level on other architectures, and this ++would imply configuring FEAT_xxx values on Arm. However, differences between ++CPUs may not map to FEAT_xxx, but to differences in other registers in the ++ID register range; for example, differences in the cache architecture exposed ++via ``CTR_EL0``. We therefore cannot rely on configuration via FEAT_xxx. A ++feature-based interface more similar to other architectures may be implemented ++on top of the ID register interface in the future. +-- +2.51.0.windows.1 + diff --git a/arm-cpu-manually-make-MIDR-REVIDR-AIDR-writable.patch b/arm-cpu-manually-make-MIDR-REVIDR-AIDR-writable.patch new file mode 100644 index 00000000..a7375d21 --- /dev/null +++ b/arm-cpu-manually-make-MIDR-REVIDR-AIDR-writable.patch @@ -0,0 +1,122 @@ +From 8c3706bcbb07816384ffa5e26c97c6a570d0e24b Mon Sep 17 00:00:00 2001 +From: Qingtong Jia +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 25/26] arm/cpu: manually make MIDR/REVIDR/AIDR writable + +Currently MIDR/REVIDR/AIDR didn't create from sysreg generation scripts, +we manually add MIDR/REVIDR/AIDR for now. + +Signed-off-by: Qingtong Jia +--- + scripts/arm-gen-cpu-sysregs-header.awk | 5 ++++- + scripts/gen-cpu-sysreg-properties.awk | 21 +++++++++++++++++++++ + target/arm/cpu-sysreg-properties.c | 19 +++++++++++++++++++ + target/arm/cpu-sysregs.h.inc | 4 +++- + target/arm/cpu64.c | 2 +- + 5 files changed, 48 insertions(+), 3 deletions(-) + +diff --git a/scripts/arm-gen-cpu-sysregs-header.awk b/scripts/arm-gen-cpu-sysregs-header.awk +index f92bbbafa7..9f16e420f8 100755 +--- a/scripts/arm-gen-cpu-sysregs-header.awk ++++ b/scripts/arm-gen-cpu-sysregs-header.awk +@@ -9,7 +9,10 @@ BEGIN { + print "/* GENERATED FILE, DO NOT EDIT */" + print "/* use arm-gen-cpu-sysregs-header.awk to regenerate */" + } END { +- print "" ++ /* add MIDR, REVIDR, and AIDR */ ++ print "DEF(MIDR_EL1, 3, 0, 0, 0, 0)" ++ print "DEF(REVIDR_EL1, 3, 0, 0, 0, 6)" ++ print "DEF(AIDR_EL1, 3, 1, 0, 0, 7)" + } + + # skip blank lines and comment lines +diff --git a/scripts/gen-cpu-sysreg-properties.awk b/scripts/gen-cpu-sysreg-properties.awk +index da00d377ff..56d9d8f002 100755 +--- a/scripts/gen-cpu-sysreg-properties.awk ++++ b/scripts/gen-cpu-sysreg-properties.awk +@@ -106,6 +106,27 @@ END { + if (__current_block_depth != 0) + fatal("Missing terminator for " block_current() " block") + ++ # Manually add MIDR/REVIDR/AIDR ++ print "" ++ print " /* MIDR_EL1 */" ++ print " ARM64SysReg *MIDR_EL1 = arm64_sysreg_get(MIDR_EL1_IDX);" ++ print " MIDR_EL1->name = \"MIDR_EL1\";" ++ print " arm64_sysreg_add_field(MIDR_EL1, \"Implementer\", 24, 31);" ++ print " arm64_sysreg_add_field(MIDR_EL1, \"Variant\", 20, 23);" ++ print " arm64_sysreg_add_field(MIDR_EL1, \"Architecture\", 16, 19);" ++ print " arm64_sysreg_add_field(MIDR_EL1, \"PartNum\", 4, 15);" ++ print " arm64_sysreg_add_field(MIDR_EL1, \"Revision\", 0, 3);" ++ print "" ++ print " /* REVIDR_EL1 */" ++ print " ARM64SysReg *REVIDR_EL1 = arm64_sysreg_get(REVIDR_EL1_IDX);" ++ print " REVIDR_EL1->name = \"REVIDR_EL1\";" ++ print " arm64_sysreg_add_field(REVIDR_EL1, \"IMPDEF\", 0, 63);" ++ print "" ++ print " /* AIDR_EL1 */" ++ print " ARM64SysReg *AIDR_EL1 = arm64_sysreg_get(AIDR_EL1_IDX);" ++ print " AIDR_EL1->name = \"AIDR_EL1\";" ++ print " arm64_sysreg_add_field(AIDR_EL1, \"IMPDEF\", 0, 63);" ++ print "" + print "}" + } + +diff --git a/target/arm/cpu-sysreg-properties.c b/target/arm/cpu-sysreg-properties.c +index 94cc496438..c8a43c9eb4 100644 +--- a/target/arm/cpu-sysreg-properties.c ++++ b/target/arm/cpu-sysreg-properties.c +@@ -742,4 +742,23 @@ void initialize_cpu_sysreg_properties(void) + + /* For S2PIR_EL2 fields see PIRx_ELx */ + ++ /* MIDR_EL1 */ ++ ARM64SysReg *MIDR_EL1 = arm64_sysreg_get(MIDR_EL1_IDX); ++ MIDR_EL1->name = "MIDR_EL1"; ++ arm64_sysreg_add_field(MIDR_EL1, "Implementer", 24, 31); ++ arm64_sysreg_add_field(MIDR_EL1, "Variant", 20, 23); ++ arm64_sysreg_add_field(MIDR_EL1, "Architecture", 16, 19); ++ arm64_sysreg_add_field(MIDR_EL1, "PartNum", 4, 15); ++ arm64_sysreg_add_field(MIDR_EL1, "Revision", 0, 3); ++ ++ /* REVIDR_EL1 */ ++ ARM64SysReg *REVIDR_EL1 = arm64_sysreg_get(REVIDR_EL1_IDX); ++ REVIDR_EL1->name = "REVIDR_EL1"; ++ arm64_sysreg_add_field(REVIDR_EL1, "IMPDEF", 0, 63); ++ ++ /* AIDR_EL1 */ ++ ARM64SysReg *AIDR_EL1 = arm64_sysreg_get(AIDR_EL1_IDX); ++ AIDR_EL1->name = "AIDR_EL1"; ++ arm64_sysreg_add_field(AIDR_EL1, "IMPDEF", 0, 63); ++ + } +diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc +index 1dddd3d357..e3e81e11ee 100644 +--- a/target/arm/cpu-sysregs.h.inc ++++ b/target/arm/cpu-sysregs.h.inc +@@ -50,4 +50,6 @@ DEF(GMID_EL1, 3, 1, 0, 0, 4) + DEF(SMIDR_EL1, 3, 1, 0, 0, 6) + DEF(CTR_EL0, 3, 3, 0, 0, 1) + DEF(DCZID_EL0, 3, 3, 0, 0, 7) +- ++DEF(MIDR_EL1, 3, 0, 0, 0, 0) ++DEF(REVIDR_EL1, 3, 0, 0, 0, 6) ++DEF(AIDR_EL1, 3, 1, 0, 0, 7) +\ No newline at end of file +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 02e5a54b76..edfc19a6ed 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -53,7 +53,7 @@ int get_sysreg_idx(ARMSysRegs sysreg) + switch (sysreg) { + #include "cpu-sysregs.h.inc" + } +- g_assert_not_reached(); ++ return -1; + } + + #undef DEF +-- +2.51.0.windows.1 + diff --git a/arm-cpu-more-customization-for-the-kvm-host-cpu-mode.patch b/arm-cpu-more-customization-for-the-kvm-host-cpu-mode.patch new file mode 100644 index 00000000..07fed877 --- /dev/null +++ b/arm-cpu-more-customization-for-the-kvm-host-cpu-mode.patch @@ -0,0 +1,277 @@ +From 9593509d0f8e80963ece8dbb271144249585fff0 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 22/26] arm/cpu: more customization for the kvm host cpu model + +If the interface for writable ID registers is available, expose uint64 +SYSREG properties for writable ID reg fields exposed by the host +kernel. Properties are named SYSREG__ with REG and FIELD +being those used in linux arch/arm64/tools/sysreg. This done by +matching the writable fields retrieved from the host kernel against the +generated description of sysregs. + +An example of invocation is: +-cpu host,SYSREG_ID_AA64ISAR0_EL1_DP=0x0 +which sets DP field of ID_AA64ISAR0_EL1 to 0. + +[CH: add properties to the host model instead of introducing a new +"custom" model] +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu.c | 12 ++++ + target/arm/cpu64.c | 22 ++++++- + target/arm/kvm64.c | 138 ++++++++++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 10 +++ + target/arm/trace-events | 4 ++ + 5 files changed, 185 insertions(+), 1 deletion(-) + +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index 08d83c4e1a..1f91fb6cf2 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -1839,6 +1839,18 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) + return; + } + ++ /* ++ * If we failed to retrieve the set of writable ID registers for the "host" ++ * CPU model, report it here. No error if the interface for discovering ++ * writable ID registers is not available. ++ * In case we did get the set of writable ID registers, set the features to ++ * the configured values here and perform some sanity checks. ++ */ ++ if (cpu->writable_id_regs == WRITABLE_ID_REGS_FAILED) { ++ error_setg(errp, "Failed to discover writable id registers"); ++ return; ++ } ++ + #ifndef CONFIG_USER_ONLY + /* The NVIC and M-profile CPU are two halves of a single piece of + * hardware; trying to use one without the other is a command line +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 1a64bdf86e..02e5a54b76 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -919,12 +919,32 @@ static void aarch64_host_initfn(Object *obj) + { + #if defined(CONFIG_KVM) + ARMCPU *cpu = ARM_CPU(obj); +- kvm_arm_set_cpu_features_from_host(cpu, false); ++ bool expose_id_regs = true; ++ int ret; ++ ++ cpu->writable_map = g_malloc(sizeof(IdRegMap)); ++ ++ /* discover via KVM_ARM_GET_REG_WRITABLE_MASKS */ ++ ret = kvm_arm_get_writable_id_regs(cpu, cpu->writable_map); ++ if (ret == -ENOSYS) { ++ /* legacy: continue without writable id regs */ ++ expose_id_regs = false; ++ } else if (ret) { ++ /* function will have marked an error */ ++ return; ++ } ++ ++ kvm_arm_set_cpu_features_from_host(cpu, expose_id_regs); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); + aarch64_add_kvm_writable_properties(obj); + } ++ if (expose_id_regs) { ++ /* generate SYSREG properties according to writable masks */ ++ kvm_arm_expose_idreg_properties(cpu, arm64_id_regs); ++ } ++ + #elif defined(CONFIG_HVF) + ARMCPU *cpu = ARM_CPU(obj); + hvf_arm_set_cpu_features_from_host(cpu); +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index be9233f936..7e0ca919b2 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -339,6 +339,144 @@ static int get_host_cpu_idregs(ARMCPU *cpu, int fd, ARMHostCPUFeatures *ahcf) + return err; + } + ++ ++static ARM64SysRegField *get_field(int i, ARM64SysReg *reg) ++{ ++ GList *l; ++ ++ for (l = reg->fields; l; l = l->next) { ++ ARM64SysRegField *field = (ARM64SysRegField *)l->data; ++ ++ if (i >= field->lower && i <= field->upper) { ++ return field; ++ } ++ } ++ return NULL; ++} ++ ++static void set_sysreg_prop(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ ARM64SysRegField *field = (ARM64SysRegField *)opaque; ++ ARMCPU *cpu = ARM_CPU(obj); ++ uint64_t *idregs = cpu->isar.idregs; ++ uint64_t old, value, mask; ++ int lower = field->lower; ++ int upper = field->upper; ++ int length = upper - lower + 1; ++ int index = field->index; ++ ++ if (!visit_type_uint64(v, name, &value, errp)) { ++ return; ++ } ++ ++ if (length < 64 && value > ((1 << length) - 1)) { ++ error_setg(errp, ++ "idreg %s set value (0x%lx) exceeds length of field (%d)!", ++ name, value, length); ++ return; ++ } ++ ++ mask = MAKE_64BIT_MASK(lower, length); ++ value = value << lower; ++ old = idregs[index]; ++ idregs[index] = old & ~mask; ++ idregs[index] |= value; ++ trace_set_sysreg_prop(name, old, mask, value, idregs[index]); ++} ++ ++static void get_sysreg_prop(Object *obj, Visitor *v, ++ const char *name, void *opaque, ++ Error **errp) ++{ ++ ARM64SysRegField *field = (ARM64SysRegField *)opaque; ++ ARMCPU *cpu = ARM_CPU(obj); ++ uint64_t *idregs = cpu->isar.idregs; ++ uint64_t value, mask; ++ int lower = field->lower; ++ int upper = field->upper; ++ int length = upper - lower + 1; ++ int index = field->index; ++ ++ mask = MAKE_64BIT_MASK(lower, length); ++ value = (idregs[index] & mask) >> lower; ++ visit_type_uint64(v, name, &value, errp); ++ trace_get_sysreg_prop(name, value); ++} ++ ++/* ++ * decode_idreg_writemap: Generate props for writable fields ++ * ++ * @obj: CPU object ++ * @index: index of the sysreg ++ * @map: writable map for the sysreg ++ * @reg: description of the sysreg ++ */ ++static int ++decode_idreg_writemap(Object *obj, int index, uint64_t map, ARM64SysReg *reg) ++{ ++ int i = ctz64(map); ++ int nb_sysreg_props = 0; ++ ++ while (map) { ++ ++ ARM64SysRegField *field = get_field(i, reg); ++ int lower, upper; ++ uint64_t mask; ++ char *prop_name; ++ ++ if (!field) { ++ /* the field cannot be matched to any know id named field */ ++ warn_report("%s bit %d of %s is writable but cannot be matched", ++ __func__, i, reg->name); ++ warn_report("%s is cpu-sysreg-properties.c up to date?", __func__); ++ map = map & ~BIT_ULL(i); ++ i = ctz64(map); ++ continue; ++ } ++ lower = field->lower; ++ upper = field->upper; ++ prop_name = g_strdup_printf("SYSREG_%s_%s", reg->name, field->name); ++ trace_decode_idreg_writemap(field->name, lower, upper, prop_name); ++ object_property_add(obj, prop_name, "uint64", ++ get_sysreg_prop, set_sysreg_prop, NULL, field); ++ nb_sysreg_props++; ++ ++ mask = MAKE_64BIT_MASK(lower, upper - lower + 1); ++ map = map & ~mask; ++ i = ctz64(map); ++ ++ g_free(prop_name); ++ } ++ trace_nb_sysreg_props(reg->name, nb_sysreg_props); ++ return 0; ++} ++ ++/* analyze the writable mask and generate properties for writable fields */ ++void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs) ++{ ++ int i, idx; ++ IdRegMap *map = cpu->writable_map; ++ Object *obj = OBJECT(cpu); ++ ++ for (i = 0; i < NR_ID_REGS; i++) { ++ uint64_t mask = map->regs[i]; ++ ++ if (mask) { ++ /* reg @i has some writable fields, decode them */ ++ idx = kvm_idx_to_idregs_idx(i); ++ if (idx < 0) { ++ /* no matching reg? */ ++ warn_report("%s: reg %d writable, but not in list of idregs?", ++ __func__, i); ++ } else { ++ decode_idreg_writemap(obj, i, mask, ®s[idx]); ++ } ++ } ++ } ++} ++ + bool kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf, + bool exhaustive) + { +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index e7126d1844..df8258ef34 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -282,6 +282,16 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool exhaustive); + */ + void kvm_arm_add_vcpu_properties(Object *obj); + ++typedef struct ARM64SysReg ARM64SysReg; ++/** ++ * kvm_arm_expose_idreg_properties: ++ * @cpu: The CPU object to generate the properties for ++ * @reg: registers from the host ++ * ++ * analyze the writable mask and generate properties for writable fields ++ */ ++void kvm_arm_expose_idreg_properties(ARMCPU *cpu, ARM64SysReg *regs); ++ + /** + * @cs: CPUState + * @feature: a KVM_ARM_VCPU_* feature +diff --git a/target/arm/trace-events b/target/arm/trace-events +index fe8721d66a..a5f08547a7 100644 +--- a/target/arm/trace-events ++++ b/target/arm/trace-events +@@ -12,6 +12,10 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d" + + # kvm64.c + get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64 ++decode_idreg_writemap(const char* name, int lower, int upper, char *prop_name) "%s [%d:%d] is writable (prop %s)" ++get_sysreg_prop(const char *name, uint64_t value) "%s 0x%"PRIx64 ++set_sysreg_prop(const char *name, uint64_t old, uint64_t mask, uint64_t field_value, uint64_t new) "%s old reg value=0x%"PRIx64" mask=0x%"PRIx64" new field value=0x%"PRIx64" new reg value=0x%"PRIx64 ++nb_sysreg_props(const char *name, int count) "%s: %d SYSREG properties" + + # kvm.c + kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64 +-- +2.51.0.windows.1 + diff --git a/arm-cpu-switch-to-a-generated-cpu-sysregs.h.inc.patch b/arm-cpu-switch-to-a-generated-cpu-sysregs.h.inc.patch new file mode 100644 index 00000000..bda24b07 --- /dev/null +++ b/arm-cpu-switch-to-a-generated-cpu-sysregs.h.inc.patch @@ -0,0 +1,85 @@ +From c4e3c2bb56b3e72b6b70b050fec6374c8dceac11 Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 13/26] arm/cpu: switch to a generated cpu-sysregs.h.inc + +Generated against Linux 6.15. + +Reviewed-by: Sebastian Ott +Reviewed-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-sysregs.h.inc | 43 +++++++++++++++++++++++++----------- + 1 file changed, 30 insertions(+), 13 deletions(-) + +diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc +index cb99286f70..1dddd3d357 100644 +--- a/target/arm/cpu-sysregs.h.inc ++++ b/target/arm/cpu-sysregs.h.inc +@@ -1,19 +1,10 @@ + /* SPDX-License-Identifier: GPL-2.0-or-later */ +-DEF(ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) +-DEF(ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) +-DEF(ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5) +-DEF(ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) +-DEF(ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) +-DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) +-DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1) +-DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2) +-DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0) +-DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1) +-DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2) +-DEF(ID_AA64MMFR3_EL1, 3, 0, 0, 7, 3) ++/* GENERATED FILE, DO NOT EDIT */ ++/* use arm-gen-cpu-sysregs-header.awk to regenerate */ + DEF(ID_PFR0_EL1, 3, 0, 0, 1, 0) + DEF(ID_PFR1_EL1, 3, 0, 0, 1, 1) + DEF(ID_DFR0_EL1, 3, 0, 0, 1, 2) ++DEF(ID_AFR0_EL1, 3, 0, 0, 1, 3) + DEF(ID_MMFR0_EL1, 3, 0, 0, 1, 4) + DEF(ID_MMFR1_EL1, 3, 0, 0, 1, 5) + DEF(ID_MMFR2_EL1, 3, 0, 0, 1, 6) +@@ -24,13 +15,39 @@ DEF(ID_ISAR2_EL1, 3, 0, 0, 2, 2) + DEF(ID_ISAR3_EL1, 3, 0, 0, 2, 3) + DEF(ID_ISAR4_EL1, 3, 0, 0, 2, 4) + DEF(ID_ISAR5_EL1, 3, 0, 0, 2, 5) +-DEF(ID_MMFR4_EL1, 3, 0, 0, 2, 6) + DEF(ID_ISAR6_EL1, 3, 0, 0, 2, 7) ++DEF(ID_MMFR4_EL1, 3, 0, 0, 2, 6) + DEF(MVFR0_EL1, 3, 0, 0, 3, 0) + DEF(MVFR1_EL1, 3, 0, 0, 3, 1) + DEF(MVFR2_EL1, 3, 0, 0, 3, 2) + DEF(ID_PFR2_EL1, 3, 0, 0, 3, 4) + DEF(ID_DFR1_EL1, 3, 0, 0, 3, 5) + DEF(ID_MMFR5_EL1, 3, 0, 0, 3, 6) ++DEF(ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) ++DEF(ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) ++DEF(ID_AA64PFR2_EL1, 3, 0, 0, 4, 2) + DEF(ID_AA64ZFR0_EL1, 3, 0, 0, 4, 4) ++DEF(ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5) ++DEF(ID_AA64FPFR0_EL1, 3, 0, 0, 4, 7) ++DEF(ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) ++DEF(ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) ++DEF(ID_AA64DFR2_EL1, 3, 0, 0, 5, 2) ++DEF(ID_AA64AFR0_EL1, 3, 0, 0, 5, 4) ++DEF(ID_AA64AFR1_EL1, 3, 0, 0, 5, 5) ++DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) ++DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1) ++DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2) ++DEF(ID_AA64ISAR3_EL1, 3, 0, 0, 6, 3) ++DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0) ++DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1) ++DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2) ++DEF(ID_AA64MMFR3_EL1, 3, 0, 0, 7, 3) ++DEF(ID_AA64MMFR4_EL1, 3, 0, 0, 7, 4) ++DEF(CCSIDR_EL1, 3, 1, 0, 0, 0) ++DEF(CLIDR_EL1, 3, 1, 0, 0, 1) ++DEF(CCSIDR2_EL1, 3, 1, 0, 0, 2) ++DEF(GMID_EL1, 3, 1, 0, 0, 4) ++DEF(SMIDR_EL1, 3, 1, 0, 0, 6) + DEF(CTR_EL0, 3, 3, 0, 0, 1) ++DEF(DCZID_EL0, 3, 3, 0, 0, 7) ++ +-- +2.51.0.windows.1 + diff --git a/arm-kvm-Allow-reading-all-the-writable-ID-registers.patch b/arm-kvm-Allow-reading-all-the-writable-ID-registers.patch new file mode 100644 index 00000000..ce670df6 --- /dev/null +++ b/arm-kvm-Allow-reading-all-the-writable-ID-registers.patch @@ -0,0 +1,262 @@ +From d7565b841e558598fdd94444593b5e9c735d1fc4 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 20/26] arm/kvm: Allow reading all the writable ID registers + +At the moment kvm_arm_get_host_cpu_features() reads a subset of the +ID regs. As we want to introduce properties for all writable ID reg +fields, we want more genericity and read more default host register +values. + +Introduce a new get_host_cpu_idregs() helper and add a new exhaustive +boolean parameter to kvm_arm_get_host_cpu_features() and +kvm_arm_set_cpu_features_from_host() to select the right behavior. +The host cpu model will keep the legacy behavior unless the writable +id register interface is available. + +A writable_map IdRegMap is introduced in the CPU object. A subsequent +patch will populate it. + +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu-sysregs.h | 2 ++ + target/arm/cpu.h | 5 ++- + target/arm/cpu64.c | 2 +- + target/arm/kvm.c | 4 +-- + target/arm/kvm64.c | 74 +++++++++++++++++++++++++++++++++++++++- + target/arm/kvm_arm.h | 17 ++++++--- + target/arm/trace-events | 3 ++ + 7 files changed, 98 insertions(+), 9 deletions(-) + +diff --git a/target/arm/cpu-sysregs.h b/target/arm/cpu-sysregs.h +index e89a110590..367fab51f1 100644 +--- a/target/arm/cpu-sysregs.h ++++ b/target/arm/cpu-sysregs.h +@@ -41,6 +41,8 @@ int get_sysreg_idx(ARMSysRegs sysreg); + + #ifdef CONFIG_KVM + uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg); ++int kvm_idx_to_idregs_idx(int kidx); ++int idregs_idx_to_kvm_idx(ARMIDRegisterIdx idx); + #endif + + #endif /* ARM_CPU_SYSREGS_H */ +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index a75f057430..7f174ca319 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1078,7 +1078,10 @@ struct ArchCPU { + * on KVM custom vcpu model realize + */ + ARMIdRegsState writable_id_regs; +- ++ ++ /* ID reg writable bitmask (KVM only) */ ++ IdRegMap *writable_map; ++ + /* Specify the number of cores in this CPU cluster. Used for the L2CTLR + * register. + */ +diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c +index 5ad6f77417..1a64bdf86e 100644 +--- a/target/arm/cpu64.c ++++ b/target/arm/cpu64.c +@@ -919,7 +919,7 @@ static void aarch64_host_initfn(Object *obj) + { + #if defined(CONFIG_KVM) + ARMCPU *cpu = ARM_CPU(obj); +- kvm_arm_set_cpu_features_from_host(cpu); ++ kvm_arm_set_cpu_features_from_host(cpu, false); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 50b7ccf759..895f44df18 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -173,13 +173,13 @@ void kvm_arm_destroy_scratch_host_vcpu(int *fdarray) + } + } + +-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) ++void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool exhaustive) + { + CPUARMState *env = &cpu->env; + + if (!arm_host_cpu_features.dtb_compatible) { + if (!kvm_enabled() || +- !kvm_arm_get_host_cpu_features(&arm_host_cpu_features)) { ++ !kvm_arm_get_host_cpu_features(cpu, &arm_host_cpu_features, exhaustive)) { + /* We can't report this error yet, so flag that we need to + * in arm_cpu_realizefn(). + */ +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index bdac9ef549..da9352b14d 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -27,11 +27,13 @@ + #include "sysemu/runstate.h" + #include "sysemu/kvm.h" + #include "sysemu/kvm_int.h" ++#include "trace.h" + #include "kvm_arm.h" + #include "internals.h" + #include "cpu-features.h" + #include "hw/acpi/acpi.h" + #include "hw/acpi/ghes.h" ++#include "cpu-custom.h" + + static bool have_guest_debug; + +@@ -273,7 +275,72 @@ static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf, ARMIDRegisterIdx i + return ret; + } + +-bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) ++int kvm_idx_to_idregs_idx(int kidx) ++{ ++ int op1, crm, op2; ++ ARMSysRegs sysreg; ++ ++ op1 = kidx / 64; ++ if (op1 == 2) { ++ op1 = 3; ++ } ++ crm = (kidx % 64) / 8; ++ op2 = kidx % 8; ++ sysreg = ENCODE_ID_REG(3, op1, 0, crm, op2); ++ return get_sysreg_idx(sysreg); ++} ++ ++int idregs_idx_to_kvm_idx(ARMIDRegisterIdx idx) ++{ ++ ARMSysRegs sysreg = id_register_sysreg[idx]; ++ ++ return KVM_ARM_FEATURE_ID_RANGE_IDX((sysreg & CP_REG_ARM64_SYSREG_OP0_MASK) >> CP_REG_ARM64_SYSREG_OP0_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_OP1_MASK) >> CP_REG_ARM64_SYSREG_OP1_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_CRN_MASK) >> CP_REG_ARM64_SYSREG_CRN_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_CRM_MASK) >> CP_REG_ARM64_SYSREG_CRM_SHIFT, ++ (sysreg & CP_REG_ARM64_SYSREG_OP2_MASK) >> CP_REG_ARM64_SYSREG_OP2_SHIFT); ++} ++ ++ ++/* ++ * get_host_cpu_idregs: Read all the writable ID reg host values ++ * ++ * Need to be called once the writable mask has been populated ++ * Note we may want to read all the known id regs but some of them are not ++ * writable and return an error, hence the choice of reading only those which ++ * are writable. Those are also readable! ++ */ ++static int get_host_cpu_idregs(ARMCPU *cpu, int fd, ARMHostCPUFeatures *ahcf) ++{ ++ int err = 0; ++ int i; ++ ++ for (i = 0; i < NUM_ID_IDX; i++) { ++ ARM64SysReg *sysregdesc = &arm64_id_regs[i]; ++ ARMSysRegs sysreg = sysregdesc->sysreg; ++ uint64_t writable_mask = cpu->writable_map->regs[idregs_idx_to_kvm_idx(i)]; ++ uint64_t *reg; ++ int ret; ++ ++ if (!writable_mask) { ++ continue; ++ } ++ ++ reg = &ahcf->isar.idregs[i]; ++ ret = read_sys_reg64(fd, reg, idregs_sysreg_to_kvm_reg(sysreg)); ++ trace_get_host_cpu_idregs(sysregdesc->name, *reg); ++ if (ret) { ++ error_report("%s error reading value of host %s register (%m)", ++ __func__, sysregdesc->name); ++ ++ err = ret; ++ } ++ } ++ return err; ++} ++ ++bool kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf, ++ bool exhaustive) + { + /* Identify the feature bits corresponding to the host CPU, and + * fill out the ARMHostCPUClass fields accordingly. To do this +@@ -399,6 +466,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_DFR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_MMFR5_EL1_IDX); + ++ /* Make sure writable ID reg values are read */ ++ if (exhaustive) { ++ err |= get_host_cpu_idregs(cpu, fd, ahcf); ++ } ++ + /* + * DBGDIDR is a bit complicated because the kernel doesn't + * provide an accessor for it in 64-bit mode, which is what this +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 50ae2be9c5..b82e04e25b 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -237,14 +237,18 @@ typedef struct ARMHostCPUFeatures { + + /** + * kvm_arm_get_host_cpu_features: ++ * @cpu: cpu object + * @ahcf: ARMHostCPUClass to fill in +- * ++ * @exhaustive: if true, all the feature ID regs are queried instead of ++ * a subset ++ + * Probe the capabilities of the host kernel's preferred CPU and fill + * in the ARMHostCPUClass struct accordingly. + * + * Returns true on success and false otherwise. + */ +-bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf); ++bool kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf, ++ bool exhaustive); + + /** + * kvm_arm_sve_get_vls: +@@ -262,8 +266,12 @@ uint32_t kvm_arm_sve_get_vls(CPUState *cs); + * + * Set up the ARMCPU struct fields up to match the information probed + * from the host CPU. ++ * ++ * @cpu: cpu object ++ * @exhaustive: if true, all the feature ID regs are queried instead of ++ * a subset + */ +-void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu); ++void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, bool exhaustive); + + /** + * kvm_arm_add_vcpu_properties: +@@ -511,7 +519,8 @@ static inline int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap) + /* + * These functions should never actually be called without KVM support. + */ +-static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) ++static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu, ++ bool exhaustive) + { + g_assert_not_reached(); + } +diff --git a/target/arm/trace-events b/target/arm/trace-events +index 48cc0512db..49162b87b2 100644 +--- a/target/arm/trace-events ++++ b/target/arm/trace-events +@@ -10,5 +10,8 @@ arm_gt_imask_toggle(int timer) "gt_ctl_write: timer %d IMASK toggle" + arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64 + arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d" + ++# kvm64.c ++get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value for %s is 0x%"PRIx64 ++ + # kvm.c + kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64 +-- +2.51.0.windows.1 + diff --git a/arm-kvm-use-fd-instead-of-fdarray-2.patch b/arm-kvm-use-fd-instead-of-fdarray-2.patch new file mode 100644 index 00000000..400b5f5d --- /dev/null +++ b/arm-kvm-use-fd-instead-of-fdarray-2.patch @@ -0,0 +1,45 @@ +From e682560920b662fd73c00bea4fd3ca47fe8433df Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 14/26] arm/kvm: use fd instead of fdarray[2] + +We have fd, so might as well neaten things up. + +Suggested-by: Eric Auger +Reviewed-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/kvm64.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 4e184fe1d5..bdac9ef549 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -389,11 +389,11 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + err |= get_host_cpu_reg(fd, ahcf, ID_ISAR6_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_MMFR4_EL1_IDX); + +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr0, ++ err |= read_sys_reg32(fd, &ahcf->isar.mvfr0, + ARM64_SYS_REG(3, 0, 0, 3, 0)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr1, ++ err |= read_sys_reg32(fd, &ahcf->isar.mvfr1, + ARM64_SYS_REG(3, 0, 0, 3, 1)); +- err |= read_sys_reg32(fdarray[2], &ahcf->isar.mvfr2, ++ err |= read_sys_reg32(fd, &ahcf->isar.mvfr2, + ARM64_SYS_REG(3, 0, 0, 3, 2)); + err |= get_host_cpu_reg(fd, ahcf, ID_PFR2_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_DFR1_EL1_IDX); +@@ -431,7 +431,7 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) + + if (pmu_supported) { + /* PMCR_EL0 is only accessible if the vCPU has feature PMU_V3 */ +- err |= read_sys_reg64(fdarray[2], &ahcf->isar.reset_pmcr_el0, ++ err |= read_sys_reg64(fd, &ahcf->isar.reset_pmcr_el0, + KVM_REG_ARM_PMCR_EL0); + } + +-- +2.51.0.windows.1 + diff --git a/arm-kvm-write-back-modified-ID-regs-to-KVM.patch b/arm-kvm-write-back-modified-ID-regs-to-KVM.patch new file mode 100644 index 00000000..bdabbadc --- /dev/null +++ b/arm-kvm-write-back-modified-ID-regs-to-KVM.patch @@ -0,0 +1,142 @@ +From 05c35d0d6e7b778563e1aa4f624f8472c814e285 Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 21/26] arm/kvm: write back modified ID regs to KVM + +We want to give a chance to override the value of host ID regs. +In a previous patch we made sure all their values could be fetched +through kvm_get_one_reg() calls before their modification. After +their potential modification we need to make sure we write back +the values through kvm_set_one_reg() calls. + +Make sure the cpreg_list is modified with updated values and +transfer those values back to kvm. + +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/kvm.c | 34 ++++++++++++++++++++++++++++++++++ + target/arm/kvm64.c | 13 +++++++++++-- + target/arm/kvm_arm.h | 6 ++++++ + target/arm/trace-events | 1 + + 4 files changed, 52 insertions(+), 2 deletions(-) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 895f44df18..1b5bd85e77 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -23,6 +23,7 @@ + #include "sysemu/kvm_int.h" + #include "kvm_arm.h" + #include "cpu.h" ++#include "cpu-custom.h" + #include "cpu-sysregs.h" + #include "trace.h" + #include "internals.h" +@@ -798,6 +799,39 @@ static void kvm_arm_configure_vcpu_regs(ARMCPU *cpu) + kvm_arm_configure_pmcr(cpu); + } + ++void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu) ++{ ++ if (!cpu->writable_map) { ++ return; ++ } ++ for (int i = 0; i < NR_ID_REGS; i++) { ++ uint64_t writable_mask = cpu->writable_map->regs[i]; ++ uint64_t *cpreg; ++ ++ if (writable_mask) { ++ uint64_t previous, new; ++ int idx = kvm_idx_to_idregs_idx(i); ++ ARM64SysReg *sysregdesc; ++ uint32_t sysreg; ++ ++ if (idx == -1) { ++ /* sysreg writable, but we don't know it */ ++ continue; ++ } ++ sysregdesc = &arm64_id_regs[idx]; ++ sysreg = sysregdesc->sysreg; ++ cpreg = kvm_arm_get_cpreg_ptr(cpu, idregs_sysreg_to_kvm_reg(sysreg)); ++ previous = *cpreg; ++ new = cpu->isar.idregs[idx]; ++ if (previous != new) { ++ *cpreg = new; ++ trace_kvm_arm_writable_idregs_to_cpreg_list(sysregdesc->name, ++ previous, new); ++ } ++ } ++ } ++} ++ + void kvm_arm_reset_vcpu(ARMCPU *cpu) + { + int ret; +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index da9352b14d..be9233f936 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -470,7 +470,7 @@ bool kvm_arm_get_host_cpu_features(ARMCPU *cpu, ARMHostCPUFeatures *ahcf, + if (exhaustive) { + err |= get_host_cpu_idregs(cpu, fd, ahcf); + } +- ++ + /* + * DBGDIDR is a bit complicated because the kernel doesn't + * provide an accessor for it in 64-bit mode, which is what this +@@ -757,7 +757,16 @@ int kvm_arch_init_vcpu(CPUState *cs) + /* Check whether user space can specify guest syndrome value */ + kvm_arm_init_serror_injection(cs); + +- return kvm_arm_init_cpreg_list(cpu); ++ ret = kvm_arm_init_cpreg_list(cpu); ++ if (ret) { ++ return ret; ++ } ++ /* overwrite writable ID regs with their updated property values */ ++ kvm_arm_writable_idregs_to_cpreg_list(cpu); ++ ++ write_list_to_kvmstate(cpu, 3); ++ ++ return 0; + } + + int kvm_arch_destroy_vcpu(CPUState *cs) +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index b82e04e25b..e7126d1844 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -471,6 +471,8 @@ Object *kvm_arm_rme_get_measurement_log(void); + + int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap); + ++void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu); ++ + #else + + /* +@@ -516,6 +518,10 @@ static inline int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap) + return -ENOSYS; + } + ++void kvm_arm_writable_idregs_to_cpreg_list(ARMCPU *cpu) ++{ ++ g_assert_not_reached(); ++} + /* + * These functions should never actually be called without KVM support. + */ +diff --git a/target/arm/trace-events b/target/arm/trace-events +index 49162b87b2..fe8721d66a 100644 +--- a/target/arm/trace-events ++++ b/target/arm/trace-events +@@ -15,3 +15,4 @@ get_host_cpu_idregs(const char *name, uint64_t value) "scratch vcpu host value f + + # kvm.c + kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64 ++kvm_arm_writable_idregs_to_cpreg_list(const char *name, uint64_t previous, uint64_t new) "%s overwrite default 0x%"PRIx64" with 0x%"PRIx64 +-- +2.51.0.windows.1 + diff --git a/arm-qmp-cmds-introspection-for-ID-register-props.patch b/arm-qmp-cmds-introspection-for-ID-register-props.patch new file mode 100644 index 00000000..be603b71 --- /dev/null +++ b/arm-qmp-cmds-introspection-for-ID-register-props.patch @@ -0,0 +1,66 @@ +From 0e3658b3adef452d8b21c08bbe0944b837549eeb Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 23/26] arm-qmp-cmds: introspection for ID register props + +Implement the capability to query available ID register values by +adding SYSREG_* options and values to the cpu model expansion for the +host model, if available. + +Excerpt: +(QEMU) query-cpu-model-expansion type=full model={"name":"host"} +{"return": {"model": {"name": "host", "props": +{"SYSREG_ID_AA64PFR0_EL1_EL3": 1224979098931106066, +"SYSREG_ID_AA64ISAR2_EL1_CLRBHB": 0, +../.. + +So this allows the upper stack to detect available writable ID +regs and the "host passthrough model" values. + +[CH: moved SYSREG_* values to host model] +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/arm-qmp-cmds.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c +index d201d319bd..5109aeb873 100644 +--- a/target/arm/arm-qmp-cmds.c ++++ b/target/arm/arm-qmp-cmds.c +@@ -21,6 +21,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/error-report.h" + #include "hw/boards.h" + #include "kvm_arm.h" + #include "qapi/error.h" +@@ -218,6 +219,24 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, + } + } + ++ /* If writable ID regs are supported, add them as well */ ++ if (ARM_CPU(obj)->writable_id_regs == WRITABLE_ID_REGS_AVAIL) { ++ ObjectProperty *prop; ++ ObjectPropertyIterator iter; ++ ++ object_property_iter_init(&iter, obj); ++ ++ while ((prop = object_property_iter_next(&iter))) { ++ QObject *value; ++ ++ if (!g_str_has_prefix(prop->name, "SYSREG_")) { ++ continue; ++ } ++ value = object_property_get_qobject(obj, prop->name, &error_abort); ++ qdict_put_obj(qdict_out, prop->name, value); ++ } ++ } ++ + if (!qdict_size(qdict_out)) { + qobject_unref(qdict_out); + } else { +-- +2.51.0.windows.1 + diff --git a/hw-arm-virt-Initial-support-to-set-target_impl-CPUs.patch b/hw-arm-virt-Initial-support-to-set-target_impl-CPUs.patch new file mode 100644 index 00000000..5c60c055 --- /dev/null +++ b/hw-arm-virt-Initial-support-to-set-target_impl-CPUs.patch @@ -0,0 +1,256 @@ +From 5f8bb127fc2f7c693cf8e75da68338402cbfbe63 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 2/4] hw/arm/virt: Initial support to set target_impl CPUs + +This is a hacked interface to test the kernel. + +Usage Eg: +-machine virt,.., x-target-impl-cpus=0xMIDR1:0xREVIDR1-0xMIDR2:REVIDR2 + +The HVC/SMC hypercall exit handling part is loosly based on this patch, +https://lore.kernel.org/qemu-devel/20240614001510.202991-1-salil.mehta@huawe... + +Signed-off-by: Shameer Kolothum +--- + hw/arm/virt.c | 65 ++++++++++++++++++++++++++++++++++++++- + include/hw/boards.h | 3 ++ + target/arm/kvm.c | 72 +++++++++++++++++++++++++++++++++++++++++--- + target/arm/kvm_arm.h | 6 ++++ + 4 files changed, 140 insertions(+), 6 deletions(-) + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index f7a9ba9a58..e046fff5dd 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -29,6 +29,7 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/cutils.h" + #include "qemu/datadir.h" + #include "qemu/units.h" + #include "qemu/option.h" +@@ -3103,6 +3104,62 @@ static void virt_set_oem_table_id(Object *obj, const char *value, + strncpy(vms->oem_table_id, value, 8); + } + ++static TargetImplCpu target_impl_cpus[MAX_TARGET_IMPL_CPUS]; ++ ++static void virt_set_target_impl_cpus(Object *obj, const char *value, ++ Error **errp) ++{ ++ MachineState *ms = MACHINE(obj); ++ g_autofree char *target_dup = g_strdup(value); ++ char *target_impl = strtok(target_dup, "-"); ++ int cnt = 0; ++ ++ while (target_impl) { ++ char num[16]; ++ long val; ++ const char *num_start = target_impl; ++ const char *num_end = strchr(num_start, ':'); ++ ++ if (!num_end) { ++ error_setg(errp, ++ "Wrong format, Please use 0xmidr:0xrevid-0xmidr:0xrevid"); ++ return; ++ } ++ ++ strncpy(num, num_start, num_end - num_start); ++ num[num_end - num_start] = '\0'; ++ if (qemu_strtol(num, NULL, 16, &val)) { ++ error_setg(errp, ++ "Wrong format, Please use 0xmidr:0xrevid-0xmidr:0xrevid"); ++ return; ++ } ++ target_impl_cpus[cnt].midr = val; ++ num_start = num_end + 1; ++ if (!(*num_start)) { ++ error_setg(errp, ++ "Wrong format, Please use 0xmidr:0xrevid-0xmidr:0xrevid"); ++ return; ++ } ++ ++ strncpy(num, num_start, sizeof(num) - 1); ++ num[sizeof(num) - 1] = '\0'; ++ if (qemu_strtol(num, NULL, 16, &val)) { ++ error_setg(errp, ++ "Wrong format, Please use 0xmidr:0xrevid-0xmidr:0xrevid"); ++ return; ++ } ++ target_impl_cpus[cnt].revidr = val; ++ cnt++; ++ if (cnt >= MAX_TARGET_IMPL_CPUS) { ++ error_setg(errp, ++ "Wrong format, Max %d targets can be set for now!", MAX_TARGET_IMPL_CPUS); ++ return; ++ } ++ target_impl = strtok(NULL, "-"); ++ } ++ ms->target_ipml_cpu_num = cnt; ++ ms->target_ipml_cpu = target_impl_cpus; ++} + + bool virt_is_acpi_enabled(VirtMachineState *vms) + { +@@ -4085,7 +4142,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + "Override the default value of field OEM Table ID " + "in ACPI table header." + "The string may be up to 8 bytes in size"); +- ++ ++ object_class_property_add_str(oc, "x-target-impl-cpus", ++ NULL, ++ virt_set_target_impl_cpus); ++ object_class_property_set_description(oc, "x-target-impl-cpus", ++ "Describe target cpu impl in the format midr1:revidr1-midr2:revidr2" ++ "Maximum 4 midr:revidr pair is supported"); + } + + static char *virt_get_kvm_type(Object *obj, Error **errp G_GNUC_UNUSED) +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 8ac8cad2a2..192dc7dc09 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -402,6 +402,9 @@ struct MachineState { + CpuTopology smp; + struct NVDIMMState *nvdimms_state; + struct NumaState *numa_state; ++ ++ uint32_t target_ipml_cpu_num; ++ void *target_ipml_cpu; + }; + + #define DEFINE_MACHINE(namestr, machine_initfn) \ +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 52fb1b0919..3ecb1f339a 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -59,7 +59,7 @@ + #define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER 64 + #define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS 65 + +-#define ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0 0x10000 ++#define ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0 0x100000000 + + #define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ +@@ -440,6 +440,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) + if (ret) { + error_report("Failed to enable RME: %s", strerror(-ret)); + } ++ ++ if (kvm_arm_set_smccc_filter(ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_VER_FUNC_ID, ++ KVM_SMCCC_FILTER_FWD_TO_USER)) { ++ error_report("ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER fwd filter install failed"); ++ } ++ ++ if (kvm_arm_set_smccc_filter(ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_CPUS_FUNC_ID, ++ KVM_SMCCC_FILTER_FWD_TO_USER)) { ++ error_report("ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS fwd filter install failed"); ++ } + + return ret; + } +@@ -1178,6 +1188,55 @@ void kvm_arm_vm_state_change(void *opaque, bool running, RunState state) + } + } + ++static bool arm_handle_smcc_kvm_vendor_hypercall(ARMCPU *cpu) ++{ ++ MachineState *ms = MACHINE(qdev_get_machine()); ++ CPUARMState *env = &cpu->env; ++ uint64_t param[4]; ++ int idx; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ /* ++ * All PSCI functions take explicit 32-bit or native int sized ++ * arguments so we can simply zero-extend all arguments regardless ++ * of which exact function we are about to call. ++ */ ++ param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; ++ } ++ ++ if (is_a64(env)) { ++ TargetImplCpu *target = ms->target_ipml_cpu; ++ ++ switch (param[0]) { ++ case ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_VER_FUNC_ID: ++ if (!ms->target_ipml_cpu_num) { ++ env->xregs[0] = SMCCC_RET_NOT_SUPPORTED; ++ break; ++ } ++ env->xregs[0] = SMCCC_RET_SUCCESS; ++ env->xregs[1] = ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0; ++ env->xregs[2] = ms->target_ipml_cpu_num; ++ break; ++ case ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_CPUS_FUNC_ID: ++ idx = param[1]; ++ if (idx >= ms->target_ipml_cpu_num) { ++ env->xregs[0] = SMCCC_RET_INVALID_PARAMETER; ++ break; ++ } ++ env->xregs[0] = SMCCC_RET_SUCCESS; ++ env->xregs[1] = target[idx].midr; ++ env->xregs[2] = target[idx].revidr; ++ break; ++ default: ++ return false; ++ } ++ } else { ++ return false; ++ } ++ return true; ++} ++ + /** + * kvm_arm_handle_dabt_nisv: + * @cs: CPUState +@@ -1240,9 +1299,12 @@ static int kvm_arm_handle_hypercall(CPUState *cs, struct kvm_run *run) + env->exception.syndrome = syn_aa64_hvc(0); + } + env->exception.target_el = 1; +- qemu_mutex_lock_iothread(); +- arm_cpu_do_interrupt(cs); +- qemu_mutex_unlock_iothread(); ++ ++ if (!arm_handle_smcc_kvm_vendor_hypercall(cpu)) { ++ qemu_mutex_lock_iothread(); ++ arm_cpu_do_interrupt(cs); ++ qemu_mutex_unlock_iothread(); ++ } + + /* + * For PSCI, exit the kvm_run loop and process the work. Especially +@@ -1267,7 +1329,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) + run->arm_nisv.fault_ipa); + break; + case KVM_EXIT_HYPERCALL: +- ret = kvm_arm_handle_hypercall(cs, run); ++ ret = kvm_arm_handle_hypercall(cs, run); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index df8258ef34..8c69957fbf 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -21,6 +21,12 @@ + #define KVM_REG_ARM_ID_AA64DFR0_EL1 ARM64_SYS_REG(3, 0, 0, 5, 0) + #define KVM_REG_ARM_PMCR_EL0 ARM64_SYS_REG(3, 3, 9, 12, 0) + ++#define MAX_TARGET_IMPL_CPUS 8 ++typedef struct TargetImplCpu { ++ uint32_t midr; ++ uint32_t revidr; ++} TargetImplCpu; ++ + /** + * kvm_arm_init_debug() - initialize guest debug capabilities + * @s: KVMState +-- +2.51.0.windows.1 + diff --git a/kvm-kvm_get_writable_id_regs.patch b/kvm-kvm_get_writable_id_regs.patch new file mode 100644 index 00000000..669a4f79 --- /dev/null +++ b/kvm-kvm_get_writable_id_regs.patch @@ -0,0 +1,139 @@ +From 39c606cce1f67508c36985ada072b3a4688794da Mon Sep 17 00:00:00 2001 +From: Cornelia Huck +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 18/26] kvm: kvm_get_writable_id_regs + +Add an helper to retrieve the writable id reg bitmask. The +status of the query is stored in the CPU struct so that an +an error, if any, can be reported on vcpu realize(). + +Signed-off-by: Eric Auger +Signed-off-by: Cornelia Huck +--- + target/arm/cpu.h | 26 ++++++++++++++++++++++++++ + target/arm/kvm.c | 32 ++++++++++++++++++++++++++++++++ + target/arm/kvm_arm.h | 7 +++++++ + 3 files changed, 65 insertions(+) + +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 2c8f2ffd45..3f57363baf 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -846,6 +846,26 @@ typedef struct { + uint32_t map, init, supported; + } ARMVQMap; + ++typedef enum ARMIdRegsState { ++ WRITABLE_ID_REGS_UNKNOWN, ++ WRITABLE_ID_REGS_NOT_DISCOVERABLE, ++ WRITABLE_ID_REGS_FAILED, ++ WRITABLE_ID_REGS_AVAIL, ++} ARMIdRegsState; ++ ++/* ++ * The following structures are for the purpose of mapping the output of ++ * KVM_ARM_GET_REG_WRITABLE_MASKS that also may cover id registers we do ++ * not support in QEMU ++ * ID registers in op0==3, op1=={0,1,3}, crn=0, crm=={0-7}, op2=={0-7}, ++ * as used by the KVM_ARM_GET_REG_WRITABLE_MASKS ioctl call. ++ */ ++#define NR_ID_REGS (3 * 8 * 8) ++ ++typedef struct IdRegMap { ++ uint64_t regs[NR_ID_REGS]; ++} IdRegMap; ++ + /* REG is ID_XXX */ + #define FIELD_DP64_IDREG(ISAR, REG, FIELD, VALUE) \ + ({ \ +@@ -1035,6 +1055,12 @@ struct ArchCPU { + */ + bool host_cpu_probe_failed; + ++ /* ++ * state of writable id regs query used to report an error, if any, ++ * on KVM custom vcpu model realize ++ */ ++ ARMIdRegsState writable_id_regs; ++ + /* Specify the number of cores in this CPU cluster. Used for the L2CTLR + * register. + */ +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index c6c92c120f..50b7ccf759 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -43,6 +43,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + static bool cap_has_mp_state; + static bool cap_has_inject_serror_esr; + static bool cap_has_inject_ext_dabt; ++static int cap_writable_id_regs; + + static ARMHostCPUFeatures arm_host_cpu_features; + +@@ -194,6 +195,37 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) + env->features = arm_host_cpu_features.features; + } + ++int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap) ++{ ++ struct reg_mask_range range = { ++ .range = 0, /* up to now only a single range is supported */ ++ .addr = (uint64_t)idregmap, ++ }; ++ int ret; ++ ++ if (!kvm_enabled()) { ++ cpu->writable_id_regs = WRITABLE_ID_REGS_NOT_DISCOVERABLE; ++ return -ENOSYS; ++ } ++ ++ cap_writable_id_regs = ++ kvm_check_extension(kvm_state, KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES); ++ ++ if (!cap_writable_id_regs || ++ !(cap_writable_id_regs & (1 << KVM_ARM_FEATURE_ID_RANGE))) { ++ cpu->writable_id_regs = WRITABLE_ID_REGS_NOT_DISCOVERABLE; ++ return -ENOSYS; ++ } ++ ++ ret = kvm_vm_ioctl(kvm_state, KVM_ARM_GET_REG_WRITABLE_MASKS, &range); ++ if (ret) { ++ cpu->writable_id_regs = WRITABLE_ID_REGS_FAILED; ++ return ret; ++ } ++ cpu->writable_id_regs = WRITABLE_ID_REGS_AVAIL; ++ return ret; ++} ++ + static bool kvm_no_adjvtime_get(Object *obj, Error **errp) + { + return !ARM_CPU(obj)->kvm_adjvtime; +diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h +index 8e9b2039c4..50ae2be9c5 100644 +--- a/target/arm/kvm_arm.h ++++ b/target/arm/kvm_arm.h +@@ -461,6 +461,8 @@ void kvm_arm_rme_init_gpa_space(hwaddr highest_gpa, PCIBus *pci_bus); + */ + Object *kvm_arm_rme_get_measurement_log(void); + ++int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap); ++ + #else + + /* +@@ -501,6 +503,11 @@ static inline Object *kvm_arm_rme_get_measurement_log(void) + return NULL; + } + ++static inline int kvm_arm_get_writable_id_regs(ARMCPU *cpu, IdRegMap *idregmap) ++{ ++ return -ENOSYS; ++} ++ + /* + * These functions should never actually be called without KVM support. + */ +-- +2.51.0.windows.1 + diff --git a/qemu.spec b/qemu.spec index c3d6bf48..c80045ca 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 48 +Release: 49 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1101,6 +1101,39 @@ Patch1084: hw-usb-hcd-xhci-Unmap-canceled-packet.patch Patch1085: meson-Use-has_header_symbol-to-check-getcpu.patch Patch1086: hw-intc-arm_gicv3_cpuif-Don-t-downgrade-monitor-trap.patch Patch1087: migration-fix-SEEK_CUR-offset-calculation-in-qio_cha.patch +Patch1088: Revert-hw-arm-virt-Introduce-a-IPIV-machine-option.patch +Patch1089: target-arm-add-ipiv-on-off-option.patch +Patch1090: arm-cpu-Add-sysreg-definitions-in-cpu-sysregs.h.patch +Patch1091: arm-cpu-Store-aa64isar0-aa64zfr0-into-the-idregs-arr.patch +Patch1092: arm-cpu-Store-aa64isar1-2-into-the-idregs-array.patch +Patch1093: arm-cpu-Store-aa64pfr0-1-into-the-idregs-array.patch +Patch1094: arm-cpu-Store-aa64mmfr0-2-into-the-idregs-array.patch +Patch1095: arm-cpu-Store-aa64dfr0-1-into-the-idregs-array.patch +Patch1096: arm-cpu-Store-aa64smfr0-into-the-idregs-array.patch +Patch1097: arm-cpu-Store-id_isar0-7-into-the-idregs-array.patch +Patch1098: arm-cpu-Store-id_pfr0-1-2-into-the-idregs-array.patch +Patch1099: arm-cpu-Store-id_dfr0-1-into-the-idregs-array.patch +Patch1100: arm-cpu-Store-id_mmfr0-5-into-the-idregs-array.patch +Patch1101: arm-cpu-Add-sysreg-generation-scripts.patch +Patch1102: arm-cpu-switch-to-a-generated-cpu-sysregs.h.inc.patch +Patch1103: arm-kvm-use-fd-instead-of-fdarray-2.patch +Patch1104: arm-cpu-Add-infra-to-handle-generated-ID-register-de.patch +Patch1105: arm-cpu-Add-sysreg-properties-generation.patch +Patch1106: arm-cpu-Add-generated-sysreg-properties.patch +Patch1107: kvm-kvm_get_writable_id_regs.patch +Patch1108: arm-cpu-accessors-for-writable-id-registers.patch +Patch1109: arm-kvm-Allow-reading-all-the-writable-ID-registers.patch +Patch1110: arm-kvm-write-back-modified-ID-regs-to-KVM.patch +Patch1111: arm-cpu-more-customization-for-the-kvm-host-cpu-mode.patch +Patch1112: arm-qmp-cmds-introspection-for-ID-register-props.patch +Patch1113: arm-cpu-features-document-ID-reg-properties.patch +Patch1114: arm-cpu-manually-make-MIDR-REVIDR-AIDR-writable.patch +Patch1115: arm-cpu-enable-MIDR-writable.patch +Patch1116: target-arm-kvm-Add-SMMC-hypercall-definitions.patch +Patch1117: hw-arm-virt-Initial-support-to-set-target_impl-CPUs.patch +Patch1118: target-arm-kvm-Use-PSCI_VERSIOn-for-version-info.patch +Patch1119: target-arm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch +Patch1120: Fix-the-compilation-of-target-arm-softmmu.patch BuildRequires: flex BuildRequires: gcc @@ -1699,6 +1732,46 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Thu Oct 30 2025 Pengrui Zhang - 11:8.2.0-49 +- Revert "hw/arm/virt: Introduce a IPIV machine option" +- target/arm: add ipiv=on/off option +- arm/cpu: Add sysreg definitions in cpu-sysregs.h +- arm/cpu: Store aa64isar0/aa64zfr0 into the idregs arrays +- arm/cpu: Store aa64isar1/2 into the idregs array +- arm/cpu: Store aa64pfr0/1 into the idregs array +- arm/cpu: Store aa64mmfr0-2 into the idregs array +- arm/cpu: Store aa64dfr0/1 into the idregs array +- arm/cpu: Store aa64smfr0 into the idregs array +- arm/cpu: Store id_isar0-7 into the idregs array +- arm/cpu: Store id_pfr0/1/2 into the idregs array +- arm/cpu: Store id_dfr0/1 into the idregs array +- arm/cpu: Store id_mmfr0-5 into the idregs array +- arm/cpu: Add generated sysreg properties +- arm/cpu: Add sysreg properties generation +- arm/cpu: Add infra to handle generated ID register definitions +- kvm: kvm_get_writable_id_regs +- arm/kvm: use fd instead of fdarray[2] +- arm/cpu: switch to a generated cpu-sysregs.h.inc +- arm/cpu: Add sysreg generation scripts +- arm/cpu: Store aa64dfr0/1 into the idregs array +- arm/cpu: Store aa64mmfr0-2 into the idregs array +- arm/cpu: Store aa64pfr0/1 into the idregs array +- arm/cpu: Store aa64isar1/2 into the idregs array +- arm/cpu: Store aa64isar0/aa64zfr0 into the idregs arrays +- arm/cpu: Add sysreg definitions in cpu-sysregs.h +- arm/cpu: more customization for the kvm host cpu model +- arm/kvm: write back modified ID regs to KVM +- arm/kvm: Allow reading all the writable ID registers +- arm/cpu-features: document ID reg properties +- arm/qmp-cmds: introspection for ID register props +- arm/cpu: manually make MIDR/REVIDR/AIDR writable +- arm/cpu: enable MIDR writable +- target/arm/kvm: Add SMMC hypercall definitions +- hw/arm/virt: Initial support to set target_impl CPUs +- target/arm/kvm: Use PSCI_VERSION for version info +- target/arm/kvm: Set DISCOVER_IMPL_* hypercalls +- Fix the compilation of target arm-softmmu + * Fri Oct 24 2025 Pengrui Zhang - 11:8.2.0-48 - common-user/host/riscv: use tail pseudoinstruction for calling tail - meson: Remove CONFIG_STATX and CONFIG_STATX_MNT_ID diff --git a/target-arm-add-ipiv-on-off-option.patch b/target-arm-add-ipiv-on-off-option.patch new file mode 100644 index 00000000..d69e4a3c --- /dev/null +++ b/target-arm-add-ipiv-on-off-option.patch @@ -0,0 +1,78 @@ +From 4168f996acf21b0ecfe34d42756bed3be49e9853 Mon Sep 17 00:00:00 2001 +From: Jinqian Yang +Date: Mon, 20 Oct 2025 16:06:52 +0800 +Subject: [PATCH] target/arm: add ipiv=on/off option + +If IPIV is required to be enabled on the virtual machine, must add +`-accel kvm,ipiv=on`. Adding the IPIV switch in QEMU ensures that +the guest's IPIV can be flexibly disabled in certain scenarios, +such as cross-generation live migration. + +Signed-off-by: Jinqian Yang +--- + include/sysemu/kvm_int.h | 1 + + target/arm/kvm.c | 24 ++++++++++++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h +index 9a7bc1a4b8..7b90117a86 100644 +--- a/include/sysemu/kvm_int.h ++++ b/include/sysemu/kvm_int.h +@@ -122,6 +122,7 @@ struct KVMState + uint32_t xen_caps; + uint16_t xen_gnttab_max_frames; + uint16_t xen_evtchn_max_pirq; ++ bool ipiv; + }; + + void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index f45783a9da..599c2c2462 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -263,6 +263,10 @@ static void kvm_update_ipiv_cap(KVMState *s) + { + int ret; + ++ if (!s->ipiv) { ++ return; ++ } ++ + if (!kvm_check_extension(s, KVM_CAP_ARM_HISI_IPIV)) { + return; + } +@@ -1364,6 +1368,20 @@ static void kvm_arch_set_eager_split_size(Object *obj, Visitor *v, + s->kvm_eager_split_size = value; + } + ++static bool virt_get_ipiv(Object *obj, Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ ++ return s->ipiv; ++} ++ ++static void virt_set_ipiv(Object *obj, bool value, Error **errp) ++{ ++ KVMState *s = KVM_STATE(obj); ++ ++ s->ipiv = value; ++} ++ + void kvm_arch_accel_class_init(ObjectClass *oc) + { + object_class_property_add(oc, "eager-split-size", "size", +@@ -1372,4 +1390,10 @@ void kvm_arch_accel_class_init(ObjectClass *oc) + + object_class_property_set_description(oc, "eager-split-size", + "Eager Page Split chunk size for hugepages. (default: 0, disabled)"); ++ ++ object_class_property_add_bool(oc, "ipiv", ++ virt_get_ipiv, ++ virt_set_ipiv); ++ object_class_property_set_description(oc, "ipiv", ++ "Set on/off to enable/disable IPIV"); + } +-- +2.33.0 + diff --git a/target-arm-kvm-Add-SMMC-hypercall-definitions.patch b/target-arm-kvm-Add-SMMC-hypercall-definitions.patch new file mode 100644 index 00000000..521a54af --- /dev/null +++ b/target-arm-kvm-Add-SMMC-hypercall-definitions.patch @@ -0,0 +1,73 @@ +From f61060d0f0b00ac94da535b72f4f62cfc5808fb6 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 1/4] target/arm/kvm: Add SMMC hypercall definitions + +ToDo: Do it properly using update-linux-headers.sh + +Signed-off-by: Shameer Kolothum +--- + target/arm/kvm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 1b5bd85e77..52fb1b0919 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -37,6 +37,53 @@ + #include "qapi/visitor.h" + #include "qemu/log.h" + ++/* ++ * SMMCC KVM Vendor hypercall definitions. ++ * ToDo: Include using update-linux-headers.sh ++ */ ++#define ARM_SMCCC_FAST_CALL _AC(1,U) ++#define ARM_SMCCC_TYPE_SHIFT 31 ++ ++#define ARM_SMCCC_SMC_32 0 ++#define ARM_SMCCC_SMC_64 1 ++#define ARM_SMCCC_CALL_CONV_SHIFT 30 ++ ++#define ARM_SMCCC_OWNER_MASK 0x3F ++#define ARM_SMCCC_OWNER_SHIFT 24 ++ ++#define ARM_SMCCC_FUNC_MASK 0xFFFF ++ ++#define ARM_SMCCC_OWNER_VENDOR_HYP 6 ++ ++ ++#define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER 64 ++#define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS 65 ++ ++#define ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0 0x10000 ++ ++#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ ++ (((type) << ARM_SMCCC_TYPE_SHIFT) | \ ++ ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ ++ (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \ ++ ((func_num) & ARM_SMCCC_FUNC_MASK)) ++ ++#define ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_VER_FUNC_ID \ ++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ ++ ARM_SMCCC_SMC_64, \ ++ ARM_SMCCC_OWNER_VENDOR_HYP, \ ++ ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER) ++ ++#define ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_CPUS_FUNC_ID \ ++ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ ++ ARM_SMCCC_SMC_64, \ ++ ARM_SMCCC_OWNER_VENDOR_HYP, \ ++ ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS) ++ ++#define SMCCC_RET_SUCCESS 0 ++#define SMCCC_RET_NOT_SUPPORTED -1 ++#define SMCCC_RET_NOT_REQUIRED -2 ++#define SMCCC_RET_INVALID_PARAMETER -3 ++ + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; +-- +2.51.0.windows.1 + diff --git a/target-arm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch b/target-arm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch new file mode 100644 index 00000000..2959f373 --- /dev/null +++ b/target-arm-kvm-Set-DISCOVER_IMPL_-hypercalls.patch @@ -0,0 +1,40 @@ +From 6daafff5667ac443411ad948343cc83fe15b3741 Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 4/4] target/arm/kvm: Set DISCOVER_IMPL_* hypercalls + +Signed-off-by: Shameer Kolothum +--- + target/arm/kvm64.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 7e0ca919b2..7614194998 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -795,6 +795,14 @@ static int kvm_arm_sve_set_vls(CPUState *cs) + return kvm_set_one_reg(cs, KVM_REG_ARM64_SVE_VLS, &vls[0]); + } + ++static int kvm_arm_set_vend_hyp_bmap_2(ARMCPU *cpu) ++{ ++ /* Set DISCOVER_IMPL_* hypercalls */ ++ uint64_t bmap_2 = MAKE_64BIT_MASK(0, 2); ++ ++ return kvm_set_one_reg(CPU(cpu), KVM_REG_ARM_VENDOR_HYP_BMAP_2, &bmap_2); ++} ++ + #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 + + int kvm_arch_init_vcpu(CPUState *cs) +@@ -871,6 +879,7 @@ int kvm_arch_init_vcpu(CPUState *cs) + } + } + ++ kvm_arm_set_vend_hyp_bmap_2(cpu); + /* + * KVM reports the exact PSCI version it is implementing via a + * special sysreg. If it is present, use its contents to determine +-- +2.51.0.windows.1 + diff --git a/target-arm-kvm-Use-PSCI_VERSIOn-for-version-info.patch b/target-arm-kvm-Use-PSCI_VERSIOn-for-version-info.patch new file mode 100644 index 00000000..fd8d7d6d --- /dev/null +++ b/target-arm-kvm-Use-PSCI_VERSIOn-for-version-info.patch @@ -0,0 +1,35 @@ +From b79e70a8a53b13ba9eeb049cedd55ff0a8eeacce Mon Sep 17 00:00:00 2001 +From: Shameer Kolothum +Date: Thu, 4 Sep 2025 16:28:48 +0800 +Subject: [PATCH 3/4] target/arm/kvm: Use PSCI_VERSIOn for version info + +Signed-off-by: Shameer Kolothum +--- + target/arm/kvm.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/target/arm/kvm.c b/target/arm/kvm.c +index 3ecb1f339a..50f22717ec 100644 +--- a/target/arm/kvm.c ++++ b/target/arm/kvm.c +@@ -59,8 +59,6 @@ + #define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_VER 64 + #define ARM_SMCCC_KVM_FUNC_DISCOVER_IMPL_CPUS 65 + +-#define ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0 0x100000000 +- + #define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \ + (((type) << ARM_SMCCC_TYPE_SHIFT) | \ + ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \ +@@ -1215,7 +1213,7 @@ static bool arm_handle_smcc_kvm_vendor_hypercall(ARMCPU *cpu) + break; + } + env->xregs[0] = SMCCC_RET_SUCCESS; +- env->xregs[1] = ARM_SMCCC_KVM_DISCOVER_IMPL_VER_1_0; ++ env->xregs[1] = PSCI_VERSION(1, 0); + env->xregs[2] = ms->target_ipml_cpu_num; + break; + case ARM_SMCCC_VENDOR_HYP_KVM_DISCOVER_IMPL_CPUS_FUNC_ID: +-- +2.51.0.windows.1 + -- Gitee From 8cf5995b5325de11843ad75f9fc6b646610a2e89 Mon Sep 17 00:00:00 2001 From: huangyan Date: Wed, 5 Nov 2025 00:31:10 +0800 Subject: [PATCH 14/14] Add qemu-user, user-static, user-binfmt package - Add qemu-user package for arm, aarch64, riscv32, riscv64 target & user-static, user-binfmt package for statically-linked QEMU user emulator Signed-off-by: huangyan Signed-off-by: zhangpengrui --- qemu.spec | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 6 deletions(-) diff --git a/qemu.spec b/qemu.spec index c80045ca..daf8f009 100644 --- a/qemu.spec +++ b/qemu.spec @@ -3,7 +3,7 @@ Name: qemu Version: 8.2.0 -Release: 49 +Release: 50 Epoch: 11 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 @@ -1192,6 +1192,8 @@ BuildRequires: liburing-devel BuildRequires: spice-server-devel %endif +BuildRequires: glibc-static glib2-static zlib-static libatomic-static + # for upgrade from qemu-kvm Provides: qemu-kvm Obsoletes: qemu-kvm < 11:8.2.0 @@ -1315,6 +1317,26 @@ Requires: spice-gtk %description system-loongarch64 This package provides the QEMU system emulator for loongarch64. +%package user +Summary: Qemu-user +Requires: qemu +%description user +This package provides the QEMU user emulator for multi-arch. + +%package user-static +Summary: Qemu-user-static +%description user-static +This package provides the statically-linked QEMU user emulator for multi-arch. +These static emulators are particularly useful for container builds. + +%package user-binfmt +Summary: QEMU user mode emulation of qemu-user-static +Requires: systemd >= 197 +Requires(post): systemd +Requires(postun): systemd +%description user-binfmt +System level emulation of foreign architectures + %prep %setup -q -n qemu-%{version}%{?rcstr} %autopatch -p1 @@ -1322,26 +1344,41 @@ This package provides the QEMU system emulator for loongarch64. %build %ifarch x86_64 buildarch="x86_64-softmmu" -targetarch="aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +targetarch="aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu \ + aarch64-linux-user arm-linux-user riscv32-linux-user riscv64-linux-user" +usermode_emulator="qemu-aarch64 qemu-arm qemu-riscv32 qemu-riscv64" +usermode_static="qemu-aarch64-static qemu-arm-static qemu-riscv32-static qemu-riscv64-static" %endif %ifarch aarch64 buildarch="aarch64-softmmu" -targetarch="x86_64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +targetarch="x86_64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu \ + arm-linux-user riscv32-linux-user riscv64-linux-user" +usermode_emulator="qemu-arm qemu-riscv32 qemu-riscv64" +usermode_static="qemu-arm-static qemu-riscv32-static qemu-riscv64-static" %endif %ifarch ppc64le buildarch="ppc64-softmmu" -targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu \ + aarch64-linux-user arm-linux-user riscv32-linux-user riscv64-linux-user" +usermode_emulator="qemu-aarch64 qemu-arm qemu-riscv32 qemu-riscv64" +usermode_static="qemu-aarch64-static qemu-arm-static qemu-riscv32-static qemu-riscv64-static" %endif %ifarch loongarch64 buildarch="loongarch64-softmmu" -targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu riscv64-softmmu \ + aarch64-linux-user arm-linux-user riscv32-linux-user riscv64-linux-user" +usermode_emulator="qemu-aarch64 qemu-arm qemu-riscv32 qemu-riscv64" +usermode_static="qemu-aarch64-static qemu-arm-static qemu-riscv32-static qemu-riscv64-static" %endif %ifarch riscv64 buildarch="riscv64-softmmu" -targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu" +targetarch="x86_64-softmmu aarch64-softmmu arm-softmmu riscv32-softmmu \ + aarch64-linux-user arm-linux-user riscv32-linux-user" +usermode_emulator="qemu-aarch64 qemu-arm qemu-riscv32" +usermode_static="qemu-aarch64-static qemu-arm-static qemu-riscv32-static" %endif buildldflags="VL_LDFLAGS=-Wl,--build-id" @@ -1418,6 +1455,48 @@ make %{?_smp_mflags} $buildldflags V=1 cp ${qemubuilddir}/${buildarch}/qemu-system-* qemu-kvm +# Independent static build for user mode emulators +# Dynamically generate static_targets from usermode_static +static_targets="" +for binary in $usermode_static; do + arch=$(echo $binary | sed 's/qemu-//' | sed 's/-static//') + static_targets="$static_targets $arch-linux-user" +done +# Remove leading space +static_targets=$(echo $static_targets | sed 's/^ *//') + +# Independent static build directory +mkdir -p static_builddir +cd static_builddir + +../configure \ + --prefix=%{_prefix} \ + --enable-attr \ + --enable-linux-user \ + --enable-pie \ + --enable-tcg \ + --disable-install-blobs \ + --target-list="$static_targets" \ + --static + +make %{?_smp_mflags} V=1 +cd .. + +# Generate file lists for user packages +for i in ${usermode_emulator}; do + echo "%{_bindir}/${i}" >> %{name}.user +done + +for binary in ${usermode_static}; do + echo "%{_bindir}/${binary}" >> %{name}.user-static +done + +# Create list of static binfmt configurations for %files section +for binary in ${usermode_static}; do + arch=$(echo $binary | sed 's/qemu-//' | sed 's/-static//') + echo "%{_exec_prefix}/lib/binfmt.d/qemu-${arch}-static.conf" >> %{name}.user-static-binfmt +done + %install make %{?_smp_mflags} DESTDIR=%{buildroot} \ @@ -1427,6 +1506,39 @@ make %{?_smp_mflags} DESTDIR=%{buildroot} \ install -m 0755 qemu-kvm %{buildroot}%{_libexecdir}/ ln -s %{_libexecdir}/qemu-kvm %{buildroot}/%{_bindir}/qemu-kvm +# Install user-static binaries +%define static_buildroot %{buildroot}/static/ +mkdir -p %{static_buildroot} + +pushd static_builddir +make DESTDIR=%{static_buildroot} install + +# Duplicates what the main build installs and we don't +# need second copy with a -static suffix +rm -f %{static_buildroot}%{_bindir}/qemu-trace-stap +popd +# back to root build directory + +# Rename all QEMU user emulators to have a -static suffix +for src in %{static_buildroot}%{_bindir}/qemu-*; do + mv $src %{buildroot}%{_bindir}/$(basename $src)-static; done + +rm -rf %{static_buildroot} + +# Install binfmt configuration files +%global binfmt_dir %{buildroot}%{_exec_prefix}/lib/binfmt.d +mkdir -p %{binfmt_dir} + +# Generate binfmt configuration for dynamic emulators +./scripts/qemu-binfmt-conf.sh --systemd ALL --exportdir %{binfmt_dir} --qemu-path %{_bindir} +for i in %{binfmt_dir}/*; do mv $i $(echo $i | sed 's/.conf/-dynamic.conf/'); done + +# Generate binfmt configuration for static emulators from dynamic ones +for regularfmt in %{binfmt_dir}/*; do + staticfmt="$(echo $regularfmt | sed 's/-dynamic/-static/g')" + cat $regularfmt | tr -d '\n' | sed "s/:$/-static:F/" > $staticfmt +done + install -D -p -m 0644 contrib/systemd/qemu-pr-helper.service %{buildroot}%{_unitdir}/qemu-pr-helper.service install -D -p -m 0644 contrib/systemd/qemu-pr-helper.socket %{buildroot}%{_unitdir}/qemu-pr-helper.socket install -D -p -m 0644 qemu.sasl %{buildroot}%{_sysconfdir}/sasl2/qemu.conf @@ -1731,7 +1843,29 @@ getent passwd qemu >/dev/null || \ %{_datadir}/%{name}/bios.bin %endif +%files user -f %{name}.user + +%files user-static -f %{name}.user-static +%license COPYING COPYING.LIB LICENSE +# Include static binfmt configurations +%{_exec_prefix}/lib/binfmt.d/qemu-*-static.conf + +%files user-binfmt +%defattr(-,root,root,-) +# user-binfmt provides systemd registration for binfmt_misc +%{_exec_prefix}/lib/binfmt.d/qemu-*-dynamic.conf + +%post user-binfmt +/bin/systemctl try-restart systemd-binfmt.service &>/dev/null || : + +%postun user-binfmt +/bin/systemctl try-restart systemd-binfmt.service &>/dev/null || : + %changelog +* Wed Nov 5 2025 huangyan - 11:8.2.0-50 +- Add qemu-user package for arm, aarch64, riscv32, riscv64 targets +- Add user-static, user-binfmt package for statically-linked QEMU user emulator + * Thu Oct 30 2025 Pengrui Zhang - 11:8.2.0-49 - Revert "hw/arm/virt: Introduce a IPIV machine option" - target/arm: add ipiv=on/off option -- Gitee