* [Qemu-devel] expose host CPU features to guests
@ 2007-09-05 17:45 danken
2007-09-05 19:26 ` [Qemu-devel] Re: [kvm-devel] " Anthony Liguori
2007-09-10 7:40 ` [Qemu-devel] expose host CPU features to guests: Take 2 Dan Kenigsberg
0 siblings, 2 replies; 43+ messages in thread
From: danken @ 2007-09-05 17:45 UTC (permalink / raw)
To: qemu-devel, kvm-devel
Hi,
It's a pity not to use a host CPU feature if it is available. This patch
exposes host CPU features to guests. It allows fine-tuning the presented
features from the command-line.
The code could use some serious clean ups, but I think it is interesting
enough right now. I'd be happy to hear your opinion and suggestions.
The diff are done against qemu cvs. I tried it with kvm, but I thinkg it
should be useful also for kqemu.
Regards,
Dan.
Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.336
diff -u -p -r1.336 vl.c
--- vl.c 28 Aug 2007 22:21:40 -0000 1.336
+++ vl.c 5 Sep 2007 15:48:10 -0000
@@ -6575,12 +6575,24 @@ int qemu_register_machine(QEMUMachine *m
return 0;
}
+const char *machine_flavor = 0;
+
QEMUMachine *find_machine(const char *name)
{
QEMUMachine *m;
+ int n;
+ machine_flavor = strchr(name, ',');
+ if (machine_flavor) {
+ n = machine_flavor - name;
+ machine_flavor++;
+ } else {
+ n = strlen(name);
+ machine_flavor = "";
+ }
+
for(m = first_machine; m != NULL; m = m->next) {
- if (!strcmp(m->name, name))
+ if (!strncmp(m->name, name, n))
return m;
}
return NULL;
@@ -7343,6 +7355,7 @@ static void read_passwords(void)
void register_machines(void)
{
#if defined(TARGET_I386)
+ qemu_register_machine(&host_pc_machine);
qemu_register_machine(&pc_machine);
qemu_register_machine(&isapc_machine);
#elif defined(TARGET_PPC)
Index: vl.h
===================================================================
RCS file: /sources/qemu/qemu/vl.h,v
retrieving revision 1.264
diff -u -p -r1.264 vl.h
--- vl.h 26 Aug 2007 17:46:00 -0000 1.264
+++ vl.h 5 Sep 2007 15:48:10 -0000
@@ -1156,6 +1156,7 @@ void piix4_smbus_register_device(SMBusDe
void acpi_bios_init(void);
/* pc.c */
+extern QEMUMachine host_pc_machine;
extern QEMUMachine pc_machine;
extern QEMUMachine isapc_machine;
extern int fd_bootchk;
Index: hw/pc.c
===================================================================
RCS file: /sources/qemu/qemu/hw/pc.c,v
retrieving revision 1.83
diff -u -p -r1.83 pc.c
--- hw/pc.c 26 Aug 2007 17:51:39 -0000 1.83
+++ hw/pc.c 5 Sep 2007 15:48:10 -0000
@@ -965,6 +965,28 @@ static void pc_init_isa(int ram_size, in
initrd_filename, 0);
}
+int use_hostlike_cpu = 0;
+
+static void pc_init_hostlike(ram_addr_t ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename)
+{
+ use_hostlike_cpu = 1;
+ pc_init1(ram_size, vga_ram_size, boot_device,
+ ds, fd_filename, snapshot,
+ kernel_filename, kernel_cmdline,
+ initrd_filename, 1);
+}
+
+QEMUMachine host_pc_machine = {
+ "host",
+ "Standard PC with host-like CPU",
+ pc_init_hostlike,
+};
+
QEMUMachine pc_machine = {
"pc",
"Standard PC",
Index: target-i386/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.45
diff -u -p -r1.45 cpu.h
--- target-i386/cpu.h 11 Jul 2007 22:48:58 -0000 1.45
+++ target-i386/cpu.h 5 Sep 2007 15:48:10 -0000
@@ -267,21 +267,44 @@
#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 EXCP00_DIVZ 0
#define EXCP01_SSTP 1
Index: target-i386/helper2.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper2.c,v
retrieving revision 1.48
diff -u -p -r1.48 helper2.c
--- target-i386/helper2.c 31 Jul 2007 23:09:18 -0000 1.48
+++ target-i386/helper2.c 5 Sep 2007 15:48:10 -0000
@@ -45,6 +45,272 @@ int modify_ldt(int func, void *ptr, unsi
#endif
#endif /* USE_CODE_COPY */
+/* 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, int *features, int *ext_features, int *ext2_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;
+ }
+ /* 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 apply_machine_flavor(CPUX86State *env)
+{
+ int plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0;
+ int minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0;
+ int family = -1, model = -1, stepping = -1;
+
+ extern char *machine_flavor;
+ char *s = strdup(machine_flavor);
+ char *featurestr = strtok(s, ",");
+
+ while (featurestr) {
+ char *val;
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features);
+ }
+ else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features);
+ }
+ else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "family")) {
+ family = atoi(val);
+ if (family <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFF;
+ env->cpuid_version |= (family << 8);
+ } else if (!strcmp(featurestr, "model")) {
+ model = atoi(val);
+ if (model <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFFFFFF0F;
+ env->cpuid_version |= (model << 4);
+ } else if (!strcmp(featurestr, "stepping")) {
+ stepping = atoi(val);
+ if (stepping <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFFFFFFF0;
+ env->cpuid_version |= stepping;
+ } else {
+ fprintf(stderr, "unknown feature %s\n", featurestr);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
+ exit(1);
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ free(s);
+ env->cpuid_features |= plus_features;
+ env->cpuid_ext_features |= plus_ext_features;
+ env->cpuid_ext2_features |= plus_ext2_features;
+ env->cpuid_features &= ~minus_features;
+ env->cpuid_ext_features &= ~minus_ext_features;
+ env->cpuid_ext2_features &= ~minus_ext2_features;
+}
+
+static int read_one_cpu_info(CPUX86State *env, FILE *f)
+{
+ char line[300], *val;
+ char vendor_id[13];
+ int family = -1, model = -1, stepping = -1;
+ int features = 0, ext_features = 0, ext2_features = 0;
+
+ while (fgets(line, sizeof(line), f)) {
+ if (!strtok(line, "\t") || line[0]=='\n') {
+ break;
+ }
+ val = strtok(NULL, "\t:");
+ if (!val)
+ val = "";
+ if (*val==' ')
+ val++;
+
+ if (!strcmp(line,"vendor_id")) {
+ strncpy(vendor_id, val, sizeof(vendor_id) - 1);
+ vendor_id[sizeof(vendor_id)-1] = 0;
+ }
+ if (!strcmp(line,"cpu family")) {
+ family = atoi(val);
+ }
+ if (!strcmp(line,"model")) {
+ model = atoi(val);
+ }
+ if (!strcmp(line,"stepping")) {
+ stepping = atoi(val);
+ }
+ if (!strcmp(line,"flags")) {
+ char *flagname;
+ struct flagstorage {
+ char *name;
+ int bit;
+ int *container;
+ };
+
+ flagname = strtok(val, " ");
+ while (flagname) {
+ add_flagname_to_bitmaps(flagname, &features, &ext_features, &ext2_features);
+ flagname = strtok(NULL, " \n");
+ }
+ features &= ~CPUID_ACPI; /* acpi causes guest kernel panic on boot time, in cpu_identify */
+ ext_features &= ~CPUID_EXT_VMX; /* KVM is not recursive */
+ }
+ }
+ if (family==-1 || model==-1 || stepping==-1)
+ return -1;
+ env->cpuid_level = 2;
+ env->cpuid_vendor1 = *(uint32_t *)&vendor_id[0];
+ env->cpuid_vendor2 = *(uint32_t *)&vendor_id[4];
+ env->cpuid_vendor3 = *(uint32_t *)&vendor_id[8];
+ env->cpuid_version = (family << 8) | (model << 4) | stepping;
+ env->cpuid_features = features;
+ env->cpuid_ext_features = ext_features;
+ env->cpuid_ext2_features = ext2_features;
+ env->pat = 0x0007040600070406ULL;
+ /* TODO expose real cpuid extended level */
+#ifdef TARGET_X86_64
+ env->cpuid_xlevel = 0x80000008;
+#else
+ env->cpuid_xlevel = 0;
+#endif
+ return 0;
+}
+
+static int set_guest_cpu_hostlike(CPUX86State *env) {
+ FILE *f;
+ f = fopen("/proc/cpuinfo", "r");
+ if (!f) {
+ fprintf(stderr, "falling back to standard guest cpu\n");
+ return -1;
+ }
+ read_one_cpu_info(env, f);
+ fclose(f);
+ return 0;
+}
+
+static int set_guest_cpu_standard(CPUX86State *env)
+{
+ int family, model, stepping;
+#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;
+#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_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 = 0;
+#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_xlevel = 0x80000008;
+
+ /* 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
+ return 0;
+}
+
CPUX86State *cpu_x86_init(void)
{
CPUX86State *env;
@@ -80,64 +346,23 @@ CPUX86State *cpu_x86_init(void)
}
#endif
{
- int family, model, stepping;
-#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;
-#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_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 = 0;
- {
- 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));
- }
+ extern int use_hostlike_cpu;
+ if (!use_hostlike_cpu || set_guest_cpu_hostlike(env))
+ set_guest_cpu_standard(env);
+ apply_machine_flavor(env);
+ }
+ {
+ 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_xlevel = 0x80000008;
-
- /* 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
}
cpu_reset(env);
#ifdef USE_KQEMU
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-05 17:45 [Qemu-devel] expose host CPU features to guests danken
@ 2007-09-05 19:26 ` Anthony Liguori
2007-09-05 19:34 ` Avi Kivity
2007-09-07 10:47 ` Jamie Lokier
2007-09-10 7:40 ` [Qemu-devel] expose host CPU features to guests: Take 2 Dan Kenigsberg
1 sibling, 2 replies; 43+ messages in thread
From: Anthony Liguori @ 2007-09-05 19:26 UTC (permalink / raw)
To: danken; +Cc: kvm-devel, qemu-devel
On Wed, 2007-09-05 at 20:45 +0300, danken@qumranet.com wrote:
> Hi,
>
> It's a pity not to use a host CPU feature if it is available. This patch
> exposes host CPU features to guests. It allows fine-tuning the presented
> features from the command-line.
>
> The code could use some serious clean ups, but I think it is interesting
> enough right now. I'd be happy to hear your opinion and suggestions.
> The diff are done against qemu cvs. I tried it with kvm, but I thinkg it
> should be useful also for kqemu.
I like this idea but I have some suggestions about the general approach.
I think instead of defining another machine type, it would be better to
just have a command line option like -cpuid that took a comma separate
string of features with "all" meaning all features that the host has.
I also think it would be nicer to use cpuid() directly instead of
attempting to parse /proc/cpuinfo.
Regards,
Anthony Liguori
> Regards,
>
> Dan.
>
> Index: vl.c
> ===================================================================
> RCS file: /sources/qemu/qemu/vl.c,v
> retrieving revision 1.336
> diff -u -p -r1.336 vl.c
> --- vl.c 28 Aug 2007 22:21:40 -0000 1.336
> +++ vl.c 5 Sep 2007 15:48:10 -0000
> @@ -6575,12 +6575,24 @@ int qemu_register_machine(QEMUMachine *m
> return 0;
> }
>
> +const char *machine_flavor = 0;
> +
> QEMUMachine *find_machine(const char *name)
> {
> QEMUMachine *m;
>
> + int n;
> + machine_flavor = strchr(name, ',');
> + if (machine_flavor) {
> + n = machine_flavor - name;
> + machine_flavor++;
> + } else {
> + n = strlen(name);
> + machine_flavor = "";
> + }
> +
> for(m = first_machine; m != NULL; m = m->next) {
> - if (!strcmp(m->name, name))
> + if (!strncmp(m->name, name, n))
> return m;
> }
> return NULL;
> @@ -7343,6 +7355,7 @@ static void read_passwords(void)
> void register_machines(void)
> {
> #if defined(TARGET_I386)
> + qemu_register_machine(&host_pc_machine);
> qemu_register_machine(&pc_machine);
> qemu_register_machine(&isapc_machine);
> #elif defined(TARGET_PPC)
> Index: vl.h
> ===================================================================
> RCS file: /sources/qemu/qemu/vl.h,v
> retrieving revision 1.264
> diff -u -p -r1.264 vl.h
> --- vl.h 26 Aug 2007 17:46:00 -0000 1.264
> +++ vl.h 5 Sep 2007 15:48:10 -0000
> @@ -1156,6 +1156,7 @@ void piix4_smbus_register_device(SMBusDe
> void acpi_bios_init(void);
>
> /* pc.c */
> +extern QEMUMachine host_pc_machine;
> extern QEMUMachine pc_machine;
> extern QEMUMachine isapc_machine;
> extern int fd_bootchk;
> Index: hw/pc.c
> ===================================================================
> RCS file: /sources/qemu/qemu/hw/pc.c,v
> retrieving revision 1.83
> diff -u -p -r1.83 pc.c
> --- hw/pc.c 26 Aug 2007 17:51:39 -0000 1.83
> +++ hw/pc.c 5 Sep 2007 15:48:10 -0000
> @@ -965,6 +965,28 @@ static void pc_init_isa(int ram_size, in
> initrd_filename, 0);
> }
>
> +int use_hostlike_cpu = 0;
> +
> +static void pc_init_hostlike(ram_addr_t ram_size, int vga_ram_size, int boot_device,
> + DisplayState *ds, const char **fd_filename,
> + int snapshot,
> + const char *kernel_filename,
> + const char *kernel_cmdline,
> + const char *initrd_filename)
> +{
> + use_hostlike_cpu = 1;
> + pc_init1(ram_size, vga_ram_size, boot_device,
> + ds, fd_filename, snapshot,
> + kernel_filename, kernel_cmdline,
> + initrd_filename, 1);
> +}
> +
> +QEMUMachine host_pc_machine = {
> + "host",
> + "Standard PC with host-like CPU",
> + pc_init_hostlike,
> +};
> +
> QEMUMachine pc_machine = {
> "pc",
> "Standard PC",
> Index: target-i386/cpu.h
> ===================================================================
> RCS file: /sources/qemu/qemu/target-i386/cpu.h,v
> retrieving revision 1.45
> diff -u -p -r1.45 cpu.h
> --- target-i386/cpu.h 11 Jul 2007 22:48:58 -0000 1.45
> +++ target-i386/cpu.h 5 Sep 2007 15:48:10 -0000
> @@ -267,21 +267,44 @@
> #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 EXCP00_DIVZ 0
> #define EXCP01_SSTP 1
> Index: target-i386/helper2.c
> ===================================================================
> RCS file: /sources/qemu/qemu/target-i386/helper2.c,v
> retrieving revision 1.48
> diff -u -p -r1.48 helper2.c
> --- target-i386/helper2.c 31 Jul 2007 23:09:18 -0000 1.48
> +++ target-i386/helper2.c 5 Sep 2007 15:48:10 -0000
> @@ -45,6 +45,272 @@ int modify_ldt(int func, void *ptr, unsi
> #endif
> #endif /* USE_CODE_COPY */
>
> +/* 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, int *features, int *ext_features, int *ext2_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;
> + }
> + /* 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 apply_machine_flavor(CPUX86State *env)
> +{
> + int plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0;
> + int minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0;
> + int family = -1, model = -1, stepping = -1;
> +
> + extern char *machine_flavor;
> + char *s = strdup(machine_flavor);
> + char *featurestr = strtok(s, ",");
> +
> + while (featurestr) {
> + char *val;
> + if (featurestr[0] == '+') {
> + add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features);
> + }
> + else if (featurestr[0] == '-') {
> + add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features);
> + }
> + else if ((val = strchr(featurestr, '='))) {
> + *val = 0; val++;
> + if (!strcmp(featurestr, "family")) {
> + family = atoi(val);
> + if (family <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFF;
> + env->cpuid_version |= (family << 8);
> + } else if (!strcmp(featurestr, "model")) {
> + model = atoi(val);
> + if (model <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFFFFFF0F;
> + env->cpuid_version |= (model << 4);
> + } else if (!strcmp(featurestr, "stepping")) {
> + stepping = atoi(val);
> + if (stepping <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFFFFFFF0;
> + env->cpuid_version |= stepping;
> + } else {
> + fprintf(stderr, "unknown feature %s\n", featurestr);
> + exit(1);
> + }
> + } else {
> + fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
> + exit(1);
> + }
> + featurestr = strtok(NULL, ",");
> + }
> + free(s);
> + env->cpuid_features |= plus_features;
> + env->cpuid_ext_features |= plus_ext_features;
> + env->cpuid_ext2_features |= plus_ext2_features;
> + env->cpuid_features &= ~minus_features;
> + env->cpuid_ext_features &= ~minus_ext_features;
> + env->cpuid_ext2_features &= ~minus_ext2_features;
> +}
> +
> +static int read_one_cpu_info(CPUX86State *env, FILE *f)
> +{
> + char line[300], *val;
> + char vendor_id[13];
> + int family = -1, model = -1, stepping = -1;
> + int features = 0, ext_features = 0, ext2_features = 0;
> +
> + while (fgets(line, sizeof(line), f)) {
> + if (!strtok(line, "\t") || line[0]=='\n') {
> + break;
> + }
> + val = strtok(NULL, "\t:");
> + if (!val)
> + val = "";
> + if (*val==' ')
> + val++;
> +
> + if (!strcmp(line,"vendor_id")) {
> + strncpy(vendor_id, val, sizeof(vendor_id) - 1);
> + vendor_id[sizeof(vendor_id)-1] = 0;
> + }
> + if (!strcmp(line,"cpu family")) {
> + family = atoi(val);
> + }
> + if (!strcmp(line,"model")) {
> + model = atoi(val);
> + }
> + if (!strcmp(line,"stepping")) {
> + stepping = atoi(val);
> + }
> + if (!strcmp(line,"flags")) {
> + char *flagname;
> + struct flagstorage {
> + char *name;
> + int bit;
> + int *container;
> + };
> +
> + flagname = strtok(val, " ");
> + while (flagname) {
> + add_flagname_to_bitmaps(flagname, &features, &ext_features, &ext2_features);
> + flagname = strtok(NULL, " \n");
> + }
> + features &= ~CPUID_ACPI; /* acpi causes guest kernel panic on boot time, in cpu_identify */
> + ext_features &= ~CPUID_EXT_VMX; /* KVM is not recursive */
> + }
> + }
> + if (family==-1 || model==-1 || stepping==-1)
> + return -1;
> + env->cpuid_level = 2;
> + env->cpuid_vendor1 = *(uint32_t *)&vendor_id[0];
> + env->cpuid_vendor2 = *(uint32_t *)&vendor_id[4];
> + env->cpuid_vendor3 = *(uint32_t *)&vendor_id[8];
> + env->cpuid_version = (family << 8) | (model << 4) | stepping;
> + env->cpuid_features = features;
> + env->cpuid_ext_features = ext_features;
> + env->cpuid_ext2_features = ext2_features;
> + env->pat = 0x0007040600070406ULL;
> + /* TODO expose real cpuid extended level */
> +#ifdef TARGET_X86_64
> + env->cpuid_xlevel = 0x80000008;
> +#else
> + env->cpuid_xlevel = 0;
> +#endif
> + return 0;
> +}
> +
> +static int set_guest_cpu_hostlike(CPUX86State *env) {
> + FILE *f;
> + f = fopen("/proc/cpuinfo", "r");
> + if (!f) {
> + fprintf(stderr, "falling back to standard guest cpu\n");
> + return -1;
> + }
> + read_one_cpu_info(env, f);
> + fclose(f);
> + return 0;
> +}
> +
> +static int set_guest_cpu_standard(CPUX86State *env)
> +{
> + int family, model, stepping;
> +#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;
> +#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_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 = 0;
> +#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_xlevel = 0x80000008;
> +
> + /* 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
> + return 0;
> +}
> +
> CPUX86State *cpu_x86_init(void)
> {
> CPUX86State *env;
> @@ -80,64 +346,23 @@ CPUX86State *cpu_x86_init(void)
> }
> #endif
> {
> - int family, model, stepping;
> -#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;
> -#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_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 = 0;
> - {
> - 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));
> - }
> + extern int use_hostlike_cpu;
> + if (!use_hostlike_cpu || set_guest_cpu_hostlike(env))
> + set_guest_cpu_standard(env);
> + apply_machine_flavor(env);
> + }
> + {
> + 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_xlevel = 0x80000008;
> -
> - /* 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
> }
> cpu_reset(env);
> #ifdef USE_KQEMU
>
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc.
> Still grepping through log files to find problems? Stop.
> Now Search log events and configuration files using AJAX and a browser.
> Download your FREE copy of Splunk now >> http://get.splunk.com/
> _______________________________________________
> kvm-devel mailing list
> kvm-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/kvm-devel
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-05 19:26 ` [Qemu-devel] Re: [kvm-devel] " Anthony Liguori
@ 2007-09-05 19:34 ` Avi Kivity
2007-09-05 19:44 ` Daniel P. Berrange
2007-09-07 10:47 ` Jamie Lokier
1 sibling, 1 reply; 43+ messages in thread
From: Avi Kivity @ 2007-09-05 19:34 UTC (permalink / raw)
To: Anthony Liguori; +Cc: danken, kvm-devel, qemu-devel
Anthony Liguori wrote:
> On Wed, 2007-09-05 at 20:45 +0300, danken@qumranet.com wrote:
>
>> Hi,
>>
>> It's a pity not to use a host CPU feature if it is available. This patch
>> exposes host CPU features to guests. It allows fine-tuning the presented
>> features from the command-line.
>>
>> The code could use some serious clean ups, but I think it is interesting
>> enough right now. I'd be happy to hear your opinion and suggestions.
>> The diff are done against qemu cvs. I tried it with kvm, but I thinkg it
>> should be useful also for kqemu.
>>
>
> I like this idea but I have some suggestions about the general approach.
> I think instead of defining another machine type, it would be better to
> just have a command line option like -cpuid that took a comma separate
> string of features with "all" meaning all features that the host has.
>
>
I think qemu-cvs has a -cpu option for non-x86 which could be used for
this. Agree machine types are the wrong approach.
> I also think it would be nicer to use cpuid() directly instead of
> attempting to parse /proc/cpuinfo.
>
Yes.
--
Any sufficiently difficult bug is indistinguishable from a feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-05 19:34 ` Avi Kivity
@ 2007-09-05 19:44 ` Daniel P. Berrange
2007-09-06 0:30 ` Paul Brook
0 siblings, 1 reply; 43+ messages in thread
From: Daniel P. Berrange @ 2007-09-05 19:44 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, qemu-devel
On Wed, Sep 05, 2007 at 10:34:45PM +0300, Avi Kivity wrote:
> Anthony Liguori wrote:
> > On Wed, 2007-09-05 at 20:45 +0300, danken@qumranet.com wrote:
> >
> >> Hi,
> >>
> >> It's a pity not to use a host CPU feature if it is available. This patch
> >> exposes host CPU features to guests. It allows fine-tuning the presented
> >> features from the command-line.
> >>
> >> The code could use some serious clean ups, but I think it is interesting
> >> enough right now. I'd be happy to hear your opinion and suggestions.
> >> The diff are done against qemu cvs. I tried it with kvm, but I thinkg it
> >> should be useful also for kqemu.
> >>
> >
> > I like this idea but I have some suggestions about the general approach.
> > I think instead of defining another machine type, it would be better to
> > just have a command line option like -cpuid that took a comma separate
> > string of features with "all" meaning all features that the host has.
> >
> >
>
> I think qemu-cvs has a -cpu option for non-x86 which could be used for
> this. Agree machine types are the wrong approach.
Yep, machine types are already used to switch between a different concept
so using the new -cpu option would make sense. Could perhaps extend the
syntax so that instead of '-cpu TYPE' it used '-cpu TYPE,FEATURES' where
FEATURES was an optional list of CPU features to allow - though perhaps
with some shortcut for specifying 'match the host cpu type & features'.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-05 19:44 ` Daniel P. Berrange
@ 2007-09-06 0:30 ` Paul Brook
2007-09-06 8:46 ` Avi Kivity
0 siblings, 1 reply; 43+ messages in thread
From: Paul Brook @ 2007-09-06 0:30 UTC (permalink / raw)
To: qemu-devel, Daniel P. Berrange; +Cc: kvm-devel
> > I think qemu-cvs has a -cpu option for non-x86 which could be used for
> > this. Agree machine types are the wrong approach.
>
> Yep, machine types are already used to switch between a different concept
> so using the new -cpu option would make sense. Could perhaps extend the
> syntax so that instead of '-cpu TYPE' it used '-cpu TYPE,FEATURES' where
> FEATURES was an optional list of CPU features to allow
I tried this for ARM, and having separate type+features isn't worth the
effort. The internal implementation is feature based, but IMHO there's little
benefit exposing that to the user. Just define appropriate CPUs for the
interesting feature combinations.
Of course the x86 emulation doesn't currently support restricting the
architecture features available. To make the --cpu option useful you need to
implement that first.
Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-06 0:30 ` Paul Brook
@ 2007-09-06 8:46 ` Avi Kivity
0 siblings, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-06 8:46 UTC (permalink / raw)
To: Paul Brook; +Cc: kvm-devel, qemu-devel
Paul Brook wrote:
>>> I think qemu-cvs has a -cpu option for non-x86 which could be used for
>>> this. Agree machine types are the wrong approach.
>>>
>> Yep, machine types are already used to switch between a different concept
>> so using the new -cpu option would make sense. Could perhaps extend the
>> syntax so that instead of '-cpu TYPE' it used '-cpu TYPE,FEATURES' where
>> FEATURES was an optional list of CPU features to allow
>>
>
> I tried this for ARM, and having separate type+features isn't worth the
> effort. The internal implementation is feature based, but IMHO there's little
> benefit exposing that to the user. Just define appropriate CPUs for the
> interesting feature combinations.
>
>
The use case is different. We don't care about the actual features, but
about finding the greatest common denominator in a virtualization farm.
I don't see this as useful for qemu; rather kvm and kqemu.
> Of course the x86 emulation doesn't currently support restricting the
> architecture features available. To make the --cpu option useful you need to
> implement that first.
>
Applications will not use a feature that is not present in cpuid, so
that is not an issue. For the virtualization use case, it is also
impossible to turn off support for a feature.
--
Any sufficiently difficult bug is indistinguishable from a feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] Re: [kvm-devel] expose host CPU features to guests
2007-09-05 19:26 ` [Qemu-devel] Re: [kvm-devel] " Anthony Liguori
2007-09-05 19:34 ` Avi Kivity
@ 2007-09-07 10:47 ` Jamie Lokier
2007-09-09 7:51 ` [kvm-devel] [Qemu-devel] " Avi Kivity
1 sibling, 1 reply; 43+ messages in thread
From: Jamie Lokier @ 2007-09-07 10:47 UTC (permalink / raw)
To: qemu-devel; +Cc: danken, kvm-devel
Anthony Liguori wrote:
> I like this idea but I have some suggestions about the general approach.
> I think instead of defining another machine type, it would be better to
> just have a command line option like -cpuid that took a comma separate
> string of features with "all" meaning all features that the host has.
I like the idea of a flag to enable specific features, but I think
"host" would be a better name for the features of the host.
"all" seems more appropriate to enable all the features the emulator
can support, which can include features which the host does not
support itself.
If it's a comma separated list, it would be good to be able to write
something like this example, which selects all the host features but
then overrides it by disabling the psn feature:
-cpuid host,-psn
Is it intended that these flags will also control the actual features
which Qemu allows or emulates, or only what cpuid reports to the guest?
> I also think it would be nicer to use cpuid() directly instead of
> attempting to parse /proc/cpuinfo.
Occasionally the features in /proc/cpuinfo differ from what the cpuid
instruction reports. They are CPU bug workarounds (features disabled
intentionally even though cpuid reports them), CPU features which
aren't properly reported (enabled intentionally in cpuinfo), and boot
flag requests (features disabled due to request from the boot command
line).
I'm inclined to think the feature list in /proc/cpuinfo is more
appropriate, for choosing the best set of host features to make
available to guests. It's unlikely that Qemu itself will duplicate
the logic of known workarounds for specific, obscure, buggy host CPUs.
There is also /dev/cpu/%d/cpuinfo (for %d = 0, 1, etc.) on some Linux
distros, I think.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-10 12:01 ` Dan Kenigsberg
@ 2007-09-07 16:18 ` Natalia Portillo
2007-09-11 19:48 ` Luke -Jr
2007-09-10 17:16 ` Jamie Lokier
1 sibling, 1 reply; 43+ messages in thread
From: Natalia Portillo @ 2007-09-07 16:18 UTC (permalink / raw)
To: qemu-devel
Hi,
> On Mon, Sep 10, 2007 at 12:47:51PM +0100, Natalia Portillo wrote:
>> I don't see in what is it useful without KVM/KQEMU.
>
> It is not. I tried to be clear about it in my post. Sorry for not being
> clearer.
Ok now understood.
>> And even with them there are some instructions that can't be accesible
>> without KQEMU/KVM prepared for them.
>
> I suspect this is true. For example, in my patch I blocked ACPI and VMX.
> Still, those features that ARE exposed to the guest, speed it up. Isn't
> it the Right Thing?
Well, I prefer to say "it is a right thing" :p
>> And, the -cpu option, should be enabled in x86 and x86_64 to
>> enable/disable emulation of instructions (and them cpuid adjusted to
>> indicate them).
>
> I'm not sure I understand this comment. If you mean that -cpu should not
> expose a feature that is not emulated by qemu, I agree.
I mean there should be a -cpu 8086, 286, 386, 486, pentium, pentium2, so on
If you use 8086, qemu should behave as a 16-bit real-mode only processor
doing an "unknown instruction" exception on anything not defined in the
8086 real processor.
And so on.
And also behave, at identification (CPUID, or legacy identification), like
the selected CPU (for example -cpu 486 says family 4 model x stepping y,
no l2 cache, so on)
This can help some operating systems that hangs on unexpected
identifications (NT 3.xx is the best example, as happens also on real
hardware), and identifying badly implemented instructions on behave of cpu
family (for example, in pentium an OS works flawlessly, in pentium2 an OS
hangs just before sending CMOV instruction).
If you implement it, count with my vote for inclusion :p
(As I think x86, and x86-64 are the only ones archs that still dont
implement -cpu in qemu. and remember, please, x86_64 only composes from
pentium4 upwards and athlon64 upwards, no sense to behave like 386 in
x86-64 emulator lol)
Regards
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-07 10:47 ` Jamie Lokier
@ 2007-09-09 7:51 ` Avi Kivity
2007-09-09 12:47 ` Jamie Lokier
0 siblings, 1 reply; 43+ messages in thread
From: Avi Kivity @ 2007-09-09 7:51 UTC (permalink / raw)
To: Jamie Lokier; +Cc: kvm-devel, qemu-devel
Jamie Lokier wrote:
> Anthony Liguori wrote:
>
>> I like this idea but I have some suggestions about the general approach.
>> I think instead of defining another machine type, it would be better to
>> just have a command line option like -cpuid that took a comma separate
>> string of features with "all" meaning all features that the host has.
>>
>
> I like the idea of a flag to enable specific features, but I think
> "host" would be a better name for the features of the host.
>
> "all" seems more appropriate to enable all the features the emulator
> can support, which can include features which the host does not
> support itself.
>
> If it's a comma separated list, it would be good to be able to write
> something like this example, which selects all the host features but
> then overrides it by disabling the psn feature:
>
> -cpuid host,-psn
>
Yes, 'host' and 'all' make more sense the way you describe them from the
emulator perspective.
> Is it intended that these flags will also control the actual features
> which Qemu allows or emulates, or only what cpuid reports to the guest?
>
>
The cpuid features are sufficient (and there's precedent -- some mobile
intel processors support pae but don't report it).
>> I also think it would be nicer to use cpuid() directly instead of
>> attempting to parse /proc/cpuinfo.
>>
>
> Occasionally the features in /proc/cpuinfo differ from what the cpuid
> instruction reports. They are CPU bug workarounds (features disabled
> intentionally even though cpuid reports them), CPU features which
> aren't properly reported (enabled intentionally in cpuinfo), and boot
> flag requests (features disabled due to request from the boot command
> line).
>
> I'm inclined to think the feature list in /proc/cpuinfo is more
> appropriate, for choosing the best set of host features to make
> available to guests. It's unlikely that Qemu itself will duplicate
> the logic of known workarounds for specific, obscure, buggy host CPUs.
>
> There is also /dev/cpu/%d/cpuinfo (for %d = 0, 1, etc.) on some Linux
> distros, I think.
>
Well, the guest will invoke its own workaround logic to disable buggy
features, so I see no issue here.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 7:51 ` [kvm-devel] [Qemu-devel] " Avi Kivity
@ 2007-09-09 12:47 ` Jamie Lokier
2007-09-09 12:55 ` Avi Kivity
0 siblings, 1 reply; 43+ messages in thread
From: Jamie Lokier @ 2007-09-09 12:47 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, qemu-devel
Avi Kivity wrote:
> Well, the guest will invoke its own workaround logic to disable buggy
> features, so I see no issue here.
The guest can only do this if it has exactly the correct id
information for the host processor (e.g. "This is an Intel Pentium Pro
model XXX"), not just the list of safe to use CPU features.
This isn't possible in a virtualisation cluster of many different CPUs
where the point is to advertise the common set of cpuid features, and
for the guest images to be able to migrate between different CPUs in
the cluster.
Then, the common cpuid features must be found by combining the
/proc/cpuinfo from each node in the cluster. But I guess that's
separate from the part of Qemu we are discussing; it would be done by
another program, preparing the -cpuid argument.
But sometimes it's good to run a simple guest (e.g. someone's pet OS
project, or anything written for Intel only which was more common in
the past) which doesn't have all the detailed obscure workarounds of
something like Linux, but still be able to take advantage of the
workarounds and obscure knowledge in the host.
The alternative is Qemu itself may end up having to have some of these
obscure workarounds :/
For example, the sysenter instruction is advertised on early Pentium
Pros, but it doesn't work. Linux removes it from the features in
/proc/cpuinfo, and doesn't use it. But some guests simply don't get
that obscure, and use it if cpuid advertises it. Of course, they
don't work on a _real_ early Pentium Pro. But it would be nice if
they did work without anything special when run in Qemu on such a
host. That's an old chip which I happen to know about, but I'm sure
there are more modern similar issues.
Perhaps there could be two options then: "-cpuid host-os", and "-cpuid
host-cpuid". I would suggest making "host" an alias for "host-os",
but I wouldn't object if it were an alias for "host-cpuid" or didn't
exist at all, so you had to choose one.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 12:47 ` Jamie Lokier
@ 2007-09-09 12:55 ` Avi Kivity
2007-09-09 13:07 ` Jamie Lokier
0 siblings, 1 reply; 43+ messages in thread
From: Avi Kivity @ 2007-09-09 12:55 UTC (permalink / raw)
To: Jamie Lokier; +Cc: kvm-devel, qemu-devel
Jamie Lokier wrote:
> Avi Kivity wrote:
>
>> Well, the guest will invoke its own workaround logic to disable buggy
>> features, so I see no issue here.
>>
>
> The guest can only do this if it has exactly the correct id
> information for the host processor (e.g. "This is an Intel Pentium Pro
> model XXX"), not just the list of safe to use CPU features.
>
> This isn't possible in a virtualisation cluster of many different CPUs
> where the point is to advertise the common set of cpuid features, and
> for the guest images to be able to migrate between different CPUs in
> the cluster.
>
Well, for a cluster the management software will coordinate all cpuid
features, perhaps taking into account features removed by the host
kernel. "-cpu host" is for the gentoo user who wants to enable all the
nice cpu flags.
> Then, the common cpuid features must be found by combining the
> /proc/cpuinfo from each node in the cluster. But I guess that's
> separate from the part of Qemu we are discussing; it would be done by
> another program, preparing the -cpuid argument.
>
Exactly.
> But sometimes it's good to run a simple guest (e.g. someone's pet OS
> project, or anything written for Intel only which was more common in
> the past) which doesn't have all the detailed obscure workarounds of
> something like Linux, but still be able to take advantage of the
> workarounds and obscure knowledge in the host.
>
> The alternative is Qemu itself may end up having to have some of these
> obscure workarounds :/
>
> For example, the sysenter instruction is advertised on early Pentium
> Pros, but it doesn't work. Linux removes it from the features in
> /proc/cpuinfo, and doesn't use it. But some guests simply don't get
> that obscure, and use it if cpuid advertises it. Of course, they
> don't work on a _real_ early Pentium Pro. But it would be nice if
> they did work without anything special when run in Qemu on such a
> host. That's an old chip which I happen to know about, but I'm sure
> there are more modern similar issues.
>
> Perhaps there could be two options then: "-cpuid host-os", and "-cpuid
> host-cpuid". I would suggest making "host" an alias for "host-os",
> but I wouldn't object if it were an alias for "host-cpuid" or didn't
> exist at all, so you had to choose one.
>
Let's start with '-cpu host' as 'cpu host-cpuid' and implement '-cpu
host-os' on the first bug report? I have a feeling we won't ever see it.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 12:55 ` Avi Kivity
@ 2007-09-09 13:07 ` Jamie Lokier
2007-09-09 13:14 ` Avi Kivity
2007-09-09 15:25 ` Paul Brook
0 siblings, 2 replies; 43+ messages in thread
From: Jamie Lokier @ 2007-09-09 13:07 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, qemu-devel
Avi Kivity wrote:
> Let's start with '-cpu host' as 'cpu host-cpuid' and implement '-cpu
> host-os' on the first bug report? I have a feeling we won't ever see it.
I have a feeling you won't ever see it either, but not because it's a
missing feature.
Instead, I think a very small number of users will spend hours
frustrated that some obscure guest doesn't work properly on their
obscure x86 hardware, then they will learn that they should not use
"-cpuid host" for that guest on that hardware, even though it works
fine with other guests, and then their problem will be solved (albeit
at a cost), and seen as such an obscure combination that it might
never be reported to Qemu developers.
In other words, host-os is what _I'd_ implement because I care too
much about the poor obscure users and think it's the safe option, but
I'm not doing the implementing here ;-)
If you are curious what the differences are, do this in a current
Linux source tree:
egrep -R '(set|clear)_bit\(X86_FEATURE' arch/{i386,x86_64}/kernel
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 13:07 ` Jamie Lokier
@ 2007-09-09 13:14 ` Avi Kivity
2007-09-09 15:25 ` Paul Brook
1 sibling, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-09 13:14 UTC (permalink / raw)
To: Jamie Lokier; +Cc: kvm-devel, qemu-devel
Jamie Lokier wrote:
> Avi Kivity wrote:
>
>> Let's start with '-cpu host' as 'cpu host-cpuid' and implement '-cpu
>> host-os' on the first bug report? I have a feeling we won't ever see it.
>>
>
> I have a feeling you won't ever see it either, but not because it's a
> missing feature.
>
> Instead, I think a very small number of users will spend hours
> frustrated that some obscure guest doesn't work properly on their
> obscure x86 hardware, then they will learn that they should not use
> "-cpuid host" for that guest on that hardware, even though it works
> fine with other guests, and then their problem will be solved (albeit
> at a cost), and seen as such an obscure combination that it might
> never be reported to Qemu developers.
>
> In other words, host-os is what _I'd_ implement because I care too
> much about the poor obscure users and think it's the safe option, but
> I'm not doing the implementing here ;-)
>
> If you are curious what the differences are, do this in a current
> Linux source tree:
>
> egrep -R '(set|clear)_bit\(X86_FEATURE' arch/{i386,x86_64}/kernel
>
>
Some of these are Linux issues, not host cpu issues (for example, it
looks like VMI disables global pages).
Some of these issues may not impact the guest and we'd be removing them
unnecessarily. Also, kvm doesn't run on obscure hardware (although
kqemu does; qemu itself is not a candidate for -cpu host).
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 13:07 ` Jamie Lokier
2007-09-09 13:14 ` Avi Kivity
@ 2007-09-09 15:25 ` Paul Brook
2007-09-09 15:29 ` Avi Kivity
1 sibling, 1 reply; 43+ messages in thread
From: Paul Brook @ 2007-09-09 15:25 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel
On Sunday 09 September 2007, Jamie Lokier wrote:
> Avi Kivity wrote:
> > Let's start with '-cpu host' as 'cpu host-cpuid' and implement '-cpu
> > host-os' on the first bug report? I have a feeling we won't ever see it.
>
> In other words, host-os is what _I'd_ implement because I care too
> much about the poor obscure users and think it's the safe option, but
> I'm not doing the implementing here ;-)
I agree. If the host OS has disabled a feature, it's a fair bet it's done that
for a reason.
What you really want to do is ask your virtualization module what features it
supports.
Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 15:25 ` Paul Brook
@ 2007-09-09 15:29 ` Avi Kivity
2007-09-09 15:47 ` Jamie Lokier
2007-09-09 16:12 ` Paul Brook
0 siblings, 2 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-09 15:29 UTC (permalink / raw)
To: Paul Brook; +Cc: kvm-devel, qemu-devel
Paul Brook wrote:
> On Sunday 09 September 2007, Jamie Lokier wrote:
>
>> Avi Kivity wrote:
>>
>>> Let's start with '-cpu host' as 'cpu host-cpuid' and implement '-cpu
>>> host-os' on the first bug report? I have a feeling we won't ever see it.
>>>
>> In other words, host-os is what _I'd_ implement because I care too
>> much about the poor obscure users and think it's the safe option, but
>> I'm not doing the implementing here ;-)
>>
>
> I agree. If the host OS has disabled a feature, it's a fair bet it's done that
> for a reason.
>
>
The reason may not be relevant to the guest.
> What you really want to do is ask your virtualization module what features it
> supports.
>
Yes, that needs to be an additional filter.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 15:29 ` Avi Kivity
@ 2007-09-09 15:47 ` Jamie Lokier
2007-09-09 16:12 ` Paul Brook
1 sibling, 0 replies; 43+ messages in thread
From: Jamie Lokier @ 2007-09-09 15:47 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, Paul Brook, qemu-devel
Avi Kivity wrote:
> >I agree. If the host OS has disabled a feature, it's a fair bet it's done
> >that for a reason.
>
> The reason may not be relevant to the guest.
For most guests the relevant features are those which work correctly
and efficiently on the virtual CPU.
If the host OS has disabled a feature, most often that's because the
feature doesn't work on the specific host CPU model, but not always.
It might be emulated well, but probably not efficiently.
In some cases, you might want a guest to see features supported by the
host CPU which the host OS has disabled, but I imagine those are
unusual - it doesn't seem very likely. Can you give an example?
They can be enabled explicitly by the -cpuid flag if needed.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 15:29 ` Avi Kivity
2007-09-09 15:47 ` Jamie Lokier
@ 2007-09-09 16:12 ` Paul Brook
2007-09-09 16:38 ` Avi Kivity
2007-09-10 16:53 ` Jamie Lokier
1 sibling, 2 replies; 43+ messages in thread
From: Paul Brook @ 2007-09-09 16:12 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel
> > What you really want to do is ask your virtualization module what
> > features it supports.
>
> Yes, that needs to be an additional filter.
I'd have thought that would be the *only* interesting set for autodetection.
Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 16:12 ` Paul Brook
@ 2007-09-09 16:38 ` Avi Kivity
2007-09-10 16:53 ` Jamie Lokier
1 sibling, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-09 16:38 UTC (permalink / raw)
To: Paul Brook; +Cc: kvm-devel, qemu-devel
Paul Brook wrote:
>>> What you really want to do is ask your virtualization module what
>>> features it supports.
>>>
>> Yes, that needs to be an additional filter.
>>
>
> I'd have thought that would be the *only* interesting set for autodetection.
>
>
Yes, you're right. It's pointless to issue cpuid in userspace and mask
it in the kernel; rather we can issue it in the kernel , mask out
unsupported features, and return it to userspace.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-05 17:45 [Qemu-devel] expose host CPU features to guests danken
2007-09-05 19:26 ` [Qemu-devel] Re: [kvm-devel] " Anthony Liguori
@ 2007-09-10 7:40 ` Dan Kenigsberg
2007-09-10 11:47 ` Natalia Portillo
2007-09-24 17:41 ` [Qemu-devel] expose host CPU features to guests: Take 3 Dan Kenigsberg
1 sibling, 2 replies; 43+ messages in thread
From: Dan Kenigsberg @ 2007-09-10 7:40 UTC (permalink / raw)
To: qemu-devel, kvm-devel
As with Take 1 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.
I changed the patch according to the comments on these mailing lists. Thanks
for your suggestions. Changes since "take 1" are:
- Use the new -cpu option to specify cpu features.
- Read host cpuid directly, instead of parsing /proc/cpuinfo. This approach is
less Linux-centric and should work with other OSs too. It means however, that
the cpuid is not checked for old CPU bugs. In the future, qemu should
negotiate the actually-supported features with the virutalizing kernel
module.
Index: hw/pc.c
===================================================================
RCS file: /sources/qemu/qemu/hw/pc.c,v
retrieving revision 1.83
diff -u -r1.83 pc.c
--- hw/pc.c 26 Aug 2007 17:51:39 -0000 1.83
+++ hw/pc.c 10 Sep 2007 06:54:00 -0000
@@ -666,7 +666,7 @@
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, char *cpu_model)
{
char buf[1024];
int ret, linux_boot, i;
@@ -683,7 +683,9 @@
/* init CPUs */
for(i = 0; i < smp_cpus; i++) {
+ void apply_i386_cpu_model(CPUX86State *env, char *cpu_model);
env = cpu_init();
+ apply_i386_cpu_model(env, cpu_model);
if (i != 0)
env->hflags |= HF_HALTED_MASK;
if (smp_cpus > 1) {
@@ -948,7 +950,7 @@
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 +964,7 @@
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.45
diff -u -r1.45 cpu.h
--- target-i386/cpu.h 11 Jul 2007 22:48:58 -0000 1.45
+++ target-i386/cpu.h 10 Sep 2007 06:54:00 -0000
@@ -267,21 +267,44 @@
#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 EXCP00_DIVZ 0
#define EXCP01_SSTP 1
Index: target-i386/helper2.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper2.c,v
retrieving revision 1.48
diff -u -r1.48 helper2.c
--- target-i386/helper2.c 31 Jul 2007 23:09:18 -0000 1.48
+++ target-i386/helper2.c 10 Sep 2007 06:54:00 -0000
@@ -45,40 +45,8 @@
#endif
#endif /* USE_CODE_COPY */
-CPUX86State *cpu_x86_init(void)
+static int set_guest_cpu_basic(CPUX86State *env)
{
- CPUX86State *env;
- static int inited;
-
- env = qemu_mallocz(sizeof(CPUX86State));
- if (!env)
- return NULL;
- cpu_exec_init(env);
-
- /* init various static tables */
- if (!inited) {
- inited = 1;
- optimize_flags_init();
- }
-#ifdef USE_CODE_COPY
- /* testing code for code copy case */
- {
- struct modify_ldt_ldt_s ldt;
-
- ldt.entry_number = 1;
- ldt.base_addr = (unsigned long)env;
- ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
- ldt.seg_32bit = 1;
- ldt.contents = MODIFY_LDT_CONTENTS_DATA;
- ldt.read_exec_only = 0;
- ldt.limit_in_pages = 1;
- ldt.seg_not_present = 0;
- ldt.useable = 1;
- modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
-
- asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
- }
-#endif
{
int family, model, stepping;
#ifdef TARGET_X86_64
@@ -114,19 +82,7 @@
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 = 0;
- {
- 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));
- }
- }
+ env->cpuid_xlevel = 0x80000006;
#ifdef TARGET_X86_64
/* currently not enabled for std i386 because not fully tested */
env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
@@ -139,6 +95,239 @@
env->cpuid_features |= CPUID_PSE36;
#endif
}
+}
+
+static int 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));
+}
+
+static int set_guest_cpu_hostlike(CPUX86State *env) {
+ uint32_t ax, bx, cx, dx;
+ host_cpuid(0, &ax, &bx, &cx, &dx);
+ env->cpuid_level = 2; /* host real level is ax */
+ env->cpuid_vendor1 = bx;
+ env->cpuid_vendor2 = dx;
+ env->cpuid_vendor3 = cx;
+
+ host_cpuid(1, &ax, &bx, &cx, &dx);
+ env->cpuid_version = ax;
+ env->cpuid_features = dx & ~CPUID_ACPI; /* acpi panics linux guests */
+ env->cpuid_ext_features = cx & ~CPUID_EXT_VMX; /* vmx is not recursive */
+
+ /* cpuid(0x80000000, &ax, &bx, &cx, &dx); */
+ env->cpuid_xlevel = 0x80000008;
+
+ host_cpuid(0x80000001, &ax, &bx, &cx, &dx);
+ env->cpuid_ext2_features = dx;
+
+ return 0;
+}
+
+/* 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, int *features, int *ext_features, int *ext2_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;
+ }
+ /* 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);
+}
+
+
+void apply_i386_cpu_model(CPUX86State *env, char *cpu_model)
+{
+ int plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0;
+ int minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0;
+ int family = -1, model = -1, stepping = -1;
+
+ char *s, *featurestr;
+
+ if (!cpu_model)
+ cpu_model = "host";
+
+ s = strdup(cpu_model);
+
+ strtok(s, ",");
+ if (!strcmp(s, "basic"))
+ set_guest_cpu_basic(env);
+ else if (!strcmp(s, "host"))
+ set_guest_cpu_hostlike(env);
+ else {
+ printf("Available CPUs:\n");
+ printf("(basic|host)[,(+feature|-feature|feature=xyz)]...\n");
+ exit(1);
+ }
+
+ featurestr = strtok(NULL, ",");
+ while (featurestr) {
+ char *val;
+ if (featurestr[0] == '+') {
+ add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features);
+ }
+ else if (featurestr[0] == '-') {
+ add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features);
+ }
+ else if ((val = strchr(featurestr, '='))) {
+ *val = 0; val++;
+ if (!strcmp(featurestr, "family")) {
+ family = atoi(val);
+ if (family <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFF;
+ env->cpuid_version |= (family << 8);
+ } else if (!strcmp(featurestr, "model")) {
+ model = atoi(val);
+ if (model <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFFFFFF0F;
+ env->cpuid_version |= (model << 4);
+ } else if (!strcmp(featurestr, "stepping")) {
+ stepping = atoi(val);
+ if (stepping <= 0) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ exit(1);
+ }
+ env->cpuid_version &= 0xFFFFFFF0;
+ env->cpuid_version |= stepping;
+ } else {
+ fprintf(stderr, "unknown feature %s\n", featurestr);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
+ exit(1);
+ }
+ featurestr = strtok(NULL, ",");
+ }
+ free(s);
+ env->cpuid_features |= plus_features;
+ env->cpuid_ext_features |= plus_ext_features;
+ env->cpuid_ext2_features |= plus_ext2_features;
+ env->cpuid_features &= ~minus_features;
+ env->cpuid_ext_features &= ~minus_ext_features;
+ env->cpuid_ext2_features &= ~minus_ext2_features;
+
+ {
+ 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));
+ }
+ }
+}
+
+CPUX86State *cpu_x86_init(void)
+{
+ CPUX86State *env;
+ static int inited;
+
+ env = qemu_mallocz(sizeof(CPUX86State));
+ if (!env)
+ return NULL;
+ cpu_exec_init(env);
+
+ /* init various static tables */
+ if (!inited) {
+ inited = 1;
+ optimize_flags_init();
+ }
+#ifdef USE_CODE_COPY
+ /* testing code for code copy case */
+ {
+ struct modify_ldt_ldt_s ldt;
+
+ ldt.entry_number = 1;
+ ldt.base_addr = (unsigned long)env;
+ ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
+ ldt.seg_32bit = 1;
+ ldt.contents = MODIFY_LDT_CONTENTS_DATA;
+ ldt.read_exec_only = 0;
+ ldt.limit_in_pages = 1;
+ ldt.seg_not_present = 0;
+ ldt.useable = 1;
+ modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
+
+ asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
+ }
+#endif
cpu_reset(env);
#ifdef USE_KQEMU
kqemu_init(env);
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-10 7:40 ` [Qemu-devel] expose host CPU features to guests: Take 2 Dan Kenigsberg
@ 2007-09-10 11:47 ` Natalia Portillo
2007-09-10 12:01 ` Dan Kenigsberg
2007-09-24 17:41 ` [Qemu-devel] expose host CPU features to guests: Take 3 Dan Kenigsberg
1 sibling, 1 reply; 43+ messages in thread
From: Natalia Portillo @ 2007-09-10 11:47 UTC (permalink / raw)
To: qemu-devel
I don't see in what is it useful without KVM/KQEMU.
And even with them there are some instructions that can't be accesible
without KQEMU/KVM prepared for them.
And, the -cpu option, should be enabled in x86 and x86_64 to
enable/disable emulation of instructions (and them cpuid adjusted to
indicate them).
Regards
On Mon, 10 Sep 2007 08:40:05 +0100, Dan Kenigsberg <danken@qumranet.com>
wrote:
> As with Take 1 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.
>
> I changed the patch according to the comments on these mailing lists.
> Thanks
> for your suggestions. Changes since "take 1" are:
> - Use the new -cpu option to specify cpu features.
> - Read host cpuid directly, instead of parsing /proc/cpuinfo. This
> approach is
> less Linux-centric and should work with other OSs too. It means
> however, that
> the cpuid is not checked for old CPU bugs. In the future, qemu should
> negotiate the actually-supported features with the virutalizing kernel
> module.
>
> Index: hw/pc.c
> ===================================================================
> RCS file: /sources/qemu/qemu/hw/pc.c,v
> retrieving revision 1.83
> diff -u -r1.83 pc.c
> --- hw/pc.c 26 Aug 2007 17:51:39 -0000 1.83
> +++ hw/pc.c 10 Sep 2007 06:54:00 -0000
> @@ -666,7 +666,7 @@
> 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, char *cpu_model)
> {
> char buf[1024];
> int ret, linux_boot, i;
> @@ -683,7 +683,9 @@
> /* init CPUs */
> for(i = 0; i < smp_cpus; i++) {
> + void apply_i386_cpu_model(CPUX86State *env, char *cpu_model);
> env = cpu_init();
> + apply_i386_cpu_model(env, cpu_model);
> if (i != 0)
> env->hflags |= HF_HALTED_MASK;
> if (smp_cpus > 1) {
> @@ -948,7 +950,7 @@
> 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 +964,7 @@
> 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.45
> diff -u -r1.45 cpu.h
> --- target-i386/cpu.h 11 Jul 2007 22:48:58 -0000 1.45
> +++ target-i386/cpu.h 10 Sep 2007 06:54:00 -0000
> @@ -267,21 +267,44 @@
> #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 EXCP00_DIVZ 0
> #define EXCP01_SSTP 1
> Index: target-i386/helper2.c
> ===================================================================
> RCS file: /sources/qemu/qemu/target-i386/helper2.c,v
> retrieving revision 1.48
> diff -u -r1.48 helper2.c
> --- target-i386/helper2.c 31 Jul 2007 23:09:18 -0000 1.48
> +++ target-i386/helper2.c 10 Sep 2007 06:54:00 -0000
> @@ -45,40 +45,8 @@
> #endif
> #endif /* USE_CODE_COPY */
> -CPUX86State *cpu_x86_init(void)
> +static int set_guest_cpu_basic(CPUX86State *env)
> {
> - CPUX86State *env;
> - static int inited;
> -
> - env = qemu_mallocz(sizeof(CPUX86State));
> - if (!env)
> - return NULL;
> - cpu_exec_init(env);
> -
> - /* init various static tables */
> - if (!inited) {
> - inited = 1;
> - optimize_flags_init();
> - }
> -#ifdef USE_CODE_COPY
> - /* testing code for code copy case */
> - {
> - struct modify_ldt_ldt_s ldt;
> -
> - ldt.entry_number = 1;
> - ldt.base_addr = (unsigned long)env;
> - ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
> - ldt.seg_32bit = 1;
> - ldt.contents = MODIFY_LDT_CONTENTS_DATA;
> - ldt.read_exec_only = 0;
> - ldt.limit_in_pages = 1;
> - ldt.seg_not_present = 0;
> - ldt.useable = 1;
> - modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
> -
> - asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
> - }
> -#endif
> {
> int family, model, stepping;
> #ifdef TARGET_X86_64
> @@ -114,19 +82,7 @@
> 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 = 0;
> - {
> - 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));
> - }
> - }
> + env->cpuid_xlevel = 0x80000006;
> #ifdef TARGET_X86_64
> /* currently not enabled for std i386 because not fully tested
> */
> env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
> @@ -139,6 +95,239 @@
> env->cpuid_features |= CPUID_PSE36;
> #endif
> }
> +}
> +
> +static int 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));
> +}
> +
> +static int set_guest_cpu_hostlike(CPUX86State *env) {
> + uint32_t ax, bx, cx, dx;
> + host_cpuid(0, &ax, &bx, &cx, &dx);
> + env->cpuid_level = 2; /* host real level is ax */
> + env->cpuid_vendor1 = bx;
> + env->cpuid_vendor2 = dx;
> + env->cpuid_vendor3 = cx;
> +
> + host_cpuid(1, &ax, &bx, &cx, &dx);
> + env->cpuid_version = ax;
> + env->cpuid_features = dx & ~CPUID_ACPI; /* acpi panics linux guests
> */
> + env->cpuid_ext_features = cx & ~CPUID_EXT_VMX; /* vmx is not
> recursive */
> +
> + /* cpuid(0x80000000, &ax, &bx, &cx, &dx); */
> + env->cpuid_xlevel = 0x80000008;
> +
> + host_cpuid(0x80000001, &ax, &bx, &cx, &dx);
> + env->cpuid_ext2_features = dx;
> +
> + return 0;
> +}
> +
> +/* 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, int *features, int
> *ext_features, int *ext2_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;
> + }
> + /* 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);
> +}
> +
> +
> +void apply_i386_cpu_model(CPUX86State *env, char *cpu_model)
> +{
> + int plus_features = 0, plus_ext_features = 0, plus_ext2_features =
> 0;
> + int minus_features = 0, minus_ext_features = 0, minus_ext2_features
> = 0;
> + int family = -1, model = -1, stepping = -1;
> +
> + char *s, *featurestr;
> +
> + if (!cpu_model)
> + cpu_model = "host";
> +
> + s = strdup(cpu_model);
> +
> + strtok(s, ",");
> + if (!strcmp(s, "basic"))
> + set_guest_cpu_basic(env);
> + else if (!strcmp(s, "host"))
> + set_guest_cpu_hostlike(env);
> + else {
> + printf("Available CPUs:\n");
> + printf("(basic|host)[,(+feature|-feature|feature=xyz)]...\n");
> + exit(1);
> + }
> +
> + featurestr = strtok(NULL, ",");
> + while (featurestr) {
> + char *val;
> + if (featurestr[0] == '+') {
> + add_flagname_to_bitmaps(featurestr + 1, &plus_features,
> &plus_ext_features, &plus_ext2_features);
> + }
> + else if (featurestr[0] == '-') {
> + add_flagname_to_bitmaps(featurestr + 1, &minus_features,
> &minus_ext_features, &minus_ext2_features);
> + }
> + else if ((val = strchr(featurestr, '='))) {
> + *val = 0; val++;
> + if (!strcmp(featurestr, "family")) {
> + family = atoi(val);
> + if (family <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFF;
> + env->cpuid_version |= (family << 8);
> + } else if (!strcmp(featurestr, "model")) {
> + model = atoi(val);
> + if (model <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFFFFFF0F;
> + env->cpuid_version |= (model << 4);
> + } else if (!strcmp(featurestr, "stepping")) {
> + stepping = atoi(val);
> + if (stepping <= 0) {
> + fprintf(stderr, "bad numerical value %s\n", val);
> + exit(1);
> + }
> + env->cpuid_version &= 0xFFFFFFF0;
> + env->cpuid_version |= stepping;
> + } else {
> + fprintf(stderr, "unknown feature %s\n", featurestr);
> + exit(1);
> + }
> + } else {
> + fprintf(stderr, "feature string `%s' not in format
> (+feature|-feature|feature=xyz)\n", featurestr);
> + exit(1);
> + }
> + featurestr = strtok(NULL, ",");
> + }
> + free(s);
> + env->cpuid_features |= plus_features;
> + env->cpuid_ext_features |= plus_ext_features;
> + env->cpuid_ext2_features |= plus_ext2_features;
> + env->cpuid_features &= ~minus_features;
> + env->cpuid_ext_features &= ~minus_ext_features;
> + env->cpuid_ext2_features &= ~minus_ext2_features;
> +
> + {
> + 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));
> + }
> + }
> +}
> +
> +CPUX86State *cpu_x86_init(void)
> +{
> + CPUX86State *env;
> + static int inited;
> +
> + env = qemu_mallocz(sizeof(CPUX86State));
> + if (!env)
> + return NULL;
> + cpu_exec_init(env);
> +
> + /* init various static tables */
> + if (!inited) {
> + inited = 1;
> + optimize_flags_init();
> + }
> +#ifdef USE_CODE_COPY
> + /* testing code for code copy case */
> + {
> + struct modify_ldt_ldt_s ldt;
> +
> + ldt.entry_number = 1;
> + ldt.base_addr = (unsigned long)env;
> + ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
> + ldt.seg_32bit = 1;
> + ldt.contents = MODIFY_LDT_CONTENTS_DATA;
> + ldt.read_exec_only = 0;
> + ldt.limit_in_pages = 1;
> + ldt.seg_not_present = 0;
> + ldt.useable = 1;
> + modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
> +
> + asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
> + }
> +#endif
> cpu_reset(env);
> #ifdef USE_KQEMU
> kqemu_init(env);
>
>
>
--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-10 11:47 ` Natalia Portillo
@ 2007-09-10 12:01 ` Dan Kenigsberg
2007-09-07 16:18 ` Natalia Portillo
2007-09-10 17:16 ` Jamie Lokier
0 siblings, 2 replies; 43+ messages in thread
From: Dan Kenigsberg @ 2007-09-10 12:01 UTC (permalink / raw)
To: qemu-devel
On Mon, Sep 10, 2007 at 12:47:51PM +0100, Natalia Portillo wrote:
> I don't see in what is it useful without KVM/KQEMU.
It is not. I tried to be clear about it in my post. Sorry for not being
clearer.
> And even with them there are some instructions that can't be accesible
> without KQEMU/KVM prepared for them.
I suspect this is true. For example, in my patch I blocked ACPI and VMX.
Still, those features that ARE exposed to the guest, speed it up. Isn't
it the Right Thing?
> And, the -cpu option, should be enabled in x86 and x86_64 to
> enable/disable emulation of instructions (and them cpuid adjusted to
> indicate them).
I'm not sure I understand this comment. If you mean that -cpu should not
expose a feature that is not emulated by qemu, I agree.
Regards,
Dan.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] Re: expose host CPU features to guests
2007-09-09 16:12 ` Paul Brook
2007-09-09 16:38 ` Avi Kivity
@ 2007-09-10 16:53 ` Jamie Lokier
1 sibling, 0 replies; 43+ messages in thread
From: Jamie Lokier @ 2007-09-10 16:53 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel
Paul Brook wrote:
> > > What you really want to do is ask your virtualization module what
> > > features it supports.
> >
> > Yes, that needs to be an additional filter.
>
> I'd have thought that would be the *only* interesting set for autodetection.
If that means the same as the features which are efficient for the
guest, then I agree. If there's a difference, I'd have thought you'd
normally want the guest to use only those features which work at
near-native performance, not those which involve a trap and long path
through the virtualisation/emulation, even if they're supported. No
example comes to mind, but that seems like the principle to go for, to
me.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-10 12:01 ` Dan Kenigsberg
2007-09-07 16:18 ` Natalia Portillo
@ 2007-09-10 17:16 ` Jamie Lokier
1 sibling, 0 replies; 43+ messages in thread
From: Jamie Lokier @ 2007-09-10 17:16 UTC (permalink / raw)
To: qemu-devel
Dan Kenigsberg wrote:
> On Mon, Sep 10, 2007 at 12:47:51PM +0100, Natalia Portillo wrote:
> > I don't see in what is it useful without KVM/KQEMU.
>
> It is not. I tried to be clear about it in my post. Sorry for not being
> clearer.
Some day it may be useful without KVM/KQEMU, but not for a long time.
There are instructions, for example MMX/SSE, which might be translated
efficiently to single instructions on some host CPUs but to long
function calls on others. But that won't happen until the translation
back end is quite a lot more sophisticated than it is now.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 2
2007-09-07 16:18 ` Natalia Portillo
@ 2007-09-11 19:48 ` Luke -Jr
0 siblings, 0 replies; 43+ messages in thread
From: Luke -Jr @ 2007-09-11 19:48 UTC (permalink / raw)
To: qemu-devel
On Friday 07 September 2007, Natalia Portillo wrote:
> and remember, please, x86_64 only composes from pentium4 upwards and
> athlon64 upwards, no sense to behave like 386 in x86-64 emulator lol)
Actually, there is. Isn't the x86_64 emulator required to use kqemu on x86_64?
Or does the -cpu 486 only apply to raw emulation mode anyway?
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-10 7:40 ` [Qemu-devel] expose host CPU features to guests: Take 2 Dan Kenigsberg
2007-09-10 11:47 ` Natalia Portillo
@ 2007-09-24 17:41 ` Dan Kenigsberg
2007-09-25 1:28 ` andrzej zaborowski
2007-10-07 12:38 ` [Qemu-devel] x86 -cpu option: Take 4 Dan Kenigsberg
1 sibling, 2 replies; 43+ messages in thread
From: Dan Kenigsberg @ 2007-09-24 17:41 UTC (permalink / raw)
To: qemu-devel, kvm-devel
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;
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-24 17:41 ` [Qemu-devel] expose host CPU features to guests: Take 3 Dan Kenigsberg
@ 2007-09-25 1:28 ` andrzej zaborowski
2007-09-25 8:48 ` [kvm-devel] " Dan Kenigsberg
2007-09-25 9:29 ` Fabrice Bellard
2007-10-07 12:38 ` [Qemu-devel] x86 -cpu option: Take 4 Dan Kenigsberg
1 sibling, 2 replies; 43+ messages in thread
From: andrzej zaborowski @ 2007-09-25 1:28 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel
Hi,
On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
> 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));
> +}
I haven't really read through the rest of your code but this piece
appears to be outside any #ifdef/#endif so it will only build on x86.
Regards
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 1:28 ` andrzej zaborowski
@ 2007-09-25 8:48 ` Dan Kenigsberg
2007-09-25 9:01 ` Avi Kivity
2007-09-25 9:29 ` Fabrice Bellard
1 sibling, 1 reply; 43+ messages in thread
From: Dan Kenigsberg @ 2007-09-25 8:48 UTC (permalink / raw)
To: andrzej zaborowski; +Cc: kvm-devel, qemu-devel
On Tue, Sep 25, 2007 at 03:28:24AM +0200, andrzej zaborowski wrote:
> Hi,
>
> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
> > As with previous "Takes" of this patch, its purpose is to expose host
> > +{
> > + asm("cpuid"
> > + : "=a" (*ax),
> > + "=b" (*bx),
> > + "=c" (*cx),
> > + "=d" (*dx)
> > + : "a" (function));
> > +}
>
> I haven't really read through the rest of your code but this piece
> appears to be outside any #ifdef/#endif so it will only build on x86.
I might be missing something here, but isn't not being on the
TARGET_PATH of Makefile.target enough? I don't see #ifdef TARGET_I386
elsewhere under target-i386. I don't mind adding extra protection, I
just be happy to better understand the whats and whys.
Dan.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 8:48 ` [kvm-devel] " Dan Kenigsberg
@ 2007-09-25 9:01 ` Avi Kivity
2007-09-25 9:19 ` J. Mayer
0 siblings, 1 reply; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 9:01 UTC (permalink / raw)
To: Dan Kenigsberg; +Cc: kvm-devel, qemu-devel
Dan Kenigsberg wrote:
> On Tue, Sep 25, 2007 at 03:28:24AM +0200, andrzej zaborowski wrote:
>
>> Hi,
>>
>> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
>>
>>> As with previous "Takes" of this patch, its purpose is to expose host
>>> +{
>>> + asm("cpuid"
>>> + : "=a" (*ax),
>>> + "=b" (*bx),
>>> + "=c" (*cx),
>>> + "=d" (*dx)
>>> + : "a" (function));
>>> +}
>>>
>> I haven't really read through the rest of your code but this piece
>> appears to be outside any #ifdef/#endif so it will only build on x86.
>>
>
> I might be missing something here, but isn't not being on the
> TARGET_PATH of Makefile.target enough? I don't see #ifdef TARGET_I386
> elsewhere under target-i386. I don't mind adding extra protection, I
> just be happy to better understand the whats and whys.
>
target-i386 means the guest will run i386 instructions, but the host can
be something else (say, powerpc).
Nothing else uses host instructions in that directory, so no protection
was necessary before.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 9:01 ` Avi Kivity
@ 2007-09-25 9:19 ` J. Mayer
2007-09-25 9:31 ` Avi Kivity
0 siblings, 1 reply; 43+ messages in thread
From: J. Mayer @ 2007-09-25 9:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Dan Kenigsberg, kvm-devel
On Tue, 2007-09-25 at 11:01 +0200, Avi Kivity wrote:
> Dan Kenigsberg wrote:
> > On Tue, Sep 25, 2007 at 03:28:24AM +0200, andrzej zaborowski wrote:
> >
> >> Hi,
> >>
> >> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
> >>
> >>> As with previous "Takes" of this patch, its purpose is to expose host
> >>> +{
> >>> + asm("cpuid"
> >>> + : "=a" (*ax),
> >>> + "=b" (*bx),
> >>> + "=c" (*cx),
> >>> + "=d" (*dx)
> >>> + : "a" (function));
> >>> +}
> >>>
> >> I haven't really read through the rest of your code but this piece
> >> appears to be outside any #ifdef/#endif so it will only build on x86.
> >>
> >
> > I might be missing something here, but isn't not being on the
> > TARGET_PATH of Makefile.target enough? I don't see #ifdef TARGET_I386
> > elsewhere under target-i386. I don't mind adding extra protection, I
> > just be happy to better understand the whats and whys.
> >
>
> target-i386 means the guest will run i386 instructions, but the host can
> be something else (say, powerpc).
>
> Nothing else uses host instructions in that directory, so no protection
> was necessary before.
I've got a remark about this: why this has to be added to the Qemu
code ?
Imho, all is needed is an implementation of the -cpu option for
x86/x86_64 target. Then, an external tool (even a shell script) can be
used to determine what is the host CPU if you want to select the exact
same CPU to be emulated in Qemu. It seems to me that trying to do so is
out of the scope of Qemu code and just add unneeded complexity.
Regards.
--
J. Mayer <l_indien@magic.fr>
Never organized
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 1:28 ` andrzej zaborowski
2007-09-25 8:48 ` [kvm-devel] " Dan Kenigsberg
@ 2007-09-25 9:29 ` Fabrice Bellard
1 sibling, 0 replies; 43+ messages in thread
From: Fabrice Bellard @ 2007-09-25 9:29 UTC (permalink / raw)
To: qemu-devel
andrzej zaborowski wrote:
> Hi,
>
> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
>
>>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.
>>[...]
> I haven't really read through the rest of your code but this piece
> appears to be outside any #ifdef/#endif so it will only build on x86.
>
> Regards
A few remarks:
1) I cannot accept GPL code in target-i386, so the code from the Linux
kernel must be removed or rewritten.
2) cpuid is already defined in kqemu.c, so it would be better to use it
(I consider this is not a blocking point though).
3) For the future, I suggest that the function cpu_xxx_register() is
removed and that the parameter xxx_def_t is added to cpu_xxx_init().
Rationale: I see no point in initializing a CPU without specifying its
exact model and I am not sure that cpu_xxx_register() can be called once
some code is executed.
Regards,
Fabrice.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 9:19 ` J. Mayer
@ 2007-09-25 9:31 ` Avi Kivity
2007-09-25 10:40 ` Avi Kivity
2007-09-25 12:51 ` Paul Brook
0 siblings, 2 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 9:31 UTC (permalink / raw)
To: J. Mayer; +Cc: kvm-devel, qemu-devel
J. Mayer wrote:
> On Tue, 2007-09-25 at 11:01 +0200, Avi Kivity wrote:
>
>> Dan Kenigsberg wrote:
>>
>>> On Tue, Sep 25, 2007 at 03:28:24AM +0200, andrzej zaborowski wrote:
>>>
>>>
>>>> Hi,
>>>>
>>>> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
>>>>
>>>>
>>>>> As with previous "Takes" of this patch, its purpose is to expose host
>>>>> +{
>>>>> + asm("cpuid"
>>>>> + : "=a" (*ax),
>>>>> + "=b" (*bx),
>>>>> + "=c" (*cx),
>>>>> + "=d" (*dx)
>>>>> + : "a" (function));
>>>>> +}
>>>>>
>>>>>
>>>> I haven't really read through the rest of your code but this piece
>>>> appears to be outside any #ifdef/#endif so it will only build on x86.
>>>>
>>>>
>>> I might be missing something here, but isn't not being on the
>>> TARGET_PATH of Makefile.target enough? I don't see #ifdef TARGET_I386
>>> elsewhere under target-i386. I don't mind adding extra protection, I
>>> just be happy to better understand the whats and whys.
>>>
>>>
>> target-i386 means the guest will run i386 instructions, but the host can
>> be something else (say, powerpc).
>>
>> Nothing else uses host instructions in that directory, so no protection
>> was necessary before.
>>
>
> I've got a remark about this: why this has to be added to the Qemu
> code ?
> Imho, all is needed is an implementation of the -cpu option for
> x86/x86_64 target. Then, an external tool (even a shell script) can be
> used to determine what is the host CPU if you want to select the exact
> same CPU to be emulated in Qemu. It seems to me that trying to do so is
> out of the scope of Qemu code and just add unneeded complexity.
>
Indeed for regular qemu this is useless. But it is useful for kqemu
(for which there is support in mainline qemu), and for kvm (which we
hope to merge one day).
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 9:31 ` Avi Kivity
@ 2007-09-25 10:40 ` Avi Kivity
2007-09-25 11:09 ` J. Mayer
2007-09-25 12:51 ` Paul Brook
1 sibling, 1 reply; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 10:40 UTC (permalink / raw)
To: J. Mayer; +Cc: kvm-devel, qemu-devel
Avi Kivity wrote:
>>>
>>>
>> I've got a remark about this: why this has to be added to the Qemu
>> code ?
>> Imho, all is needed is an implementation of the -cpu option for
>> x86/x86_64 target. Then, an external tool (even a shell script) can be
>> used to determine what is the host CPU if you want to select the exact
>> same CPU to be emulated in Qemu. It seems to me that trying to do so is
>> out of the scope of Qemu code and just add unneeded complexity.
>>
>>
>
> Indeed for regular qemu this is useless. But it is useful for kqemu
> (for which there is support in mainline qemu), and for kvm (which we
> hope to merge one day).
>
>
Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
it can't trap cpuid in all circumstances.
So this is mainly useful for kvm. I hope it will be applied regardless
of that, as there is agreement that kvm support should be merged. I'd
much rather pull the feature from qemu rather than carry it as an
additional patch.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 10:40 ` Avi Kivity
@ 2007-09-25 11:09 ` J. Mayer
2007-09-25 11:36 ` Avi Kivity
0 siblings, 1 reply; 43+ messages in thread
From: J. Mayer @ 2007-09-25 11:09 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, qemu-devel
On Tue, 2007-09-25 at 12:40 +0200, Avi Kivity wrote:
> Avi Kivity wrote:
> >>>
> >>>
> >> I've got a remark about this: why this has to be added to the Qemu
> >> code ?
> >> Imho, all is needed is an implementation of the -cpu option for
> >> x86/x86_64 target. Then, an external tool (even a shell script) can be
> >> used to determine what is the host CPU if you want to select the exact
> >> same CPU to be emulated in Qemu. It seems to me that trying to do so is
> >> out of the scope of Qemu code and just add unneeded complexity.
> >>
> >>
> >
> > Indeed for regular qemu this is useless. But it is useful for kqemu
> > (for which there is support in mainline qemu), and for kvm (which we
> > hope to merge one day).
> >
> >
>
> Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
> it can't trap cpuid in all circumstances.
>
> So this is mainly useful for kvm. I hope it will be applied regardless
> of that, as there is agreement that kvm support should be merged. I'd
> much rather pull the feature from qemu rather than carry it as an
> additional patch.
Still I don't understand why it's usefull to put it inside the emulator
and why:
# qemu -cpu `guess_host_cpu`
would not do the work properly. Adding a specific case for '-cpu host'
seems useless to me.
And this way of doing potentially work for any family of emulated
targets, without any modification in Qemu. If the string returned by
'guess_host_cpu' is not recognized for the specific target you used it
with, Qemu just stops telling it cannot find this CPU model, no more, no
less.
The only case it could be interresting, imho, is if you do not allow the
-cpu option in KVM case and force the cpu model instead using this
function. This behavior does not seem to be great idea to me.
Or maybe I missed something ?
--
J. Mayer <l_indien@magic.fr>
Never organized
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 11:09 ` J. Mayer
@ 2007-09-25 11:36 ` Avi Kivity
2007-09-25 12:05 ` Fabrice Bellard
2007-09-25 13:07 ` Jocelyn Mayer
0 siblings, 2 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 11:36 UTC (permalink / raw)
To: J. Mayer; +Cc: kvm-devel, qemu-devel
J. Mayer wrote:
> On Tue, 2007-09-25 at 12:40 +0200, Avi Kivity wrote:
>
>> Avi Kivity wrote:
>>
>>>>>
>>>>>
>>>>>
>>>> I've got a remark about this: why this has to be added to the Qemu
>>>> code ?
>>>> Imho, all is needed is an implementation of the -cpu option for
>>>> x86/x86_64 target. Then, an external tool (even a shell script) can be
>>>> used to determine what is the host CPU if you want to select the exact
>>>> same CPU to be emulated in Qemu. It seems to me that trying to do so is
>>>> out of the scope of Qemu code and just add unneeded complexity.
>>>>
>>>>
>>>>
>>> Indeed for regular qemu this is useless. But it is useful for kqemu
>>> (for which there is support in mainline qemu), and for kvm (which we
>>> hope to merge one day).
>>>
>>>
>>>
>> Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
>> it can't trap cpuid in all circumstances.
>>
>> So this is mainly useful for kvm. I hope it will be applied regardless
>> of that, as there is agreement that kvm support should be merged. I'd
>> much rather pull the feature from qemu rather than carry it as an
>> additional patch.
>>
>
> Still I don't understand why it's usefull to put it inside the emulator
> and why:
> # qemu -cpu `guess_host_cpu`
> would not do the work properly. Adding a specific case for '-cpu host'
> seems useless to me.
> And this way of doing potentially work for any family of emulated
> targets, without any modification in Qemu. If the string returned by
> 'guess_host_cpu' is not recognized for the specific target you used it
> with, Qemu just stops telling it cannot find this CPU model, no more, no
> less.
>
It's a usability issue. I agree your suggestion would work, but I'd
like the default for kvm to be using the host cpu features, whereas
managed environments would specify some subset to enable live migration.
> The only case it could be interresting, imho, is if you do not allow the
> -cpu option in KVM case and force the cpu model instead using this
> function. This behavior does not seem to be great idea to me.
>
I think we can move the host cpu checks to kvm-specific code, since it
is not useful for kqemu.
So, running qemu without any parameters would use host capabilities if
kvm is available and the default qemu cpu if not. The -cpu option can
be used to override this if necessary.
--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 11:36 ` Avi Kivity
@ 2007-09-25 12:05 ` Fabrice Bellard
2007-09-25 13:07 ` Jocelyn Mayer
1 sibling, 0 replies; 43+ messages in thread
From: Fabrice Bellard @ 2007-09-25 12:05 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel, J. Mayer
Avi Kivity wrote:
> J. Mayer wrote:
>
>>On Tue, 2007-09-25 at 12:40 +0200, Avi Kivity wrote:
>>
>>
>>>Avi Kivity wrote:
>>>
>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>I've got a remark about this: why this has to be added to the Qemu
>>>>>code ?
>>>>>Imho, all is needed is an implementation of the -cpu option for
>>>>>x86/x86_64 target. Then, an external tool (even a shell script) can be
>>>>>used to determine what is the host CPU if you want to select the exact
>>>>>same CPU to be emulated in Qemu. It seems to me that trying to do so is
>>>>>out of the scope of Qemu code and just add unneeded complexity.
>>>>>
>>>>>
>>>>>
>>>>
>>>>Indeed for regular qemu this is useless. But it is useful for kqemu
>>>>(for which there is support in mainline qemu), and for kvm (which we
>>>>hope to merge one day).
>>>>
>>>>
>>>>
>>>
>>>Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
>>>it can't trap cpuid in all circumstances.
>>>
>>>So this is mainly useful for kvm. I hope it will be applied regardless
>>>of that, as there is agreement that kvm support should be merged. I'd
>>>much rather pull the feature from qemu rather than carry it as an
>>>additional patch.
>>>
>>
>>Still I don't understand why it's usefull to put it inside the emulator
>>and why:
>># qemu -cpu `guess_host_cpu`
>>would not do the work properly. Adding a specific case for '-cpu host'
>>seems useless to me.
>>And this way of doing potentially work for any family of emulated
>>targets, without any modification in Qemu. If the string returned by
>>'guess_host_cpu' is not recognized for the specific target you used it
>>with, Qemu just stops telling it cannot find this CPU model, no more, no
>>less.
>>
>
>
> It's a usability issue. I agree your suggestion would work, but I'd
> like the default for kvm to be using the host cpu features, whereas
> managed environments would specify some subset to enable live migration.
>
>
>>The only case it could be interresting, imho, is if you do not allow the
>>-cpu option in KVM case and force the cpu model instead using this
>>function. This behavior does not seem to be great idea to me.
>>
>
>
> I think we can move the host cpu checks to kvm-specific code, since it
> is not useful for kqemu.
>
> So, running qemu without any parameters would use host capabilities if
> kvm is available and the default qemu cpu if not. The -cpu option can
> be used to override this if necessary.
Rectification: this is useful for kqemu too. I strongly suggest to look
at kqemu.c:kqemu_update_cpuid() !
Moreover I believe that using the same CPU as host can be useful for
pure emulation too, for example if code to do cache profiling is added.
Regards,
Fabrice.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 9:31 ` Avi Kivity
2007-09-25 10:40 ` Avi Kivity
@ 2007-09-25 12:51 ` Paul Brook
2007-09-25 13:13 ` Avi Kivity
1 sibling, 1 reply; 43+ messages in thread
From: Paul Brook @ 2007-09-25 12:51 UTC (permalink / raw)
To: qemu-devel; +Cc: kvm-devel, J. Mayer
On Tuesday 25 September 2007, Avi Kivity wrote:
> J. Mayer wrote:
> > On Tue, 2007-09-25 at 11:01 +0200, Avi Kivity wrote:
> >> Dan Kenigsberg wrote:
> >>> On Tue, Sep 25, 2007 at 03:28:24AM +0200, andrzej zaborowski wrote:
> >>>> Hi,
> >>>>
> >>>> On 24/09/2007, Dan Kenigsberg <danken@qumranet.com> wrote:
> >>>>> As with previous "Takes" of this patch, its purpose is to expose host
> >>>>> +{
> >>>>> + asm("cpuid"
> >>>>> + : "=a" (*ax),
> >>>>> + "=b" (*bx),
> >>>>> + "=c" (*cx),
> >>>>> + "=d" (*dx)
> >>>>> + : "a" (function));
> >>>>> +}
> >>>>
> Indeed for regular qemu this is useless. But it is useful for kqemu
> (for which there is support in mainline qemu), and for kvm (which we
> hope to merge one day).
And, as discussed before, it should be asking the hypervisor what features it
supports instead of trying to guess from the cpuid output.
Paul
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 11:36 ` Avi Kivity
2007-09-25 12:05 ` Fabrice Bellard
@ 2007-09-25 13:07 ` Jocelyn Mayer
2007-09-25 13:12 ` Avi Kivity
` (2 more replies)
1 sibling, 3 replies; 43+ messages in thread
From: Jocelyn Mayer @ 2007-09-25 13:07 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, qemu-devel
On Tue, 2007-09-25 at 13:36 +0200, Avi Kivity wrote:
> J. Mayer wrote:
> > On Tue, 2007-09-25 at 12:40 +0200, Avi Kivity wrote:
> >
> >> Avi Kivity wrote:
> >>
> >>>>>
> >>>>>
> >>>>>
> >>>> I've got a remark about this: why this has to be added to the Qemu
> >>>> code ?
> >>>> Imho, all is needed is an implementation of the -cpu option for
> >>>> x86/x86_64 target. Then, an external tool (even a shell script) can be
> >>>> used to determine what is the host CPU if you want to select the exact
> >>>> same CPU to be emulated in Qemu. It seems to me that trying to do so is
> >>>> out of the scope of Qemu code and just add unneeded complexity.
> >>>>
> >>>>
> >>>>
> >>> Indeed for regular qemu this is useless. But it is useful for kqemu
> >>> (for which there is support in mainline qemu), and for kvm (which we
> >>> hope to merge one day).
> >>>
> >>>
> >>>
> >> Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
> >> it can't trap cpuid in all circumstances.
> >>
> >> So this is mainly useful for kvm. I hope it will be applied regardless
> >> of that, as there is agreement that kvm support should be merged. I'd
> >> much rather pull the feature from qemu rather than carry it as an
> >> additional patch.
> >>
> >
> > Still I don't understand why it's usefull to put it inside the emulator
> > and why:
> > # qemu -cpu `guess_host_cpu`
> > would not do the work properly. Adding a specific case for '-cpu host'
> > seems useless to me.
> > And this way of doing potentially work for any family of emulated
> > targets, without any modification in Qemu. If the string returned by
> > 'guess_host_cpu' is not recognized for the specific target you used it
> > with, Qemu just stops telling it cannot find this CPU model, no more, no
> > less.
> >
>
> It's a usability issue. I agree your suggestion would work, but I'd
> like the default for kvm to be using the host cpu features, whereas
> managed environments would specify some subset to enable live migration.
>
> > The only case it could be interresting, imho, is if you do not allow the
> > -cpu option in KVM case and force the cpu model instead using this
> > function. This behavior does not seem to be great idea to me.
> >
>
> I think we can move the host cpu checks to kvm-specific code, since it
> is not useful for kqemu.
>
> So, running qemu without any parameters would use host capabilities if
> kvm is available and the default qemu cpu if not. The -cpu option can
> be used to override this if necessary.
Well, it may be needed to integrate the "-cpu host" option.
But I think it's a really bad idea that running qemu without the -cpu
option would not act the same on different host. When I want to test
qemu with the same command line, I want it to behave exactly the same,
whatever the host I'm running on, like any other tool. Think about gcc,
for example, if you launch it without option, it compiles for a generic
CPU. If you want to tune the generated code, even for the host you're
running on, you have to use -mcpu/-march/-mtune. Using one command line
always have gives the same result.
Then, my opinion is that running qemu without any -cpu option should
always use a default target.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 13:07 ` Jocelyn Mayer
@ 2007-09-25 13:12 ` Avi Kivity
2007-09-25 13:27 ` Dan Kenigsberg
2007-09-25 15:54 ` Jamie Lokier
2 siblings, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 13:12 UTC (permalink / raw)
To: l_indien; +Cc: kvm-devel, qemu-devel
Jocelyn Mayer wrote:
> On Tue, 2007-09-25 at 13:36 +0200, Avi Kivity wrote:
>
>> J. Mayer wrote:
>>
>>> On Tue, 2007-09-25 at 12:40 +0200, Avi Kivity wrote:
>>>
>>>
>>>> Avi Kivity wrote:
>>>>
>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> I've got a remark about this: why this has to be added to the Qemu
>>>>>> code ?
>>>>>> Imho, all is needed is an implementation of the -cpu option for
>>>>>> x86/x86_64 target. Then, an external tool (even a shell script) can be
>>>>>> used to determine what is the host CPU if you want to select the exact
>>>>>> same CPU to be emulated in Qemu. It seems to me that trying to do so is
>>>>>> out of the scope of Qemu code and just add unneeded complexity.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Indeed for regular qemu this is useless. But it is useful for kqemu
>>>>> (for which there is support in mainline qemu), and for kvm (which we
>>>>> hope to merge one day).
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Actually (as Izik Eidus reminds me), this isn't very useful for kqemu as
>>>> it can't trap cpuid in all circumstances.
>>>>
>>>> So this is mainly useful for kvm. I hope it will be applied regardless
>>>> of that, as there is agreement that kvm support should be merged. I'd
>>>> much rather pull the feature from qemu rather than carry it as an
>>>> additional patch.
>>>>
>>>>
>>> Still I don't understand why it's usefull to put it inside the emulator
>>> and why:
>>> # qemu -cpu `guess_host_cpu`
>>> would not do the work properly. Adding a specific case for '-cpu host'
>>> seems useless to me.
>>> And this way of doing potentially work for any family of emulated
>>> targets, without any modification in Qemu. If the string returned by
>>> 'guess_host_cpu' is not recognized for the specific target you used it
>>> with, Qemu just stops telling it cannot find this CPU model, no more, no
>>> less.
>>>
>>>
>> It's a usability issue. I agree your suggestion would work, but I'd
>> like the default for kvm to be using the host cpu features, whereas
>> managed environments would specify some subset to enable live migration.
>>
>>
>>> The only case it could be interresting, imho, is if you do not allow the
>>> -cpu option in KVM case and force the cpu model instead using this
>>> function. This behavior does not seem to be great idea to me.
>>>
>>>
>> I think we can move the host cpu checks to kvm-specific code, since it
>> is not useful for kqemu.
>>
>> So, running qemu without any parameters would use host capabilities if
>> kvm is available and the default qemu cpu if not. The -cpu option can
>> be used to override this if necessary.
>>
>
> Well, it may be needed to integrate the "-cpu host" option.
> But I think it's a really bad idea that running qemu without the -cpu
> option would not act the same on different host. When I want to test
> qemu with the same command line, I want it to behave exactly the same,
> whatever the host I'm running on, like any other tool. Think about gcc,
> for example, if you launch it without option, it compiles for a generic
> CPU. If you want to tune the generated code, even for the host you're
> running on, you have to use -mcpu/-march/-mtune. Using one command line
> always have gives the same result.
> Then, my opinion is that running qemu without any -cpu option should
> always use a default target.
>
That's a valid usage model. For many kvm users, however, the primary
reason to run qemu is to get the performance that kvm provides, so
they'd like to see host cpuid as the default. Maybe a .qemurc can help
here.
--
Any sufficiently difficult bug is indistinguishable from a feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 12:51 ` Paul Brook
@ 2007-09-25 13:13 ` Avi Kivity
0 siblings, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 13:13 UTC (permalink / raw)
To: Paul Brook; +Cc: kvm-devel, J. Mayer, qemu-devel
Paul Brook wrote:
>> Indeed for regular qemu this is useless. But it is useful for kqemu
>> (for which there is support in mainline qemu), and for kvm (which we
>> hope to merge one day).
>>
>
> And, as discussed before, it should be asking the hypervisor what features it
> supports instead of trying to guess from the cpuid output.
>
Agreed.
--
Any sufficiently difficult bug is indistinguishable from a feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 13:07 ` Jocelyn Mayer
2007-09-25 13:12 ` Avi Kivity
@ 2007-09-25 13:27 ` Dan Kenigsberg
2007-09-25 15:54 ` Jamie Lokier
2 siblings, 0 replies; 43+ messages in thread
From: Dan Kenigsberg @ 2007-09-25 13:27 UTC (permalink / raw)
To: Jocelyn Mayer; +Cc: kvm-devel, qemu-devel
On Tue, Sep 25, 2007 at 03:07:44PM +0200, Jocelyn Mayer wrote:
> > So, running qemu without any parameters would use host capabilities if
> > kvm is available and the default qemu cpu if not. The -cpu option can
> > be used to override this if necessary.
>
> Well, it may be needed to integrate the "-cpu host" option.
> But I think it's a really bad idea that running qemu without the -cpu
> option would not act the same on different host. When I want to test
> qemu with the same command line, I want it to behave exactly the same,
> whatever the host I'm running on, like any other tool. Think about gcc,
> for example, if you launch it without option, it compiles for a generic
> CPU. If you want to tune the generated code, even for the host you're
> running on, you have to use -mcpu/-march/-mtune. Using one command line
> always have gives the same result.
> Then, my opinion is that running qemu without any -cpu option should
> always use a default target.
Note that in "take 3" the default is indeed to expose the "basic"
default cpu features if no -cpu is specified. One must add -cpu host in
order to read and expose the host cpuid.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 13:07 ` Jocelyn Mayer
2007-09-25 13:12 ` Avi Kivity
2007-09-25 13:27 ` Dan Kenigsberg
@ 2007-09-25 15:54 ` Jamie Lokier
2007-09-25 16:15 ` Avi Kivity
2 siblings, 1 reply; 43+ messages in thread
From: Jamie Lokier @ 2007-09-25 15:54 UTC (permalink / raw)
To: l_indien, qemu-devel
Jocelyn Mayer wrote:
> Well, it may be needed to integrate the "-cpu host" option.
> But I think it's a really bad idea that running qemu without the -cpu
> option would not act the same on different host. When I want to test
> qemu with the same command line, I want it to behave exactly the same,
> whatever the host I'm running on, like any other tool. Think about gcc,
> for example, if you launch it without option, it compiles for a generic
> CPU. If you want to tune the generated code, even for the host you're
> running on, you have to use -mcpu/-march/-mtune. Using one command line
> always have gives the same result.
> Then, my opinion is that running qemu without any -cpu option should
> always use a default target.
A major feature of qemu is reproducible behaviour. This is especially
important when resuming snapshots or booting pre-installed images for
testing things.
A major feature of kvm/kqemu is performance. But not always
performance at the expense of reproducibility. Sometimes you want to
use kvm/kqemu to make qemu as fast as possible while still behaving
the same with some image.
Where someone wants performance to have precedence, it's easy enough
to advise "use -cpu host" for that.
Where someone wants performance, but reproducibility to have
precedence, it would be more awkward to have to advise "use -cpu
list,of,common,features".
I think reproducibility is something which needs to be working by
default. This is because people make images before they decide to
move them to other hosts, and often before they would consider at all
issues about host differences, and making images is sometimes a lot of
work. Images should be portable among hosts by default.
But, if we say that the default is a baseline CPU, and there's a "-cpu
host" option to maximise performance, then we have to decide what
features the baseline CPU has. Obviously a 386 isn't very useful for
emulation any more - many OSes won't run on it.
Then, if we change our mind about the default baseline CPU, then we've
lost reproducibility for old images anyway.
That's an argument for storing the emulated CPU features in images.
If that's done, then for image portability among hosts, it is not so
important that the default CPU have only the features which
are native to every host. Instead, the critical thing is simply that
it has only features which are either native or can be emulated on
every host. E.g. TSC is in this category.
-- Jamie
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [kvm-devel] [Qemu-devel] expose host CPU features to guests: Take 3
2007-09-25 15:54 ` Jamie Lokier
@ 2007-09-25 16:15 ` Avi Kivity
0 siblings, 0 replies; 43+ messages in thread
From: Avi Kivity @ 2007-09-25 16:15 UTC (permalink / raw)
To: qemu-devel; +Cc: l_indien
Jamie Lokier wrote:
> Jocelyn Mayer wrote:
>
>> Well, it may be needed to integrate the "-cpu host" option.
>> But I think it's a really bad idea that running qemu without the -cpu
>> option would not act the same on different host. When I want to test
>> qemu with the same command line, I want it to behave exactly the same,
>> whatever the host I'm running on, like any other tool. Think about gcc,
>> for example, if you launch it without option, it compiles for a generic
>> CPU. If you want to tune the generated code, even for the host you're
>> running on, you have to use -mcpu/-march/-mtune. Using one command line
>> always have gives the same result.
>> Then, my opinion is that running qemu without any -cpu option should
>> always use a default target.
>>
>
> A major feature of qemu is reproducible behaviour. This is especially
> important when resuming snapshots or booting pre-installed images for
> testing things.
>
> A major feature of kvm/kqemu is performance. But not always
> performance at the expense of reproducibility. Sometimes you want to
> use kvm/kqemu to make qemu as fast as possible while still behaving
> the same with some image.
>
> Where someone wants performance to have precedence, it's easy enough
> to advise "use -cpu host" for that.
>
> Where someone wants performance, but reproducibility to have
> precedence, it would be more awkward to have to advise "use -cpu
> list,of,common,features".
>
Or maybe "-cpu baseline" or some other neutral word.
> I think reproducibility is something which needs to be working by
> default. This is because people make images before they decide to
> move them to other hosts, and often before they would consider at all
> issues about host differences, and making images is sometimes a lot of
> work. Images should be portable among hosts by default.
>
> But, if we say that the default is a baseline CPU, and there's a "-cpu
> host" option to maximise performance, then we have to decide what
> features the baseline CPU has. Obviously a 386 isn't very useful for
> emulation any more - many OSes won't run on it.
>
>
The baseline cpu should be whatever qemu supports today.
> Then, if we change our mind about the default baseline CPU, then we've
> lost reproducibility for old images anyway.
>
> That's an argument for storing the emulated CPU features in images.
>
That's another thread -- I want memory size and network configuration in
there too :)
> If that's done, then for image portability among hosts, it is not so
> important that the default CPU have only the features which
> are native to every host. Instead, the critical thing is simply that
> it has only features which are either native or can be emulated on
> every host. E.g. TSC is in this category.
>
Qemu is used to support three different user classes which have
different requirements. Developers want reproducibility and control, so
-cpu baseline should be the default for them. Home users want speed to
run Windows or test distros, so -cpu host and kvm should be the default
for them. Managed deployments want something in between, so they'd
specify -cpu feature,feature and won't care about the default.
We can make it a ./configure option. I suspect distros will want to set
-cpu host as default as their users primarily care about speed.
--
Any sufficiently difficult bug is indistinguishable from a feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* [Qemu-devel] x86 -cpu option: Take 4
2007-09-24 17:41 ` [Qemu-devel] expose host CPU features to guests: Take 3 Dan Kenigsberg
2007-09-25 1:28 ` andrzej zaborowski
@ 2007-10-07 12:38 ` Dan Kenigsberg
1 sibling, 0 replies; 43+ messages in thread
From: Dan Kenigsberg @ 2007-10-07 12:38 UTC (permalink / raw)
To: qemu-devel, kvm-devel
Hi,
Due to comments on "Take 3", I rewrote the feature name list according
to Intel's and AMD's specs in order not to contaminate target-i386 with
GPL code. More importantly - the "host" cpu type is dropped. It will be
added, as a kvm-specific code, in a future patch.
I'd be happy to hear if patch is applicable in its current minimalistic
form this, or that more changes should be made.
Thanks,
Dan.
Index: vl.c
===================================================================
RCS file: /sources/qemu/qemu/vl.c,v
retrieving revision 1.346
diff -u -p -r1.346 vl.c
--- vl.c 5 Oct 2007 13:08:34 -0000 1.346
+++ vl.c 7 Oct 2007 12:34:45 -0000
@@ -7696,6 +7696,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.86
diff -u -p -r1.86 pc.c
--- hw/pc.c 5 Oct 2007 13:08:35 -0000 1.86
+++ hw/pc.c 7 Oct 2007 12:34:46 -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)
@@ -950,7 +957,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,
@@ -964,7 +971,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.50
diff -u -p -r1.50 cpu.h
--- target-i386/cpu.h 27 Sep 2007 16:44:31 -0000 1.50
+++ target-i386/cpu.h 7 Oct 2007 12:34:46 -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 7 Oct 2007 12:34:46 -0000
@@ -46,6 +46,64 @@ 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);
+
+static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, uint32_t *ext_features, uint32_t *ext2_features, uint32_t *ext3_features)
+{
+ int i;
+ /* feature flags taken from "Intel Processor Identification and the CPUID
+ * Instruction" and AMD's "CPUID Specification". In cases of disagreement
+ * about feature names, the Linux name is used. */
+ const char *feature_name[] = {
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
+ };
+ const char *ext_feature_name[] = {
+ "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux 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,
+ };
+ const char *ext2_feature_name[] = {
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov",
+ "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
+ "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
+ };
+ const char *ext3_feature_name[] = {
+ "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ };
+
+ for ( i = 0 ; i < 32 ; i++ )
+ if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
+ *features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
+ *ext_features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
+ *ext2_features |= 1 << i;
+ return;
+ }
+ for ( i = 0 ; i < 32 ; i++ )
+ if (ext3_features[i] && !strcmp (flagname, ext3_feature_name[i])) {
+ *ext3_features |= 1 << i;
+ return;
+ }
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
+}
+
CPUX86State *cpu_x86_init(void)
{
CPUX86State *env;
@@ -80,71 +138,220 @@ 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;
+};
+
+#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,
+ .ext3_features = CPUID_EXT3_SVM,
+ .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,
+ },
+};
+
+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;
+
+ 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 %16s\n", x86_defs[i].name);
+}
+
+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));
- }
+ }
+ 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;
+ 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;
-
- /* 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
}
- 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 +391,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;
^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2007-10-07 12:41 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-05 17:45 [Qemu-devel] expose host CPU features to guests danken
2007-09-05 19:26 ` [Qemu-devel] Re: [kvm-devel] " Anthony Liguori
2007-09-05 19:34 ` Avi Kivity
2007-09-05 19:44 ` Daniel P. Berrange
2007-09-06 0:30 ` Paul Brook
2007-09-06 8:46 ` Avi Kivity
2007-09-07 10:47 ` Jamie Lokier
2007-09-09 7:51 ` [kvm-devel] [Qemu-devel] " Avi Kivity
2007-09-09 12:47 ` Jamie Lokier
2007-09-09 12:55 ` Avi Kivity
2007-09-09 13:07 ` Jamie Lokier
2007-09-09 13:14 ` Avi Kivity
2007-09-09 15:25 ` Paul Brook
2007-09-09 15:29 ` Avi Kivity
2007-09-09 15:47 ` Jamie Lokier
2007-09-09 16:12 ` Paul Brook
2007-09-09 16:38 ` Avi Kivity
2007-09-10 16:53 ` Jamie Lokier
2007-09-10 7:40 ` [Qemu-devel] expose host CPU features to guests: Take 2 Dan Kenigsberg
2007-09-10 11:47 ` Natalia Portillo
2007-09-10 12:01 ` Dan Kenigsberg
2007-09-07 16:18 ` Natalia Portillo
2007-09-11 19:48 ` Luke -Jr
2007-09-10 17:16 ` Jamie Lokier
2007-09-24 17:41 ` [Qemu-devel] expose host CPU features to guests: Take 3 Dan Kenigsberg
2007-09-25 1:28 ` andrzej zaborowski
2007-09-25 8:48 ` [kvm-devel] " Dan Kenigsberg
2007-09-25 9:01 ` Avi Kivity
2007-09-25 9:19 ` J. Mayer
2007-09-25 9:31 ` Avi Kivity
2007-09-25 10:40 ` Avi Kivity
2007-09-25 11:09 ` J. Mayer
2007-09-25 11:36 ` Avi Kivity
2007-09-25 12:05 ` Fabrice Bellard
2007-09-25 13:07 ` Jocelyn Mayer
2007-09-25 13:12 ` Avi Kivity
2007-09-25 13:27 ` Dan Kenigsberg
2007-09-25 15:54 ` Jamie Lokier
2007-09-25 16:15 ` Avi Kivity
2007-09-25 12:51 ` Paul Brook
2007-09-25 13:13 ` Avi Kivity
2007-09-25 9:29 ` Fabrice Bellard
2007-10-07 12:38 ` [Qemu-devel] x86 -cpu option: Take 4 Dan Kenigsberg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).