Re: [Qemu-devel] expose host CPU features to guests: Take 3

andrzej zaborowski
2007-09-25T01:28:24Z

Hi,

On 24/09/2007, Dan Kenigsberg <danken-atKUWr5tajBWk0Htik3J/w@public.gmane.org> 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