[PATCH v3 3/4] target/loongarch: Add host CPU model in kvm mode

Bibo Mao posted 4 patches 4 weeks, 1 day ago
Maintainers: Song Gao <gaosong@loongson.cn>, Bibo Mao <maobibo@loongson.cn>, Jiaxun Yang <jiaxun.yang@flygoat.com>
There is a newer version of this series
[PATCH v3 3/4] target/loongarch: Add host CPU model in kvm mode
Posted by Bibo Mao 4 weeks, 1 day ago
Host CPU model is basically the same with max CPU model, except Product
ID and CPU model name. With host CPU model, Product ID comes from
cpucfg0 and CPU model comes from /proc/cpuinfo.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
 target/loongarch/cpu.c | 94 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index dffe6f652f..f9255c4f84 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -429,6 +429,97 @@ static void loongarch_max_initfn(Object *obj)
     }
 }
 
+#if defined(CONFIG_KVM)
+static int read_cpuinfo(const char *field, char *value, int len)
+{
+    FILE *f;
+    int ret = -1;
+    int field_len = strlen(field);
+    char line[512];
+
+    f = fopen("/proc/cpuinfo", "r");
+    if (!f) {
+        return -1;
+    }
+
+    do {
+        if (!fgets(line, sizeof(line), f)) {
+            break;
+        }
+        if (!strncmp(line, field, field_len)) {
+            strncpy(value, line, len);
+            ret = 0;
+            break;
+        }
+    } while (*line);
+
+    fclose(f);
+
+    return ret;
+}
+
+static uint64_t get_host_cpu_model(void)
+{
+    char line[512];
+    char *ns;
+    static uint64_t cpuid;
+
+    if (cpuid) {
+        return cpuid;
+    }
+
+    if (read_cpuinfo("Model Name", line, sizeof(line))) {
+        return 0;
+    }
+
+    ns = strchr(line, ':');
+    if (!ns) {
+        return 0;
+    }
+
+    ns = strstr(ns, "Loongson-");
+    if (!ns) {
+        return 0;
+    }
+
+    ns += strlen("Loongson-");
+    memccpy((void *)&cpuid, ns, 0, 8);
+    return cpuid;
+}
+
+static uint32_t get_host_cpucfg(int number)
+{
+    unsigned int data = 0;
+
+#ifdef __loongarch__
+    asm volatile("cpucfg %[val], %[reg]"
+                 : [val] "=r" (data)
+                 : [reg] "r" (number)
+                 : "memory");
+#endif
+
+    return data;
+}
+
+static void loongarch_host_initfn(Object *obj)
+{
+    uint32_t data;
+    uint64_t cpuid;
+    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+    loongarch_max_initfn(obj);
+    data = get_host_cpucfg(0);
+    if (data) {
+        cpu->env.cpucfg[0] = data;
+    }
+
+    cpuid = get_host_cpu_model();
+    if (cpuid) {
+        cpu->env.cpu_id = cpuid;
+    }
+}
+#endif
+
 static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
 {
     uint8_t tlb_ps;
@@ -780,6 +871,9 @@ static const TypeInfo loongarch_cpu_type_infos[] = {
     DEFINE_LOONGARCH_CPU_TYPE(64, "la464", loongarch_la464_initfn),
     DEFINE_LOONGARCH_CPU_TYPE(32, "la132", loongarch_la132_initfn),
     DEFINE_LOONGARCH_CPU_TYPE(64, "max", loongarch_max_initfn),
+#if defined(CONFIG_KVM)
+    DEFINE_LOONGARCH_CPU_TYPE(64, "host", loongarch_host_initfn),
+#endif
 };
 
 DEFINE_TYPES(loongarch_cpu_type_infos)
-- 
2.39.3
Re: [PATCH v3 3/4] target/loongarch: Add host CPU model in kvm mode
Posted by Richard Henderson 4 weeks ago
On 1/12/26 19:07, Bibo Mao wrote:
> +#if defined(CONFIG_KVM)
> +static int read_cpuinfo(const char *field, char *value, int len)
> +{
> +    FILE *f;
> +    int ret = -1;
> +    int field_len = strlen(field);
> +    char line[512];
> +
> +    f = fopen("/proc/cpuinfo", "r");
> +    if (!f) {
> +        return -1;
> +    }
> +
> +    do {
> +        if (!fgets(line, sizeof(line), f)) {
> +            break;
> +        }
> +        if (!strncmp(line, field, field_len)) {
> +            strncpy(value, line, len);
> +            ret = 0;
> +            break;
> +        }
> +    } while (*line);
> +
> +    fclose(f);
> +
> +    return ret;
> +}
> +
> +static uint64_t get_host_cpu_model(void)
> +{
> +    char line[512];
> +    char *ns;
> +    static uint64_t cpuid;
> +
> +    if (cpuid) {
> +        return cpuid;
> +    }
> +
> +    if (read_cpuinfo("Model Name", line, sizeof(line))) {
> +        return 0;
> +    }
> +
> +    ns = strchr(line, ':');
> +    if (!ns) {
> +        return 0;
> +    }
> +
> +    ns = strstr(ns, "Loongson-");
> +    if (!ns) {
> +        return 0;
> +    }
> +
> +    ns += strlen("Loongson-");
> +    memccpy((void *)&cpuid, ns, 0, 8);
> +    return cpuid;
> +}
> +
> +static uint32_t get_host_cpucfg(int number)
> +{
> +    unsigned int data = 0;
> +
> +#ifdef __loongarch__
> +    asm volatile("cpucfg %[val], %[reg]"
> +                 : [val] "=r" (data)
> +                 : [reg] "r" (number)
> +                 : "memory");
> +#endif
> +
> +    return data;
> +}
Are you sure you should be bypassing KVM for this?  Other targets start a scratch vcpu and 
then read the values via KVM_GET_ONE_REG.

I'm not sure how much trap-and-emulate support LoongArch has for such ID registers.


r~
Re: [PATCH v3 3/4] target/loongarch: Add host CPU model in kvm mode
Posted by Bibo Mao 4 weeks ago

On 2026/1/13 上午5:45, Richard Henderson wrote:
> On 1/12/26 19:07, Bibo Mao wrote:
>> +#if defined(CONFIG_KVM)
>> +static int read_cpuinfo(const char *field, char *value, int len)
>> +{
>> +    FILE *f;
>> +    int ret = -1;
>> +    int field_len = strlen(field);
>> +    char line[512];
>> +
>> +    f = fopen("/proc/cpuinfo", "r");
>> +    if (!f) {
>> +        return -1;
>> +    }
>> +
>> +    do {
>> +        if (!fgets(line, sizeof(line), f)) {
>> +            break;
>> +        }
>> +        if (!strncmp(line, field, field_len)) {
>> +            strncpy(value, line, len);
>> +            ret = 0;
>> +            break;
>> +        }
>> +    } while (*line);
>> +
>> +    fclose(f);
>> +
>> +    return ret;
>> +}
>> +
>> +static uint64_t get_host_cpu_model(void)
>> +{
>> +    char line[512];
>> +    char *ns;
>> +    static uint64_t cpuid;
>> +
>> +    if (cpuid) {
>> +        return cpuid;
>> +    }
>> +
>> +    if (read_cpuinfo("Model Name", line, sizeof(line))) {
>> +        return 0;
>> +    }
>> +
>> +    ns = strchr(line, ':');
>> +    if (!ns) {
>> +        return 0;
>> +    }
>> +
>> +    ns = strstr(ns, "Loongson-");
>> +    if (!ns) {
>> +        return 0;
>> +    }
>> +
>> +    ns += strlen("Loongson-");
>> +    memccpy((void *)&cpuid, ns, 0, 8);
>> +    return cpuid;
>> +}
>> +
>> +static uint32_t get_host_cpucfg(int number)
>> +{
>> +    unsigned int data = 0;
>> +
>> +#ifdef __loongarch__
>> +    asm volatile("cpucfg %[val], %[reg]"
>> +                 : [val] "=r" (data)
>> +                 : [reg] "r" (number)
>> +                 : "memory");
>> +#endif
>> +
>> +    return data;
>> +}
> Are you sure you should be bypassing KVM for this?  Other targets start 
> a scratch vcpu and then read the values via KVM_GET_ONE_REG.
Feature detection instruction CPUCFG can be executed in user mode, 
similar with CPUID on X86, on ARM platform instruction MRS can only used 
in privileged mode.

On LoongArch platform, it is both OK to detect host CPU features by 
CPUCFG instruction or KVM_GET_DEVICE_ATTR ioctl command method.
     struct kvm_device_attr attr = {
         .group = KVM_LOONGARCH_VCPU_CPUCFG,
         .attr = 2,
         .addr = (uint64_t)&val,
     };

     CPULoongArchState *env = cpu_env(cs);
     ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
     if (!ret) {
         kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
     }

Regards
Bibo Mao
> 
> I'm not sure how much trap-and-emulate support LoongArch has for such ID 
> registers.
> 
> 
> r~