From bf7f2ee96faee0b6834f570129b97c8f15bd20ec Mon Sep 17 00:00:00 2001 From: Tao Cui Date: Fri, 26 Jun 2026 13:27:39 +0800 Subject: [PATCH 1/8] target/loongarch/kvm: fix uninitialized val and unchecked GET in cpucfg2 check kvm_check_cpucfg2() discards the return value of KVM_GET_DEVICE_ATTR and uses the local val (the host cpucfg2 mask) without checking whether the read succeeded. val is also declared without an initializer, so on a GET failure env->cpucfg[2] &= val reads an uninitialized value. The &= mask is best-effort feature negotiation: if KVM_HAS_DEVICE_ATTR succeeds, a GET failure is most likely a copy_{from,to}_user issue, not a reason to fail the whole register sync. Check the GET return value, warn and skip the mask on failure (the guest keeps the cpucfg2 it already has), and initialize val to 0. Signed-off-by: Tao Cui Reviewed-by: Bibo Mao Message-ID: <20260626052742.810726-2-cui.tao@linux.dev> Signed-off-by: Song Gao --- target/loongarch/kvm/kvm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 48cdb78a4c..0b72883ec9 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -725,7 +725,7 @@ static int kvm_loongarch_get_cpucfg(CPUState *cs) static int kvm_check_cpucfg2(CPUState *cs) { int ret; - uint64_t val; + uint64_t val = 0; struct kvm_device_attr attr = { .group = KVM_LOONGARCH_VCPU_CPUCFG, .attr = 2, @@ -736,8 +736,17 @@ static int kvm_check_cpucfg2(CPUState *cs) ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); if (!ret) { - kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); - env->cpucfg[2] &= val; + /* + * The &= mask is best-effort feature negotiation. If HAS succeeded, + * a GET failure is most likely a copy_{from,to}_user issue; warn and + * keep the cpucfg2 the guest already has rather than failing the sync. + */ + int r = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); + if (r) { + warn_report("CPUCFG2: KVM_GET_DEVICE_ATTR: %s", strerror(errno)); + } else { + env->cpucfg[2] &= val; + } if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) { /* The FP minimal version is 1. */ From f029c634ee99e70f7523a8662fe83d92c1999852 Mon Sep 17 00:00:00 2001 From: Tao Cui Date: Fri, 26 Jun 2026 13:27:40 +0800 Subject: [PATCH 2/8] target/loongarch/kvm: pass device attr by reference to kvm_vcpu_ioctl kvm_vcpu_ioctl() is variadic and reads its argument as a pointer, but kvm_get_stealtime(), kvm_set_stealtime() and kvm_set_pv_features() pass the local struct kvm_device_attr by value. It currently works because of how the calling convention passes large structs; pass &attr so the argument is passed as intended. Reviewed-by: Bibo Mao Signed-off-by: Tao Cui Message-ID: <20260626052742.810726-3-cui.tao@linux.dev> Signed-off-by: Song Gao --- target/loongarch/kvm/kvm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 0b72883ec9..010df226f4 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -46,12 +46,12 @@ static int kvm_get_stealtime(CPUState *cs) .addr = (uint64_t)&env->stealtime.guest_addr, }; - err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); if (err) { return 0; } - err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); if (err) { error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno)); return err; @@ -70,12 +70,12 @@ static int kvm_set_stealtime(CPUState *cs) .addr = (uint64_t)&env->stealtime.guest_addr, }; - err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); if (err) { return 0; } - err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr); if (err) { error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx, strerror(errno), env->stealtime.guest_addr); @@ -96,13 +96,13 @@ static int kvm_set_pv_features(CPUState *cs) .addr = (uint64_t)&val, }; - err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); if (err) { return 0; } val = env->pv_features; - err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); + err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr); if (err) { error_report("Fail to set pv feature "TARGET_FMT_lx " with error %s", val, strerror(errno)); From 5f59ac61692b4f289f499f80b698e17f377ec59d Mon Sep 17 00:00:00 2001 From: Tao Cui Date: Fri, 26 Jun 2026 13:27:41 +0800 Subject: [PATCH 3/8] target/loongarch/kvm: remove redundant cpucfg failure traces kvm_get_one_reg() and kvm_set_one_reg() already trace on failure, so the trace_kvm_failed_get_cpucfg()/trace_kvm_failed_put_cpucfg() calls in kvm_loongarch_get_cpucfg() and kvm_loongarch_put_cpucfg() duplicate that. Remove the calls and the now-unused trace events. Signed-off-by: Tao Cui Reviewed-by: Bibo Mao Message-ID: <20260626052742.810726-4-cui.tao@linux.dev> Signed-off-by: Song Gao --- target/loongarch/kvm/kvm.c | 6 ------ target/loongarch/trace-events | 2 -- 2 files changed, 8 deletions(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 010df226f4..162e7010ac 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -714,9 +714,6 @@ static int kvm_loongarch_get_cpucfg(CPUState *cs) for (i = 0; i < 21; i++) { ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); - if (ret < 0) { - trace_kvm_failed_get_cpucfg(strerror(errno)); - } env->cpucfg[i] = (uint32_t)val; } return ret; @@ -777,9 +774,6 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) } val = env->cpucfg[i]; ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); - if (ret < 0) { - trace_kvm_failed_put_cpucfg(strerror(errno)); - } } return ret; } diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events index dea11edc0f..829d8e0f53 100644 --- a/target/loongarch/trace-events +++ b/target/loongarch/trace-events @@ -9,7 +9,5 @@ kvm_failed_get_mpstate(const char *msg) "Failed to get mp_state from KVM: %s" kvm_failed_put_mpstate(const char *msg) "Failed to put mp_state into KVM: %s" kvm_failed_get_counter(const char *msg) "Failed to get counter from KVM: %s" kvm_failed_put_counter(const char *msg) "Failed to put counter into KVM: %s" -kvm_failed_get_cpucfg(const char *msg) "Failed to get cpucfg from KVM: %s" -kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" kvm_arch_handle_exit(int num) "kvm arch handle exit, the reason number: %d" kvm_set_intr(int irq, int level) "kvm set interrupt, irq num: %d, level: %d" From 87da979a96afd97d05497f80f6277962c40553d4 Mon Sep 17 00:00:00 2001 From: Tao Cui Date: Fri, 26 Jun 2026 13:27:42 +0800 Subject: [PATCH 4/8] target/loongarch/kvm: fix cpucfg sync error handling In kvm_loongarch_get_cpucfg() and kvm_loongarch_put_cpucfg(), ret is overwritten on each iteration, so only the last register's result is returned and earlier failures are lost. On a failed read, env->cpucfg[i] is stored from a stale or uninitialized val. Accumulate errors with ret |=, matching kvm_loongarch_get_csr()/put_csr(), and only update env->cpucfg[i] on a successful read. Keep the cpucfg2 negotiation check in put_cpucfg() on a separate variable so its early return does not overwrite the accumulated result. Signed-off-by: Tao Cui Reviewed-by: Bibo Mao Message-ID: <20260626052742.810726-5-cui.tao@linux.dev> Signed-off-by: Song Gao --- target/loongarch/kvm/kvm.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 162e7010ac..4d0cad5732 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -713,8 +713,11 @@ static int kvm_loongarch_get_cpucfg(CPUState *cs) CPULoongArchState *env = cpu_env(cs); for (i = 0; i < 21; i++) { - ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); - env->cpucfg[i] = (uint32_t)val; + int r = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + ret |= r; + if (!r) { + env->cpucfg[i] = (uint32_t)val; + } } return ret; } @@ -767,13 +770,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs) for (i = 0; i < 21; i++) { if (i == 2) { - ret = kvm_check_cpucfg2(cs); - if (ret) { - return ret; + int r = kvm_check_cpucfg2(cs); + if (r) { + return r; } } val = env->cpucfg[i]; - ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + ret |= kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); } return ret; } From e819c126a8d9629f57deef31689f3a7fc476fa45 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 30 Jun 2026 15:56:04 +0800 Subject: [PATCH 5/8] target/loongarch: Enable TARGET_PAGE_BITS_VARY for loongarch64 user-only Hard coding PAGE_SIZE to 4K will prevent user-only emulation from working on hosts with 16K page size. Fixes: 1d832c19db1e ("target/loongarch: Support 4K page size") Fixes: qemu-project/qemu#3651 Signed-off-by: Miao Wang Reviewed-by: Song Gao Message-ID: <20260630-loong64-vary-page-sz-v1-1-1d1a894674be@gmail.com> Signed-off-by: Song Gao --- target/loongarch/cpu-param.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h index 3bcf77b375..6abe72ff5c 100644 --- a/target/loongarch/cpu-param.h +++ b/target/loongarch/cpu-param.h @@ -10,6 +10,11 @@ #define TARGET_VIRT_ADDR_SPACE_BITS 48 -#define TARGET_PAGE_BITS 12 +#ifdef CONFIG_USER_ONLY +/* Allow user-only to vary page size from 4k */ +# define TARGET_PAGE_BITS_VARY +#else +# define TARGET_PAGE_BITS 12 +#endif #endif From febd672714a513b40c466e5960ef8e7fa7a6f41b Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 1 Jul 2026 14:54:54 +0800 Subject: [PATCH 6/8] hw/intc/loongarch_dintc: Fix OOB access in DINT MMIO write handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate guest-controlled cpu_num before using it to index the cpu[] array or pass to async_run_on_cpu(). Without this check, a malicious guest can trigger a NULL pointer dereference in async_run_on_cpu() and an out-of-bounds array access in qemu_set_irq(), causing host crash. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3616 Fixes: 0d148eaf5a3e ("hw/loongarch: Implement dintc set irq") Reported-by: Thomas Huth Signed-off-by: Song Gao Reported-by: huntr bubble Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-ID: <20260701065454.1976188-1-gaosong@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_dintc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/intc/loongarch_dintc.c b/hw/intc/loongarch_dintc.c index c877a8003b..e40292887c 100644 --- a/hw/intc/loongarch_dintc.c +++ b/hw/intc/loongarch_dintc.c @@ -19,6 +19,7 @@ #include "target/loongarch/cpu.h" #include "qemu/error-report.h" #include "system/hw_accel.h" +#include "qemu/log.h" /* msg addr field */ FIELD(MSG_ADDR, IRQ_NUM, 4, 8) @@ -52,7 +53,19 @@ static void loongarch_dintc_mem_write(void *opaque, hwaddr addr, CPUState *cs; cpu_num = FIELD_EX64(msg_addr, MSG_ADDR, CPU_NUM); + + /* Validate cpu_num against the configured number of CPUs */ + if (cpu_num >= s->num_cpu) { + qemu_log_mask(LOG_GUEST_ERROR, + "loongarch-dintc: invalid cpu number%d\n", cpu_num); + return; + } cs = cpu_by_arch_id(cpu_num); + if (!cs) { + qemu_log_mask(LOG_GUEST_ERROR, + "loongarch-dintc: no CPU for arch_id %d\n", cpu_num); + return; + } irq_num = FIELD_EX64(msg_addr, MSG_ADDR, IRQ_NUM); async_run_on_cpu(cs, do_set_vcpu_dintc_irq, From 25a5f018505cba2eb4bde0a314761c5abfef9118 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 3 Jul 2026 17:55:37 +0800 Subject: [PATCH 7/8] MAINTAINERS: update Song Gao's email address Update maintainer email from gaosong@loongson.cn to 17746591750@163.com and add corresponding .mailmap entries. Signed-off-by: Song Gao Reviewed-by: Song Gao Message-ID: <20260703095538.3211983-2-gaosong@loongson.cn> Signed-off-by: Song Gao --- .mailmap | 1 + MAINTAINERS | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index 8ade2eed66..593b6c2c53 100644 --- a/.mailmap +++ b/.mailmap @@ -119,6 +119,7 @@ Roman Bolshakov Sriram Yagnaraman Stefan Brankovic Stefan Weil Stefan Weil +Song Gao <17746591750@163.com> Taylor Simpson Yongbok Kim diff --git a/MAINTAINERS b/MAINTAINERS index 1e239f2116..03afb5c7dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -280,7 +280,7 @@ F: disas/hppa.c F: tests/tcg/hppa/ LoongArch TCG CPUs -M: Song Gao +M: Song Gao <17746591750@163.com> S: Maintained F: target/loongarch/ F: tests/docker/dockerfiles/debian-loongarch-cross.docker @@ -1360,7 +1360,7 @@ F: docs/devel/hexagon-sys.rst LoongArch Machines ------------------ Virt -M: Song Gao +M: Song Gao <17746591750@163.com> M: Bibo Mao R: Jiaxun Yang S: Maintained From a37dcc1bf04093d6d451b055129abde5c5e0a086 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 3 Jul 2026 17:55:38 +0800 Subject: [PATCH 8/8] MAINTAINERS: add LoongArch's maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add xianglai and bibo as maintainers for the loongarch architecture Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Xianglai Li Message-ID: <20260703095538.3211983-3-gaosong@loongson.cn> Signed-off-by: Song Gao --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 03afb5c7dc..614d04fae3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -281,6 +281,8 @@ F: tests/tcg/hppa/ LoongArch TCG CPUs M: Song Gao <17746591750@163.com> +M: Bibo Mao +R: Xianglai Li S: Maintained F: target/loongarch/ F: tests/docker/dockerfiles/debian-loongarch-cross.docker @@ -1362,6 +1364,7 @@ LoongArch Machines Virt M: Song Gao <17746591750@163.com> M: Bibo Mao +R: Xianglai Li R: Jiaxun Yang S: Maintained F: docs/system/loongarch/virt.rst