aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-02-26 07:35:55 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2025-02-26 07:35:56 +0800
commit50d38b8921837827ea397d4b20c8bc5efe186e53 (patch)
tree6e420a1c1acd5edafa3f89b4b945ece9cd933715
parentb69801dd6b1eb4d107f7c2f643adf0a4e3ec9124 (diff)
parentdb369c11c90b35f3a6ab59ad78564aea5b30c3da (diff)
downloadqemu-master.zip
qemu-master.tar.gz
qemu-master.tar.bz2
Merge tag 'pull-loongarch-20250225' of https://gitlab.com/bibo-mao/qemu into stagingHEADmaster
loongarch queue # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQQNhkKjomWfgLCz0aQfewwSUazn0QUCZ7156AAKCRAfewwSUazn # 0T2AAQDW4zr8ECab5FH+udeCtGOv2I6gtTT8CwjwhCdHNzsAAgEAxi0JJOjTIMrK # z657Q4MTeKbTyzi48niXBbI9hKvyhQM= # =g4Wx # -----END PGP SIGNATURE----- # gpg: Signature made Tue 25 Feb 2025 16:06:00 HKT # gpg: using EDDSA key 0D8642A3A2659F80B0B3D1A41F7B0C1251ACE7D1 # gpg: Good signature from "bibo mao <maobibo@loongson.cn>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 7044 3A00 19C0 E97A 31C7 13C4 8E86 8FB7 A176 9D4C # Subkey fingerprint: 0D86 42A3 A265 9F80 B0B3 D1A4 1F7B 0C12 51AC E7D1 * tag 'pull-loongarch-20250225' of https://gitlab.com/bibo-mao/qemu: target/loongarch: Enable virtual extioi feature target/loongarch: Add kvm steal time feature detection target/loongarch: Add vCPU property for kvm steal time feature target/loongarch: Enable paravirt ipi feature target/loongarch: Add paravirt ipi feature detection target/loongarch: Add vCPU property for paravirt ipi feature target/loongarch: Move kvm specified vCPU property to kvm directory target/loongarch: Add post init function for kvm mode target/loongarch: Correct maximum physical address in KVM mode target/loongarch/gdbstub: Fix gdbstub incorrectly handling some registers target/loongarch: fix vcpu reset command word issue Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--hw/loongarch/virt.c8
-rw-r--r--include/hw/loongarch/virt.h9
-rw-r--r--target/loongarch/cpu.c52
-rw-r--r--target/loongarch/cpu.h13
-rw-r--r--target/loongarch/gdbstub.c11
-rw-r--r--target/loongarch/kvm/kvm.c186
-rw-r--r--target/loongarch/loongarch-qmp-cmds.c2
7 files changed, 224 insertions, 57 deletions
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f2aa0a9..59533b0 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -45,14 +45,6 @@
#include "hw/virtio/virtio-iommu.h"
#include "qemu/error-report.h"
-static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
-{
- if (lvms->veiointc == ON_OFF_AUTO_OFF) {
- return false;
- }
- return true;
-}
-
static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 661efae..2e7cdfa 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -68,4 +68,13 @@ struct LoongArchVirtMachineState {
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE)
void virt_acpi_setup(LoongArchVirtMachineState *lvms);
void virt_fdt_setup(LoongArchVirtMachineState *lvms);
+
+static inline bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
+{
+ if (lvms->veiointc == ON_OFF_AUTO_OFF) {
+ return false;
+ }
+ return true;
+}
+
#endif
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index e91f4a5..3788f89 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -406,7 +406,7 @@ static void loongarch_la464_initfn(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
- uint32_t data = 0;
+ uint32_t data = 0, field;
int i;
for (i = 0; i < 21; i++) {
@@ -419,7 +419,13 @@ static void loongarch_la464_initfn(Object *obj)
data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
- data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f);
+ if (kvm_enabled()) {
+ /* GPA address width of VM is 47, field value is 47 - 1 */
+ field = 0x2e;
+ } else {
+ field = 0x2f; /* 48 bit - 1 */
+ }
+ data = FIELD_DP32(data, CPUCFG1, PALEN, field);
data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f);
data = FIELD_DP32(data, CPUCFG1, UAL, 1);
data = FIELD_DP32(data, CPUCFG1, RI, 1);
@@ -712,34 +718,12 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
cpu->env.cpucfg[2] = FIELD_DP32(val, CPUCFG2, LASX, value);
}
-static bool loongarch_get_lbt(Object *obj, Error **errp)
-{
- return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF;
-}
-
-static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
-{
- LoongArchCPU *cpu = LOONGARCH_CPU(obj);
-
- cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
-}
-
-static bool loongarch_get_pmu(Object *obj, Error **errp)
-{
- return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF;
-}
-
-static void loongarch_set_pmu(Object *obj, bool value, Error **errp)
-{
- LoongArchCPU *cpu = LOONGARCH_CPU(obj);
-
- cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
-}
-
void loongarch_cpu_post_init(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+ cpu->lbt = ON_OFF_AUTO_OFF;
+ cpu->pmu = ON_OFF_AUTO_OFF;
cpu->lsx = ON_OFF_AUTO_AUTO;
cpu->lasx = ON_OFF_AUTO_AUTO;
object_property_add_bool(obj, "lsx", loongarch_get_lsx,
@@ -748,21 +732,7 @@ void loongarch_cpu_post_init(Object *obj)
loongarch_set_lasx);
/* lbt is enabled only in kvm mode, not supported in tcg mode */
if (kvm_enabled()) {
- cpu->lbt = ON_OFF_AUTO_AUTO;
- object_property_add_bool(obj, "lbt", loongarch_get_lbt,
- loongarch_set_lbt);
- object_property_set_description(obj, "lbt",
- "Set off to disable Binary Tranlation.");
-
- cpu->pmu = ON_OFF_AUTO_AUTO;
- object_property_add_bool(obj, "pmu", loongarch_get_pmu,
- loongarch_set_pmu);
- object_property_set_description(obj, "pmu",
- "Set off to performance monitor unit.");
-
- } else {
- cpu->lbt = ON_OFF_AUTO_OFF;
- cpu->pmu = ON_OFF_AUTO_OFF;
+ kvm_loongarch_cpu_post_init(cpu);
}
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index f2a23b7..83183a3 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -287,6 +287,8 @@ enum loongarch_features {
LOONGARCH_FEATURE_LASX,
LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */
LOONGARCH_FEATURE_PMU,
+ LOONGARCH_FEATURE_PV_IPI,
+ LOONGARCH_FEATURE_STEALTIME,
};
typedef struct LoongArchBT {
@@ -310,6 +312,7 @@ typedef struct CPUArchState {
lbt_t lbt;
uint32_t cpucfg[21];
+ uint32_t pv_features;
/* LoongArch CSRs */
uint64_t CSR_CRMD;
@@ -406,6 +409,8 @@ struct ArchCPU {
OnOffAuto pmu;
OnOffAuto lsx;
OnOffAuto lasx;
+ OnOffAuto kvm_pv_ipi;
+ OnOffAuto kvm_steal_time;
/* 'compatible' string for this CPU for Linux device trees */
const char *dtb_compatible;
@@ -491,4 +496,12 @@ static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc,
void loongarch_cpu_post_init(Object *obj);
+#ifdef CONFIG_KVM
+void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu);
+#else
+static inline void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
+{
+}
+#endif
+
#endif /* LOONGARCH_CPU_H */
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
index dafa4fe..471eda2 100644
--- a/target/loongarch/gdbstub.c
+++ b/target/loongarch/gdbstub.c
@@ -63,23 +63,24 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CPULoongArchState *env = cpu_env(cs);
target_ulong tmp;
- int read_length;
int length = 0;
+ if (n < 0 || n > 34) {
+ return 0;
+ }
+
if (is_la64(env)) {
tmp = ldq_le_p(mem_buf);
- read_length = 8;
+ length = 8;
} else {
tmp = ldl_le_p(mem_buf);
- read_length = 4;
+ length = 4;
}
if (0 <= n && n < 32) {
env->gpr[n] = tmp;
- length = read_length;
} else if (n == 33) {
set_pc(env, tmp);
- length = read_length;
}
return length;
}
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index a3f5515..28735c8 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -8,7 +8,7 @@
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include <linux/kvm.h>
-
+#include "asm-loongarch/kvm_para.h"
#include "qapi/error.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
@@ -21,6 +21,7 @@
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/irq.h"
+#include "hw/loongarch/virt.h"
#include "qemu/log.h"
#include "hw/loader.h"
#include "system/runstate.h"
@@ -83,6 +84,33 @@ static int kvm_set_stealtime(CPUState *cs)
return 0;
}
+static int kvm_set_pv_features(CPUState *cs)
+{
+ CPULoongArchState *env = cpu_env(cs);
+ int err;
+ uint64_t val;
+ struct kvm_device_attr attr = {
+ .group = KVM_LOONGARCH_VCPU_CPUCFG,
+ .attr = CPUCFG_KVM_FEATURE,
+ .addr = (uint64_t)&val,
+ };
+
+ 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);
+ if (err) {
+ error_report("Fail to set pv feature "TARGET_FMT_lx " with error %s",
+ val, strerror(errno));
+ return err;
+ }
+
+ return 0;
+}
+
static int kvm_loongarch_get_regs_core(CPUState *cs)
{
int ret = 0;
@@ -581,9 +609,16 @@ static int kvm_loongarch_get_lbt(CPUState *cs)
void kvm_arch_reset_vcpu(CPUState *cs)
{
CPULoongArchState *env = cpu_env(cs);
+ int ret = 0;
+ uint64_t unused = 0;
env->mp_state = KVM_MP_STATE_RUNNABLE;
- kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0);
+ ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, &unused);
+ if (ret) {
+ error_report("Failed to set KVM_REG_LOONGARCH_VCPU_RESET: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
}
static int kvm_loongarch_get_mpstate(CPUState *cs)
@@ -731,6 +766,7 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
int ret;
+ static int once;
ret = kvm_loongarch_put_regs_core(cs);
if (ret) {
@@ -757,6 +793,14 @@ int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
return ret;
}
+ if (!once) {
+ ret = kvm_set_pv_features(cs);
+ if (ret) {
+ return ret;
+ }
+ once = 1;
+ }
+
if (level >= KVM_PUT_FULL_STATE) {
/*
* only KVM_PUT_FULL_STATE is required, kvm kernel will clear
@@ -875,6 +919,18 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature)
ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
return (ret == 0);
+ case LOONGARCH_FEATURE_PV_IPI:
+ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
+ attr.attr = KVM_LOONGARCH_VM_FEAT_PV_IPI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
+ return (ret == 0);
+
+ case LOONGARCH_FEATURE_STEALTIME:
+ attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
+ attr.attr = KVM_LOONGARCH_VM_FEAT_PV_STEALTIME;
+ ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
+ return (ret == 0);
+
default:
return false;
}
@@ -973,6 +1029,52 @@ static int kvm_cpu_check_pmu(CPUState *cs, Error **errp)
return 0;
}
+static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = cpu_env(cs);
+ bool kvm_supported;
+
+ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PV_IPI);
+ if (cpu->kvm_pv_ipi == ON_OFF_AUTO_ON) {
+ if (!kvm_supported) {
+ error_setg(errp, "'pv_ipi' feature not supported by KVM host");
+ return -ENOTSUP;
+ }
+ } else if (cpu->kvm_pv_ipi != ON_OFF_AUTO_AUTO) {
+ kvm_supported = false;
+ }
+
+ if (kvm_supported) {
+ env->pv_features |= BIT(KVM_FEATURE_IPI);
+ }
+
+ kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_STEALTIME);
+ if (cpu->kvm_steal_time == ON_OFF_AUTO_ON) {
+ if (!kvm_supported) {
+ error_setg(errp, "'kvm stealtime' feature not supported by KVM host");
+ return -ENOTSUP;
+ }
+ } else if (cpu->kvm_steal_time != ON_OFF_AUTO_AUTO) {
+ kvm_supported = false;
+ }
+
+ if (kvm_supported) {
+ env->pv_features |= BIT(KVM_FEATURE_STEAL_TIME);
+ }
+
+ if (object_dynamic_cast(OBJECT(ms), TYPE_LOONGARCH_VIRT_MACHINE)) {
+ LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
+
+ if (virt_is_veiointc_enabled(lvms)) {
+ env->pv_features |= BIT(KVM_FEATURE_VIRT_EXTIOI);
+ }
+ }
+
+ return 0;
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
uint64_t val;
@@ -1006,9 +1108,89 @@ int kvm_arch_init_vcpu(CPUState *cs)
error_report_err(local_err);
}
+ ret = kvm_cpu_check_pv_features(cs, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ }
+
return ret;
}
+static bool loongarch_get_lbt(Object *obj, Error **errp)
+{
+ return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF;
+}
+
+static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
+static bool loongarch_get_pmu(Object *obj, Error **errp)
+{
+ return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF;
+}
+
+static void loongarch_set_pmu(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
+static bool kvm_pv_ipi_get(Object *obj, Error **errp)
+{
+ return LOONGARCH_CPU(obj)->kvm_pv_ipi != ON_OFF_AUTO_OFF;
+}
+
+static void kvm_pv_ipi_set(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->kvm_pv_ipi = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
+static bool kvm_steal_time_get(Object *obj, Error **errp)
+{
+ return LOONGARCH_CPU(obj)->kvm_steal_time != ON_OFF_AUTO_OFF;
+}
+
+static void kvm_steal_time_set(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->kvm_steal_time = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
+void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
+{
+ cpu->lbt = ON_OFF_AUTO_AUTO;
+ object_property_add_bool(OBJECT(cpu), "lbt", loongarch_get_lbt,
+ loongarch_set_lbt);
+ object_property_set_description(OBJECT(cpu), "lbt",
+ "Set off to disable Binary Tranlation.");
+
+ cpu->pmu = ON_OFF_AUTO_AUTO;
+ object_property_add_bool(OBJECT(cpu), "pmu", loongarch_get_pmu,
+ loongarch_set_pmu);
+ object_property_set_description(OBJECT(cpu), "pmu",
+ "Set off to disable performance monitor unit.");
+
+ cpu->kvm_pv_ipi = ON_OFF_AUTO_AUTO;
+ object_property_add_bool(OBJECT(cpu), "kvm-pv-ipi", kvm_pv_ipi_get,
+ kvm_pv_ipi_set);
+ object_property_set_description(OBJECT(cpu), "kvm-pv-ipi",
+ "Set off to disable KVM paravirt IPI.");
+
+ cpu->kvm_steal_time = ON_OFF_AUTO_AUTO;
+ object_property_add_bool(OBJECT(cpu), "kvm-steal-time", kvm_steal_time_get,
+ kvm_steal_time_set);
+ object_property_set_description(OBJECT(cpu), "kvm-steal-time",
+ "Set off to disable KVM steal time.");
+}
+
int kvm_arch_destroy_vcpu(CPUState *cs)
{
return 0;
diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c
index 3fde5a5..6f732d8 100644
--- a/target/loongarch/loongarch-qmp-cmds.c
+++ b/target/loongarch/loongarch-qmp-cmds.c
@@ -40,7 +40,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
}
static const char *cpu_model_advertised_features[] = {
- "lsx", "lasx", "lbt", "pmu", NULL
+ "lsx", "lasx", "lbt", "pmu", "kvm-pv-ipi", "kvm-steal-time", NULL
};
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,