expose host CPU features to guests: Take 3

Dan Kenigsberg
2007-09-24T17:41:29Z

As with previous "Takes" of this patch, its purpose is to expose host
CPU features to guests. It proved rather helpful to KVM in various
benchmarks, and it should similarly speed kqemu up. Note that it does
not extend the set of emulated opcodes, only exposes what's supported by
the host CPU.

Another purpose for "Take 2" is to add the -cpu option to the x86
architecture, similarly to that of other architectures.
-cpu 486, pentium, pentium2 and pentium3 are supported in addition to
finer-grained features such as -cpu pentium,-mmx . As in Take 1,
-cpu host exposes host features to guest.

This patch exposes the requested CPU also right after RESET command, and
not only in CPUID.

Please let me know if you have more suggestions,

Dan.

=======================================

Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.342
diff -u -p -r1.342 vl.c
--- vl.c 17 Sep 2007 21:25:20 -0000 1.342
+++ vl.c 24 Sep 2007 16:53:29 -0000
@@ -7694,6 +7694,8 @@ int main(int argc, char **argv)
mips_cpu_list(stdout, &fprintf);
#elif defined(TARGET_SPARC)
sparc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_I386)
+ x86_cpu_list(stdout, &fprintf);
#endif
exit(0);
} else {
Index: hw/pc.c
===================================================================
RCS file: /sources/qemu/qemu/hw/pc.c,v
retrieving revision 1.85
diff -u -p -r1.85 pc.c
--- hw/pc.c 17 Sep 2007 08:09:47 -0000 1.85
+++ hw/pc.c 24 Sep 2007 16:53:29 -0000
@@ -666,7 +666,7 @@ static void pc_init1(int ram_size, int v
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename,
- int pci_enabled)
+ int pci_enabled, const char *cpu_model)
{
char buf[1024];
int ret, linux_boot, i;
@@ -682,6 +682,13 @@ static void pc_init1(int ram_size, int v
linux_boot = (kernel_filename != NULL);

/* init CPUs */
+ if (cpu_model == NULL)
+ cpu_model = "basic";
+
+ if (x86_find_cpu_by_name(cpu_model)) {
+ fprintf(stderr, "Unable to find x86 CPU definition\n");
+ exit(1);
+ }
for(i = 0; i < smp_cpus; i++) {
env = cpu_init();
if (i != 0)
@@ -948,7 +955,7 @@ static void pc_init_pci(int ram_size, in
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 1);
+ initrd_filename, 1, cpu_model);
}

static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device,
@@ -962,7 +969,7 @@ static void pc_init_isa(int ram_size, in
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 0);
+ initrd_filename, 0, cpu_model);
}

