diff options
-rw-r--r-- | target-i386/cpu.h | 4 | ||||
-rw-r--r-- | target-i386/helper.c | 166 | ||||
-rw-r--r-- | target-i386/op_helper.c | 168 |
3 files changed, 176 insertions, 162 deletions
diff --git a/target-i386/cpu.h b/target-i386/cpu.h index b1678efd8c..263a477765 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -730,6 +730,10 @@ void cpu_smm_update(CPUX86State *env); /* will be suppressed */ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); +void cpu_x86_cpuid(CPUX86State *env, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx); + /* used to debug */ #define X86_DUMP_FPU 0x0001 /* dump FPU state too */ #define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ diff --git a/target-i386/helper.c b/target-i386/helper.c index 7569c7e20a..bcf5e7f705 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1287,3 +1287,169 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) return paddr; } #endif /* !CONFIG_USER_ONLY */ + +void cpu_x86_cpuid(CPUX86State *env, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + /* test if maximum index reached */ + if (index & 0x80000000) { + if (index > env->cpuid_xlevel) + index = env->cpuid_level; + } else { + if (index > env->cpuid_level) + index = env->cpuid_level; + } + + switch(index) { + case 0: + *eax = env->cpuid_level; + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; + break; + case 1: + *eax = env->cpuid_version; + *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ + *ecx = env->cpuid_ext_features; + *edx = env->cpuid_features; + break; + case 2: + /* cache info: needed for Pentium Pro compatibility */ + *eax = 1; + *ebx = 0; + *ecx = 0; + *edx = 0x2c307d; + break; + case 4: + /* cache info: needed for Core compatibility */ + switch (*ecx) { + case 0: /* L1 dcache info */ + *eax = 0x0000121; + *ebx = 0x1c0003f; + *ecx = 0x000003f; + *edx = 0x0000001; + break; + case 1: /* L1 icache info */ + *eax = 0x0000122; + *ebx = 0x1c0003f; + *ecx = 0x000003f; + *edx = 0x0000001; + break; + case 2: /* L2 cache info */ + *eax = 0x0000143; + *ebx = 0x3c0003f; + *ecx = 0x0000fff; + *edx = 0x0000001; + break; + default: /* end of info */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + } + + break; + case 5: + /* mwait info: needed for Core compatibility */ + *eax = 0; /* Smallest monitor-line size in bytes */ + *ebx = 0; /* Largest monitor-line size in bytes */ + *ecx = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; + *edx = 0; + break; + case 6: + /* Thermal and Power Leaf */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 9: + /* Direct Cache Access Information Leaf */ + *eax = 0; /* Bits 0-31 in DCA_CAP MSR */ + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 0xA: + /* Architectural Performance Monitoring Leaf */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 0x80000000: + *eax = env->cpuid_xlevel; + *ebx = env->cpuid_vendor1; + *edx = env->cpuid_vendor2; + *ecx = env->cpuid_vendor3; + break; + case 0x80000001: + *eax = env->cpuid_features; + *ebx = 0; + *ecx = env->cpuid_ext3_features; + *edx = env->cpuid_ext2_features; + break; + case 0x80000002: + case 0x80000003: + case 0x80000004: + *eax = env->cpuid_model[(index - 0x80000002) * 4 + 0]; + *ebx = env->cpuid_model[(index - 0x80000002) * 4 + 1]; + *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2]; + *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3]; + break; + case 0x80000005: + /* cache info (L1 cache) */ + *eax = 0x01ff01ff; + *ebx = 0x01ff01ff; + *ecx = 0x40020140; + *edx = 0x40020140; + break; + case 0x80000006: + /* cache info (L2 cache) */ + *eax = 0; + *ebx = 0x42004200; + *ecx = 0x02008140; + *edx = 0; + break; + case 0x80000008: + /* virtual & phys address size in low 2 bytes. */ +/* XXX: This value must match the one used in the MMU code. */ + if (env->cpuid_ext2_features & CPUID_EXT2_LM) { + /* 64 bit processor */ +#if defined(USE_KQEMU) + *eax = 0x00003020; /* 48 bits virtual, 32 bits physical */ +#else +/* XXX: The physical address space is limited to 42 bits in exec.c. */ + *eax = 0x00003028; /* 48 bits virtual, 40 bits physical */ +#endif + } else { +#if defined(USE_KQEMU) + *eax = 0x00000020; /* 32 bits physical */ +#else + if (env->cpuid_features & CPUID_PSE36) + *eax = 0x00000024; /* 36 bits physical */ + else + *eax = 0x00000020; /* 32 bits physical */ +#endif + } + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 0x8000000A: + *eax = 0x00000001; /* SVM Revision */ + *ebx = 0x00000010; /* nr of ASIDs */ + *ecx = 0; + *edx = 0; /* optional features */ + break; + default: + /* reserved values: zero */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + } +} diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c index d0919d95ff..c9c0936a70 100644 --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -1885,171 +1885,15 @@ void helper_single_step(void) void helper_cpuid(void) { - uint32_t index; + uint32_t eax, ebx, ecx, edx; helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0); - - index = (uint32_t)EAX; - /* test if maximum index reached */ - if (index & 0x80000000) { - if (index > env->cpuid_xlevel) - index = env->cpuid_level; - } else { - if (index > env->cpuid_level) - index = env->cpuid_level; - } - switch(index) { - case 0: - EAX = env->cpuid_level; - EBX = env->cpuid_vendor1; - EDX = env->cpuid_vendor2; - ECX = env->cpuid_vendor3; - break; - case 1: - EAX = env->cpuid_version; - EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ - ECX = env->cpuid_ext_features; - EDX = env->cpuid_features; - break; - case 2: - /* cache info: needed for Pentium Pro compatibility */ - EAX = 1; - EBX = 0; - ECX = 0; - EDX = 0x2c307d; - break; - case 4: - /* cache info: needed for Core compatibility */ - switch (ECX) { - case 0: /* L1 dcache info */ - EAX = 0x0000121; - EBX = 0x1c0003f; - ECX = 0x000003f; - EDX = 0x0000001; - break; - case 1: /* L1 icache info */ - EAX = 0x0000122; - EBX = 0x1c0003f; - ECX = 0x000003f; - EDX = 0x0000001; - break; - case 2: /* L2 cache info */ - EAX = 0x0000143; - EBX = 0x3c0003f; - ECX = 0x0000fff; - EDX = 0x0000001; - break; - default: /* end of info */ - EAX = 0; - EBX = 0; - ECX = 0; - EDX = 0; - break; - } - - break; - case 5: - /* mwait info: needed for Core compatibility */ - EAX = 0; /* Smallest monitor-line size in bytes */ - EBX = 0; /* Largest monitor-line size in bytes */ - ECX = CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; - EDX = 0; - break; - case 6: - /* Thermal and Power Leaf */ - EAX = 0; - EBX = 0; - ECX = 0; - EDX = 0; - break; - case 9: - /* Direct Cache Access Information Leaf */ - EAX = 0; /* Bits 0-31 in DCA_CAP MSR */ - EBX = 0; - ECX = 0; - EDX = 0; - break; - case 0xA: - /* Architectural Performance Monitoring Leaf */ - EAX = 0; - EBX = 0; - ECX = 0; - EDX = 0; - break; - case 0x80000000: - EAX = env->cpuid_xlevel; - EBX = env->cpuid_vendor1; - EDX = env->cpuid_vendor2; - ECX = env->cpuid_vendor3; - break; - case 0x80000001: - EAX = env->cpuid_features; - EBX = 0; - ECX = env->cpuid_ext3_features; - EDX = env->cpuid_ext2_features; - break; - case 0x80000002: - case 0x80000003: - case 0x80000004: - EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0]; - EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1]; - ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; - EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; - break; - case 0x80000005: - /* cache info (L1 cache) */ - EAX = 0x01ff01ff; - EBX = 0x01ff01ff; - ECX = 0x40020140; - EDX = 0x40020140; - break; - case 0x80000006: - /* cache info (L2 cache) */ - EAX = 0; - EBX = 0x42004200; - ECX = 0x02008140; - EDX = 0; - break; - case 0x80000008: - /* virtual & phys address size in low 2 bytes. */ -/* XXX: This value must match the one used in the MMU code. */ - if (env->cpuid_ext2_features & CPUID_EXT2_LM) { - /* 64 bit processor */ -#if defined(USE_KQEMU) - EAX = 0x00003020; /* 48 bits virtual, 32 bits physical */ -#else -/* XXX: The physical address space is limited to 42 bits in exec.c. */ - EAX = 0x00003028; /* 48 bits virtual, 40 bits physical */ -#endif - } else { -#if defined(USE_KQEMU) - EAX = 0x00000020; /* 32 bits physical */ -#else - if (env->cpuid_features & CPUID_PSE36) - EAX = 0x00000024; /* 36 bits physical */ - else - EAX = 0x00000020; /* 32 bits physical */ -#endif - } - EBX = 0; - ECX = 0; - EDX = 0; - break; - case 0x8000000A: - EAX = 0x00000001; /* SVM Revision */ - EBX = 0x00000010; /* nr of ASIDs */ - ECX = 0; - EDX = 0; /* optional features */ - break; - default: - /* reserved values: zero */ - EAX = 0; - EBX = 0; - ECX = 0; - EDX = 0; - break; - } + cpu_x86_cpuid(env, (uint32_t)EAX, &eax, &ebx, &ecx, &edx); + EAX = eax; + EBX = ebx; + ECX = ecx; + EDX = edx; } void helper_enter_level(int level, int data32, target_ulong t1) |