}
}
+#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;
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)