From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1IUhkg-0007Lw-RM for qemu-devel@nongnu.org; Mon, 10 Sep 2007 07:48:26 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1IUhkd-0007KN-QQ for qemu-devel@nongnu.org; Mon, 10 Sep 2007 07:48:26 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IUhkd-0007K9-Kx for qemu-devel@nongnu.org; Mon, 10 Sep 2007 07:48:23 -0400 Received: from 149.red-80-37-155.staticip.rima-tde.net ([80.37.155.149] helo=claunia.com) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1IUhkc-0000hf-3B for qemu-devel@nongnu.org; Mon, 10 Sep 2007 07:48:23 -0400 Received: from localhost (localhost [127.0.0.1]) by claunia.com (Postfix) with ESMTP id BAA171E02655 for ; Mon, 10 Sep 2007 12:48:15 +0100 (BST) Received: from claunia.com ([127.0.0.1]) by localhost (hecate.claunia.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 23013-06 for ; Mon, 10 Sep 2007 12:47:57 +0100 (BST) Received: from hermes (80.224.24.149.static.user.ono.com [80.224.24.149]) by claunia.com (Postfix) with ESMTP id 42CA21E0262B for ; Mon, 10 Sep 2007 12:47:56 +0100 (BST) Date: Mon, 10 Sep 2007 12:47:51 +0100 Subject: Re: [Qemu-devel] expose host CPU features to guests: Take 2 From: "Natalia Portillo" Content-Type: text/plain; format=flowed; delsp=yes; charset=iso-8859-15 MIME-Version: 1.0 References: <20070905174530.GA3945@karma.qumranet.com> <20070910074005.GA26869@karma.qumranet.com> Content-Transfer-Encoding: Quoted-Printable Message-ID: In-Reply-To: <20070910074005.GA26869@karma.qumranet.com> Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 = = wrote: > As with Take 1 of this patch, its purpose is to expose host CPU featur= es = > 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 shoul= d > negotiate the actually-supported features with the virutalizing kern= el > module. > > Index: hw/pc.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > 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 =3D 0; i < smp_cpus; i++) { > + void apply_i386_cpu_model(CPUX86State *env, char *cpu_model);= > env =3D cpu_init(); > + apply_i386_cpu_model(env, cpu_model); > if (i !=3D 0) > env->hflags |=3D 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_devic= e, > @@ -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 =3D { > Index: target-i386/cpu.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > 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 > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > 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 =3D qemu_mallocz(sizeof(CPUX86State)); > - if (!env) > - return NULL; > - cpu_exec_init(env); > - > - /* init various static tables */ > - if (!inited) { > - inited =3D 1; > - optimize_flags_init(); > - } > -#ifdef USE_CODE_COPY > - /* testing code for code copy case */ > - { > - struct modify_ldt_ldt_s ldt; > - > - ldt.entry_number =3D 1; > - ldt.base_addr =3D (unsigned long)env; > - ldt.limit =3D (sizeof(CPUState) + 0xfff) >> 12; > - ldt.seg_32bit =3D 1; > - ldt.contents =3D MODIFY_LDT_CONTENTS_DATA; > - ldt.read_exec_only =3D 0; > - ldt.limit_in_pages =3D 1; > - ldt.seg_not_present =3D 0; > - ldt.useable =3D 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 =3D CPUID_EXT_SSE3; > env->cpuid_features |=3D CPUID_FXSR | CPUID_MMX | CPUID_SSE |= = > CPUID_SSE2 | CPUID_PAE | CPUID_SEP; > env->cpuid_features |=3D CPUID_APIC; > - env->cpuid_xlevel =3D 0; > - { > - const char *model_id =3D "QEMU Virtual CPU version " = > QEMU_VERSION; > - int c, len, i; > - len =3D strlen(model_id); > - for(i =3D 0; i < 48; i++) { > - if (i >=3D len) > - c =3D '\0'; > - else > - c =3D model_id[i]; > - env->cpuid_model[i >> 2] |=3D c << (8 * (i & 3)); > - } > - } > + env->cpuid_xlevel =3D 0x80000006; > #ifdef TARGET_X86_64 > /* currently not enabled for std i386 because not fully teste= d = > */ > env->cpuid_ext2_features =3D (env->cpuid_features & 0x0183F3F= F); > @@ -139,6 +95,239 @@ > env->cpuid_features |=3D CPUID_PSE36; > #endif > } > +} > + > +static int host_cpuid (uint32_t function, uint32_t *ax,uint32_t *bx, = = > uint32_t *cx, uint32_t *dx) > +{ > + asm("cpuid" > + : "=3Da" (*ax), > + "=3Db" (*bx), > + "=3Dc" (*cx), > + "=3Dd" (*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 =3D 2; /* host real level is ax */ > + env->cpuid_vendor1 =3D bx; > + env->cpuid_vendor2 =3D dx; > + env->cpuid_vendor3 =3D cx; > + > + host_cpuid(1, &ax, &bx, &cx, &dx); > + env->cpuid_version =3D ax; > + env->cpuid_features =3D dx & ~CPUID_ACPI; /* acpi panics linux gu= ests = > */ > + env->cpuid_ext_features =3D cx & ~CPUID_EXT_VMX; /* vmx is not = > recursive */ > + > + /* cpuid(0x80000000, &ax, &bx, &cx, &dx); */ > + env->cpuid_xlevel =3D 0x80000008; > + > + host_cpuid(0x80000001, &ax, &bx, &cx, &dx); > + env->cpuid_ext2_features =3D dx; > + > + return 0; > +} > + > +/* x86_cap_flags taken from Linux's arch/i386/kernel/cpu/proc.c */ > +static const char * const x86_cap_flags[] =3D { > + /* 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", "3dno= w", > + > + /* 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 =3D 0 ; i < 32 ; i++ ) > + if (x86_cap_flags[i] && !strcmp (flagname, x86_cap_flags[i]))= { > + *features |=3D 1 << i; > + return; > + } > + for ( i =3D 0 ; i < 32 ; i++ ) > + if (x86_cap_flags[32*4+i] && !strcmp (flagname, = > x86_cap_flags[32*4+i])) { > + *ext_features |=3D 1 << i; > + return; > + } > + for ( i =3D 0 ; i < 32 ; i++ ) > + if (x86_cap_flags[32*1+i] && !strcmp (flagname, = > x86_cap_flags[32*1+i])) { > + *ext2_features |=3D 1 << i; > + return; > + } > + /* Silently ignore Linux-defined features */ > + for ( i =3D 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 =3D 0, plus_ext_features =3D 0, plus_ext2_featu= res =3D = > 0; > + int minus_features =3D 0, minus_ext_features =3D 0, minus_ext2_fe= atures = > =3D 0; > + int family =3D -1, model =3D -1, stepping =3D -1; > + > + char *s, *featurestr; > + > + if (!cpu_model) > + cpu_model =3D "host"; > + > + s =3D 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=3Dxyz)]...\n= "); > + exit(1); > + } > + > + featurestr =3D strtok(NULL, ","); > + while (featurestr) { > + char *val; > + if (featurestr[0] =3D=3D '+') { > + add_flagname_to_bitmaps(featurestr + 1, &plus_features, = > &plus_ext_features, &plus_ext2_features); > + } > + else if (featurestr[0] =3D=3D '-') { > + add_flagname_to_bitmaps(featurestr + 1, &minus_features, = > &minus_ext_features, &minus_ext2_features); > + } > + else if ((val =3D strchr(featurestr, '=3D'))) { > + *val =3D 0; val++; > + if (!strcmp(featurestr, "family")) { > + family =3D atoi(val); > + if (family <=3D 0) { > + fprintf(stderr, "bad numerical value %s\n", val); > + exit(1); > + } > + env->cpuid_version &=3D 0xFF; > + env->cpuid_version |=3D (family << 8); > + } else if (!strcmp(featurestr, "model")) { > + model =3D atoi(val); > + if (model <=3D 0) { > + fprintf(stderr, "bad numerical value %s\n", val); > + exit(1); > + } > + env->cpuid_version &=3D 0xFFFFFF0F; > + env->cpuid_version |=3D (model << 4); > + } else if (!strcmp(featurestr, "stepping")) { > + stepping =3D atoi(val); > + if (stepping <=3D 0) { > + fprintf(stderr, "bad numerical value %s\n", val); > + exit(1); > + } > + env->cpuid_version &=3D 0xFFFFFFF0; > + env->cpuid_version |=3D stepping; > + } else { > + fprintf(stderr, "unknown feature %s\n", featurestr); > + exit(1); > + } > + } else { > + fprintf(stderr, "feature string `%s' not in format = > (+feature|-feature|feature=3Dxyz)\n", featurestr); > + exit(1); > + } > + featurestr =3D strtok(NULL, ","); > + } > + free(s); > + env->cpuid_features |=3D plus_features; > + env->cpuid_ext_features |=3D plus_ext_features; > + env->cpuid_ext2_features |=3D plus_ext2_features; > + env->cpuid_features &=3D ~minus_features; > + env->cpuid_ext_features &=3D ~minus_ext_features; > + env->cpuid_ext2_features &=3D ~minus_ext2_features; > + > + { > + const char *model_id =3D "QEMU Virtual CPU version " QEMU_VER= SION; > + int c, len, i; > + len =3D strlen(model_id); > + for(i =3D 0; i < 48; i++) { > + if (i >=3D len) > + c =3D '\0'; > + else > + c =3D model_id[i]; > + env->cpuid_model[i >> 2] |=3D c << (8 * (i & 3)); > + } > + } > +} > + > +CPUX86State *cpu_x86_init(void) > +{ > + CPUX86State *env; > + static int inited; > + > + env =3D qemu_mallocz(sizeof(CPUX86State)); > + if (!env) > + return NULL; > + cpu_exec_init(env); > + > + /* init various static tables */ > + if (!inited) { > + inited =3D 1; > + optimize_flags_init(); > + } > +#ifdef USE_CODE_COPY > + /* testing code for code copy case */ > + { > + struct modify_ldt_ldt_s ldt; > + > + ldt.entry_number =3D 1; > + ldt.base_addr =3D (unsigned long)env; > + ldt.limit =3D (sizeof(CPUState) + 0xfff) >> 12; > + ldt.seg_32bit =3D 1; > + ldt.contents =3D MODIFY_LDT_CONTENTS_DATA; > + ldt.read_exec_only =3D 0; > + ldt.limit_in_pages =3D 1; > + ldt.seg_not_present =3D 0; > + ldt.useable =3D 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/