[PATCH 2/3] Split CPUID from op_helper

Anthony Liguori
2008-10-28T20:13:56Z

KVM needs to call CPUID from outside of the TCG code. This patch
splits out the CPUID logic into a separate helper that both the op
helper and KVM can call.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index b1678ef..263a477 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 c2e1a88..905ae9b 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 ebb5824..e424c61 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)