QEMUMachine pc_machine = {
Index: target-i386/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.48
diff -u -p -r1.48 cpu.h
--- target-i386/cpu.h 23 Sep 2007 15:28:04 -0000 1.48
+++ target-i386/cpu.h 24 Sep 2007 16:53:30 -0000
@@ -274,23 +274,56 @@
#define CPUID_CMOV (1 << 15)
#define CPUID_PAT (1 << 16)
#define CPUID_PSE36 (1 << 17)
+#define CPUID_PN (1 << 18)
#define CPUID_CLFLUSH (1 << 19)
-/* ... */
+#define CPUID_DTS (1 << 21)
+#define CPUID_ACPI (1 << 22)
#define CPUID_MMX (1 << 23)
#define CPUID_FXSR (1 << 24)
#define CPUID_SSE (1 << 25)
#define CPUID_SSE2 (1 << 26)
+#define CPUID_SS (1 << 27)
+#define CPUID_HT (1 << 28)
+#define CPUID_TM (1 << 29)
+#define CPUID_IA64 (1 << 30)
+#define CPUID_PBE (1 << 31)

#define CPUID_EXT_SSE3 (1 << 0)
#define CPUID_EXT_MONITOR (1 << 3)
+#define CPUID_EXT_DSCPL (1 << 4)
+#define CPUID_EXT_VMX (1 << 5)
+#define CPUID_EXT_SMX (1 << 6)
+#define CPUID_EXT_EST (1 << 7)
+#define CPUID_EXT_TM2 (1 << 8)
+#define CPUID_EXT_SSSE3 (1 << 9)
+#define CPUID_EXT_CID (1 << 10)
#define CPUID_EXT_CX16 (1 << 13)
+#define CPUID_EXT_XTPR (1 << 14)
+#define CPUID_EXT_DCA (1 << 17)
+#define CPUID_EXT_POPCNT (1 << 22)

#define CPUID_EXT2_SYSCALL (1 << 11)
+#define CPUID_EXT2_MP (1 << 19)
#define CPUID_EXT2_NX (1 << 20)
+#define CPUID_EXT2_MMXEXT (1 << 22)
#define CPUID_EXT2_FFXSR (1 << 25)
+#define CPUID_EXT2_PDPE1GB (1 << 26)
+#define CPUID_EXT2_RDTSCP (1 << 27)
#define CPUID_EXT2_LM (1 << 29)
+#define CPUID_EXT2_3DNOWEXT (1 << 30)
+#define CPUID_EXT2_3DNOW (1 << 31)

+#define CPUID_EXT3_LAHF_LM (1 << 0)
+#define CPUID_EXT3_CMP_LEG (1 << 1)
#define CPUID_EXT3_SVM (1 << 2)
+#define CPUID_EXT3_EXTAPIC (1 << 3)
+#define CPUID_EXT3_CR8LEG (1 << 4)
+#define CPUID_EXT3_ABM (1 << 5)
+#define CPUID_EXT3_SSE4A (1 << 6)
+#define CPUID_EXT3_MISALIGNSSE (1 << 7)
+#define CPUID_EXT3_3DNOWPREFETCH (1 << 8)
+#define CPUID_EXT3_OSVW (1 << 9)
+#define CPUID_EXT3_IBS (1 << 10)

#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
@@ -564,6 +597,9 @@ typedef struct CPUX86State {
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
+int x86_find_cpu_by_name (const unsigned char *name);
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
+ ...));
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void cpu_set_ferr(CPUX86State *s);
Index: target-i386/helper2.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper2.c,v
retrieving revision 1.52
diff -u -p -r1.52 helper2.c
--- target-i386/helper2.c 23 Sep 2007 15:28:04 -0000 1.52
+++ target-i386/helper2.c 24 Sep 2007 16:53:30 -0000
@@ -46,6 +46,98 @@ int modify_ldt(int func, void *ptr, unsi
#endif
#endif /* USE_CODE_COPY */

+static struct x86_def_t *x86_cpu_def;
+typedef struct x86_def_t x86_def_t;
+static int cpu_x86_register (CPUX86State *env, const x86_def_t *def);
+
+/* x86_cap_flags taken from Linux's arch/i386/kernel/cpu/proc.c */
+static const char * const x86_cap_flags[] = {
+ /* Intel-defined */
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
+
+ /* AMD-defined */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
+ NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow",
+
+ /* Transmeta-defined */
+ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Other (Linux-defined) */
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+ NULL, NULL, NULL, NULL,
+ "constant_tsc", "up", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Intel-defined (#2) */
+ "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
+ NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* VIA/Cyrix/Centaur-defined */
+ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
+ "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* AMD-defined (#2) */
+ "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8legacy", "abm",
+ "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", "ibs", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+void add_flagname_to_bitmaps(char *flagname, uint32_t *features, uint32_t *ext_features, uint32_t *ext2_features, uint32_t *ext3_features)
+{
+ int i;
+ for ( i = 0 ; i < 32 ; i++ )
+ if (x86_cap_flags[i] && !strcmp (flagname, x86_cap_flags[i])) {
+ *features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (x86_cap_flags[32*4+i] && !strcmp (flagname, x86_cap_flags[32*4+i])) {
+ *ext_features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (x86_cap_flags[32*1+i] && !strcmp (flagname, x86_cap_flags[32*1+i])) {
+ *ext2_features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (x86_cap_flags[32*6+i] && !strcmp (flagname, x86_cap_flags[32*6+i])) {
+ *ext3_features |= 1 << i;
+ return;
+ }
+ /* Silently ignore Linux-defined features */
+ for ( i = 0 ; i < 32 ; i++ )
+ if (x86_cap_flags[32*3+i] && !strcmp (flagname, x86_cap_flags[32*3+i])) {
+ return;
+ }
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
+static void host_cpuid (uint32_t function, uint32_t *ax,uint32_t *bx, uint32_t *cx, uint32_t *dx)
+{
+ asm("cpuid"
+ : "=a" (*ax),
+ "=b" (*bx),
+ "=c" (*cx),
+ "=d" (*dx)
+ : "a" (function));
+}
+
CPUX86State *cpu_x86_init(void)
{
CPUX86State *env;
@@ -80,71 +172,258 @@ CPUX86State *cpu_x86_init(void)
asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
}
#endif
- {
- int family, model, stepping;
+ cpu_x86_register(env, x86_cpu_def);
+ cpu_reset(env);
+#ifdef USE_KQEMU
+ kqemu_init(env);
+#endif
+ return env;
+}
+
+struct x86_def_t {
+ const char *name;
+ uint32_t vendor1, vendor2, vendor3;
+ int family;
+ int model;
+ int stepping;
+ uint32_t features, ext_features, ext2_features, ext3_features;
+ uint32_t xlevel;
+ int hostlike;
+};
+
+#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
+ CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
+ CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
+ CPUID_PAE | CPUID_SEP | CPUID_APIC)
+static x86_def_t x86_defs[] = {
#ifdef TARGET_X86_64
- env->cpuid_vendor1 = 0x68747541; /* "Auth" */
- env->cpuid_vendor2 = 0x69746e65; /* "enti" */
- env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */
- family = 6;
- model = 2;
- stepping = 3;
+ {
+ .name = "basic",
+ .vendor1 = 0x68747541, /* "Auth" */
+ .vendor2 = 0x69746e65, /* "enti" */
+ .vendor3 = 0x444d4163, /* "cAMD" */
+ .family = 6,
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ /* these features are needed for Win64 and aren't fully implemented */
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ /* this feature is needed for Solaris and isn't fully implemented */
+ CPUID_PSE36,
+ .ext_features = CPUID_EXT_SSE3,
+ .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .xlevel = 0x80000008,
+ },
#else
+ {
+ .name = "basic",
+ .family = 6,
+ .model = 3,
+ .stepping = 3,
+ .features = PPRO_FEATURES,
+ .ext_features = CPUID_EXT_SSE3,
+ .xlevel = 0,
+ },
+#endif
+ {
+ .name = "486",
+ .family = 4,
+ .model = 0,
+ .stepping = 0,
+ .features = 0x0000000B,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium",
+ .family = 5,
+ .model = 4,
+ .stepping = 3,
+ .features = 0x008001BF,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium2",
+ .family = 6,
+ .model = 5,
+ .stepping = 2,
+ .features = 0x0183F9FF,
+ .xlevel = 0,
+ },
+ {
+ .name = "pentium3",
+ .family = 6,
+ .model = 7,
+ .stepping = 3,
+ .features = 0x0383F9FF,
+ .xlevel = 0,
+ },
+ {
+ .name = "host",
+ .hostlike = 1,
+ },
+};
+
+int x86_find_cpu_by_name(const unsigned char *cpu_model)
+{
+ int ret;
+ unsigned int i;
+
+ char *s = strdup(cpu_model);
+ char *featurestr, *name = strtok(s, ",");
+ uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0;
+ uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0;
+ int family = -1, model = -1, stepping = -1;
+
+ ret = -1;
+ x86_cpu_def = NULL;
+ for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
+ if (strcasecmp(name, x86_defs[i].name) == 0) {
+ x86_cpu_def = &x86_defs[i];
+ ret = 0;
+ break;
+ }
+ }
+ if (!x86_cpu_def)
+ goto error;
+
+ if (x86_cpu_def->hostlike) {
+ uint32_t ax, bx, cx, dx;
+ host_cpuid(0, &ax, &bx, &cx, &dx);
+ /* we ignore ax and take level=2 always */;
+ x86_cpu_def->vendor1 = bx;
+ x86_cpu_def->vendor2 = dx;
+ x86_cpu_def->vendor3 = cx;
+
+ host_cpuid(1, &ax, &bx, &cx, &dx);
+ x86_cpu_def->stepping = ax & 0xf;
+ x86_cpu_def->model = (ax >> 4) & 0xf;
+ x86_cpu_def->family = ax >> 8;
+ x86_cpu_def->features = dx & ~CPUID_ACPI; /* acpi panics linux guests */
+ x86_cpu_def->ext_features = cx & ~CPUID_EXT_VMX; /* vmx is not recursive */
+
+ /* host_cpuid(0x80000000, &ax, &bx, &cx, &dx); */
+ x86_cpu_def->xlevel = 0x80000008 /*ax*/;
+
+ host_cpuid(0x80000001, &ax, &bx, &cx, &dx);
+ /* svm is not recursive - unless Alexander Graf's SVM patch is applied */
+ x86_cpu_def->ext3_features = cx & ~CPUID_EXT3_SVM;
+ x86_cpu_def->ext2_features = dx;
+ }
+
+ featurestr = strtok(NULL, ",");
+
+ while (featurestr) {
+ char *val;
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features);
+ } else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features);
+ } else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "family")) {
+ char *err;
+ family = strtol(val, &err, 10);
+ if (!*val || *err || family < 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ x86_cpu_def = 0;
+ goto error;
+ }
+ x86_cpu_def->family = family;
+ } else if (!strcmp(featurestr, "model")) {
+ char *err;
+ model = strtol(val, &err, 10);
+ if (!*val || *err || model < 0 || model > 0xf) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ x86_cpu_def = 0;
+ goto error;
+ }
+ x86_cpu_def->model = model;
+ } else if (!strcmp(featurestr, "stepping")) {
+ char *err;
+ stepping = strtol(val, &err, 10);
+ if (!*val || *err || stepping < 0 || stepping > 0xf) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ x86_cpu_def = 0;
+ goto error;
+ }
+ x86_cpu_def->stepping = stepping;
+ } else {
+ fprintf(stderr, "unregnized feature %s\n", featurestr);
+ x86_cpu_def = 0;
+ goto error;
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
+ x86_cpu_def = 0;
+ goto error;
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ x86_cpu_def->features |= plus_features;
+ x86_cpu_def->ext_features |= plus_ext_features;
+ x86_cpu_def->ext2_features |= plus_ext2_features;
+ x86_cpu_def->ext3_features |= plus_ext3_features;
+ x86_cpu_def->features &= ~minus_features;
+ x86_cpu_def->ext_features &= ~minus_ext_features;
+ x86_cpu_def->ext2_features &= ~minus_ext2_features;
+ x86_cpu_def->ext3_features &= ~minus_ext3_features;
+
+error:
+ free(s);
+ return ret;
+}
+
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
+ (*cpu_fprintf)(f, x86_defs[i].hostlike ? "x86 %16s Host-like CPU\n"
+ : "x86 %16s family %d model %d features %08x ext_features %08x ext2_features %08x ext3_features %08x\n",
+ x86_defs[i].name,
+ x86_defs[i].family,
+ x86_defs[i].model,
+ x86_defs[i].features,
+ x86_defs[i].ext_features,
+ x86_defs[i].ext2_features,
+ x86_defs[i].ext3_features);
+ }
+}
+
+static int cpu_x86_register (CPUX86State *env, const x86_def_t *def)
+{
+ if (def->vendor1) {
+ env->cpuid_vendor1 = def->vendor1;
+ env->cpuid_vendor2 = def->vendor2;
+ env->cpuid_vendor3 = def->vendor3;
+ } else {
env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
-#if 0
- /* pentium 75-200 */
- family = 5;
- model = 2;
- stepping = 11;
-#else
- /* pentium pro */
- family = 6;
- model = 3;
- stepping = 3;
-#endif
-#endif
- env->cpuid_level = 2;
- env->cpuid_version = (family << 8) | (model << 4) | stepping;
- env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
- CPUID_TSC | CPUID_MSR | CPUID_MCE |
- CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
- CPUID_PAT);
- env->pat = 0x0007040600070406ULL;
- env->cpuid_ext3_features = CPUID_EXT3_SVM;
- env->cpuid_ext_features = CPUID_EXT_SSE3;
- env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
- env->cpuid_features |= CPUID_APIC;
- env->cpuid_xlevel = 0x8000000e;
- {
- const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
- int c, len, i;
- len = strlen(model_id);
- for(i = 0; i < 48; i++) {
- if (i >= len)
- c = '\0';
- else
- c = model_id[i];
- env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
- }
- }
-#ifdef TARGET_X86_64
- /* currently not enabled for std i386 because not fully tested */
- env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
- env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
+ }
+ env->cpuid_level = 2;
+ env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping;
+ env->cpuid_features = def->features;
+ env->pat = 0x0007040600070406ULL;
+ env->cpuid_ext_features = def->ext_features;
+ env->cpuid_ext2_features = def->ext2_features;
+ env->cpuid_xlevel = def->xlevel;
+ env->cpuid_ext3_features = def->ext3_features;
+ {
+ const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
+ int c, len, i;

- /* these features are needed for Win64 and aren't fully implemented */
- env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
- /* this feature is needed for Solaris and isn't fully implemented */
- env->cpuid_features |= CPUID_PSE36;
-#endif
+ len = strlen(model_id);
+ for(i = 0; i < 48; i++) {
+ if (i >= len)
+ c = '\0';
+ else
+ c = model_id[i];
+ env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
+ }
}
- cpu_reset(env);
-#ifdef USE_KQEMU
- kqemu_init(env);
-#endif
- return env;
+ return 0;
}

/* NOTE: must be called outside the CPU execute loop */
@@ -184,7 +463,7 @@ void cpu_reset(CPUX86State *env)
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);

env->eip = 0xfff0;
- env->regs[R_EDX] = 0x600; /* indicate P6 processor */
+ env->regs[R_EDX] = env->cpuid_version;

env->eflags = 0x2;