@@ -421,6 +421,14 @@ static void loongarch_la464_initfn(Object *obj)
data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
env->cpucfg[5] = data;
+ if (kvm_enabled()) {
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG6, PMP, 1);
+ data = FIELD_DP32(data, CPUCFG6, PMNUM, 3);
+ data = FIELD_DP32(data, CPUCFG6, PMBITS, 63);
+ env->cpucfg[6] = data;
+ }
+
data = 0;
data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
@@ -643,6 +651,20 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
}
}
+static bool loongarch_get_pmu(Object *obj, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ return !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP));
+}
+
+static void loongarch_set_pmu(Object *obj, bool value, Error **errp)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value);
+}
+
void loongarch_cpu_post_init(Object *obj)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@@ -655,6 +677,11 @@ void loongarch_cpu_post_init(Object *obj)
object_property_add_bool(obj, "lasx", loongarch_get_lasx,
loongarch_set_lasx);
}
+
+ if (kvm_enabled()) {
+ object_property_add_bool(obj, "pmu", loongarch_get_pmu,
+ loongarch_set_pmu);
+ }
}
static void loongarch_cpu_init(Object *obj)
@@ -556,6 +556,51 @@ static int kvm_check_cpucfg2(CPUState *cs)
return ret;
}
+static int kvm_check_cpucfg6(CPUState *cs)
+{
+ int ret;
+ uint64_t val;
+ struct kvm_device_attr attr = {
+ .group = KVM_LOONGARCH_VCPU_CPUCFG,
+ .attr = 6,
+ .addr = (uint64_t)&val,
+ };
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
+ if (!ret) {
+ kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
+
+ if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) {
+ /* Check PMP */
+ if (!FIELD_EX32(val, CPUCFG6, PMP)) {
+ error_report("'pmu' feature not supported by KVM on this host"
+ " Please disable 'pmu' with "
+ "'... -cpu XXX,pmu=off ...'\n");
+ exit(EXIT_FAILURE);
+ }
+ /* Check PMNUM */
+ int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM);
+ int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM);
+ if (guest_pmnum > host_pmnum){
+ error_report("The guest pmnum %d larger than KVM support %d\n",
+ guest_pmnum, host_pmnum);
+ exit(EXIT_FAILURE);
+ }
+ /* Check PMBITS */
+ int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS);
+ int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS);
+ if (guest_pmbits != host_pmbits) {
+ exit_report("The host not support PMBITS %d\n", guest_pmbits);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ return ret;
+}
+
static int kvm_loongarch_put_cpucfg(CPUState *cs)
{
int i, ret = 0;
@@ -568,7 +613,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
if (ret) {
return ret;
}
- }
+ }
+ if (i == 6) {
+ ret = kvm_check_cpucfg6(cs);
+ if (ret) {
+ return ret;
+ }
+ }
val = env->cpucfg[i];
ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
if (ret < 0) {
@@ -40,7 +40,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
}
static const char *cpu_model_advertised_features[] = {
- "lsx", "lasx", NULL
+ "lsx", "lasx", "pmu", NULL
};
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
This patch adds PMU support, We just sets some cpucfg6 default value to PMU config on kvm mode, and then check the PMU config with kvm ioctl KVM_GET_DEVICE_ATTR. e.g '... -cpu max,pmu=on' (enable PMU)' '... -cpu max,pmu=off' (disable PMU)' Signed-off-by: Song Gao <gaosong@loongson.cn> --- v2: - Drop the property 'pmnum'. - Link to v1: https://patchew.org/QEMU/20240514094630.988617-1-gaosong@loongson.cn/ This patch adds the 'RFC' heading because it requires the kernel to merge into patch[1] first [1]: https://lore.kernel.org/all/20240507120140.3119714-1-gaosong@loongson.cn/ target/loongarch/cpu.c | 27 ++++++++++++++ target/loongarch/kvm/kvm.c | 53 ++++++++++++++++++++++++++- target/loongarch/loongarch-qmp-cmds.c | 2 +- 3 files changed, 80 insertions(+), 2 deletions(-)