aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErwan Velu <erwan@seanodes.com>2006-09-04 22:34:55 +0200
committerH. Peter Anvin <hpa@zytor.com>2006-09-05 13:53:38 -0700
commit1f675cf4298e2cb5dd5bc3be2c3649ac81d4fac6 (patch)
tree81da0ba3df4648fec09696c98096058062607f94
parent329e23c16d0f3ecd4062ec715fbe047bf85f8976 (diff)
downloadsyslinux-1f675cf4298e2cb5dd5bc3be2c3649ac81d4fac6.tar.gz
syslinux-1f675cf4298e2cb5dd5bc3be2c3649ac81d4fac6.tar.xz
syslinux-1f675cf4298e2cb5dd5bc3be2c3649ac81d4fac6.zip
Adding a new com32 module to handle cpu informationsyslinux-3.21-pre1
From : Erwan Velu <erwan.velu@free.fr> This patch a new com32 module to handle cpu information. A new "cpu" structure can be filled by calling "detect_cpu(&cpu)". It provides : - Vendor name as string - Model as string - Vendor as integer - Model as integer - Family as integer - Stepping as Integer - Flags as boolean - SMP as boolean Note that SMP is just a manner to know if the bios annonce an MPTABLE. This code can't detect each processor. I've been adding a demo program called cpuidtest to show how it works. if (cpu.flags.lm == true) printf("This system is x86_64 compatible\n"); This example shows how to test if a system is X86_64 compatible. I hope it's simple enough ;) This code is mainly taken from the Linux Kernel. Greetings for all the guys who wrote it. Testing and feedback are welcome. Signed-off-by:Erwan Velu <erwan.velu@free.fr>
-rw-r--r--com32/include/cpufeature.h127
-rw-r--r--com32/include/cpuid.h228
-rw-r--r--com32/modules/Makefile5
-rw-r--r--com32/modules/cpuid.c371
-rw-r--r--com32/modules/cpuidtest.c82
5 files changed, 812 insertions, 1 deletions
diff --git a/com32/include/cpufeature.h b/com32/include/cpufeature.h
new file mode 100644
index 00000000..5db863ce
--- /dev/null
+++ b/com32/include/cpufeature.h
@@ -0,0 +1,127 @@
+/*
+ * cpufeature.h
+ *
+ * Defines x86 CPU feature bits
+ */
+
+#ifndef __ASM_I386_CPUFEATURE_H
+#define __ASM_I386_CPUFEATURE_H
+
+#define NCAPINTS 7 /* N 32-bit words worth of info */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
+#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES (0*32+21) /* Debug Trace Store */
+#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
+ /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */
+#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */
+#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */
+#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
+#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
+#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
+/* cpu types for specific tunings: */
+#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */
+#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */
+#define X86_FEATURE_P3 (3*32+ 6) /* P3 */
+#define X86_FEATURE_P4 (3*32+ 7) /* P4 */
+
+/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
+#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
+#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */
+#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
+#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */
+#define X86_FEATURE_CID (4*32+10) /* Context ID */
+#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */
+#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */
+
+/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
+#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
+#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */
+#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
+#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */
+
+/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
+#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
+#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
+
+#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
+#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability)
+
+#define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU)
+#define cpu_has_vme boot_cpu_has(X86_FEATURE_VME)
+#define cpu_has_de boot_cpu_has(X86_FEATURE_DE)
+#define cpu_has_pse boot_cpu_has(X86_FEATURE_PSE)
+#define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC)
+#define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE)
+#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
+#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
+#define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP)
+#define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR)
+#define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX)
+#define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR)
+#define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM)
+#define cpu_has_xmm2 boot_cpu_has(X86_FEATURE_XMM2)
+#define cpu_has_xmm3 boot_cpu_has(X86_FEATURE_XMM3)
+#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
+#define cpu_has_mp boot_cpu_has(X86_FEATURE_MP)
+#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX)
+#define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR)
+#define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR)
+#define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
+#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE)
+#define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
+#define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT)
+#define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN)
+
+#endif /* __ASM_I386_CPUFEATURE_H */
+
+/*
+ * Local Variables:
+ * mode:c
+ * comment-column:42
+ * End:
+ */
diff --git a/com32/include/cpuid.h b/com32/include/cpuid.h
new file mode 100644
index 00000000..a1df807d
--- /dev/null
+++ b/com32/include/cpuid.h
@@ -0,0 +1,228 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 Erwan Velu - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef CPUID_H
+#define CPUID_H
+
+#include "stdbool.h"
+#include "cpufeature.h"
+#define u32 unsigned int
+#define __u32 u32
+#define __u16 unsigned short
+#define __u8 unsigned char
+#define PAGE_SIZE 4096
+
+#define CPU_MODEL_SIZE 48
+#define CPU_VENDOR_SIZE 48
+
+typedef struct {
+ __u32 l;
+ __u32 h;
+} __u64;
+
+typedef struct {
+ bool fpu; /* Onboard FPU */
+ bool vme; /* Virtual Mode Extensions */
+ bool de; /* Debugging Extensions */
+ bool pse; /* Page Size Extensions */
+ bool tsc; /* Time Stamp Counter */
+ bool msr; /* Model-Specific Registers, RDMSR, WRMSR */
+ bool pae; /* Physical Address Extensions */
+ bool mce; /* Machine Check Architecture */
+ bool cx8; /* CMPXCHG8 instruction */
+ bool apic;/* Onboard APIC */
+ bool sep; /* SYSENTER/SYSEXIT */
+ bool mtrr;/* Memory Type Range Registers */
+ bool pge; /* Page Global Enable */
+ bool mca; /* Machine Check Architecture */
+ bool cmov;/* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+ bool pat; /* Page Attribute Table */
+ bool pse_36; /* 36-bit PSEs */
+ bool psn; /* Processor serial number */
+ bool clflsh; /* Supports the CLFLUSH instruction */
+ bool dts; /* Debug Trace Store */
+ bool acpi;/* ACPI via MSR */
+ bool mmx; /* Multimedia Extensions */
+ bool fxsr;/* FXSAVE and FXRSTOR instructions (fast save and restore */
+ /* of FPU context), and CR4.OSFXSR available */
+ bool sse; /* Streaming SIMD Extensions */
+ bool sse2;/* Streaming SIMD Extensions 2*/
+ bool ss; /* CPU self snoop */
+ bool htt; /* Hyper-Threading */
+ bool acc; /* Automatic clock control */
+ bool syscall; /* SYSCALL/SYSRET */
+ bool mp; /* MP Capable. */
+ bool nx; /* Execute Disable */
+ bool mmxext; /* AMD MMX extensions */
+ bool lm; /* Long Mode (x86-64) */
+ bool nowext;/* AMD 3DNow! extensions */
+ bool now; /* 3DNow! */
+ bool smp; /* A smp configuration has been found*/
+} __attribute__((__packed__)) s_cpu_flags;
+
+typedef struct {
+char vendor[CPU_VENDOR_SIZE];
+__u8 vendor_id;
+__u8 family;
+char model[CPU_MODEL_SIZE];
+__u8 model_id;
+__u8 stepping;
+s_cpu_flags flags;
+} s_cpu;
+
+/**********************************************************************************/
+/**********************************************************************************/
+/* From this point this is some internal stuff mainly taken from the linux kernel */
+/**********************************************************************************/
+/**********************************************************************************/
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_NEXGEN 4
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_RISE 6
+#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NSC 8
+#define X86_VENDOR_NUM 9
+#define X86_VENDOR_UNKNOWN 0xff
+
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+ return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
+}
+
+#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
+
+/*
+ * CPU type and hardware bug flags. Kept separately for each CPU.
+ * Members of this structure are referenced in head.S, so think twice
+ * before touching them. [mj]
+ */
+
+struct cpuinfo_x86 {
+ __u8 x86; /* CPU family */
+ __u8 x86_vendor; /* CPU vendor */
+ __u8 x86_model;
+ __u8 x86_mask;
+ char wp_works_ok; /* It doesn't on 386's */
+ char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
+ char hard_math;
+ char rfu;
+ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
+ unsigned long x86_capability[NCAPINTS];
+ char x86_vendor_id[16];
+ char x86_model_id[64];
+ int x86_cache_size; /* in KB - valid for CPUS which support this
+ call */
+ int x86_cache_alignment; /* In bytes */
+ char fdiv_bug;
+ char f00f_bug;
+ char coma_bug;
+ char pad0;
+ int x86_power;
+ unsigned long loops_per_jiffy;
+#ifdef CONFIG_SMP
+ cpumask_t llc_shared_map; /* cpus sharing the last level cache */
+#endif
+ unsigned char x86_max_cores; /* cpuid returned max cores value */
+ unsigned char booted_cores; /* number of cores as seen by OS */
+ unsigned char apicid;
+} __attribute__((__packed__));
+#endif
+
+struct cpu_model_info {
+ int vendor;
+ int family;
+ char *model_names[16];
+};
+
+/* attempt to consolidate cpu attributes */
+struct cpu_dev {
+ char * c_vendor;
+
+ /* some have two possibilities for cpuid string */
+ char * c_ident[2];
+
+ struct cpu_model_info c_models[4];
+
+ void (*c_init)(struct cpuinfo_x86 * c);
+ void (*c_identify)(struct cpuinfo_x86 * c);
+ unsigned int (*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
+};
+
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
+{
+ __asm__("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (op), "c"(0));
+}
+
+/*
+ * Structure definitions for SMP machines following the
+ * Intel Multiprocessing Specification 1.1 and 1.4.
+ */
+
+/*
+ * This tag identifies where the SMP configuration
+ * information is.
+ */
+
+#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
+
+struct intel_mp_floating
+{
+ char mpf_signature[4]; /* "_MP_" */
+ unsigned long mpf_physptr; /* Configuration table address */
+ unsigned char mpf_length; /* Our length (paragraphs) */
+ unsigned char mpf_specification;/* Specification version */
+ unsigned char mpf_checksum; /* Checksum (makes sum 0) */
+ unsigned char mpf_feature1; /* Standard or configuration ? */
+ unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
+ unsigned char mpf_feature3; /* Unused (0) */
+ unsigned char mpf_feature4; /* Unused (0) */
+ unsigned char mpf_feature5; /* Unused (0) */
+};
+
+
+extern void get_cpu_vendor(struct cpuinfo_x86 *c);
+extern void detect_cpu(s_cpu *cpu);
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index fc8c8619..efba4c36 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -44,7 +44,7 @@ AUXDIR = $(LIBDIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-MODULES = chain.c32 menu.c32 ethersel.c32 mboot.c32 dmitest.c32
+MODULES = chain.c32 menu.c32 ethersel.c32 mboot.c32 dmitest.c32 cpuidtest.c32
TESTFILES = menu.lnx
all: $(MODULES) $(TESTFILES)
@@ -76,6 +76,9 @@ all: $(MODULES) $(TESTFILES)
%.c32: %.elf
$(OBJCOPY) -O binary $< $@
+cpuidtest.elf : cpuidtest.o cpuid.o $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
dmitest.elf : dmitest.o dmi_utils.o dmi.o $(LIBS)
$(LD) $(LDFLAGS) -o $@ $^
diff --git a/com32/modules/cpuid.c b/com32/modules/cpuid.c
new file mode 100644
index 00000000..acb18bf5
--- /dev/null
+++ b/com32/modules/cpuid.c
@@ -0,0 +1,371 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 Erwan Velu - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "cpuid.h"
+
+struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
+
+/*
+* CPUID functions returning a single datum
+*/
+static inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax;
+
+ __asm__("cpuid"
+ : "=a" (eax)
+ : "0" (op)
+ : "bx", "cx", "dx");
+ return eax;
+}
+
+static inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ecx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=c" (ecx)
+ : "0" (op)
+ : "bx", "dx" );
+ return ecx;
+}
+static inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=d" (edx)
+ : "0" (op)
+ : "bx", "cx");
+ return edx;
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
+{
+ u32 f1, f2;
+
+ asm("pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
+
+ return ((f1^f2) & flag) != 0;
+}
+
+/* Probe for the CPUID instruction */
+static int have_cpuid_p(void)
+{
+ return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+static struct cpu_dev amd_cpu_dev = {
+ .c_vendor = "AMD",
+ .c_ident = { "AuthenticAMD" }
+};
+
+static struct cpu_dev intel_cpu_dev = {
+ .c_vendor = "Intel",
+ .c_ident = { "GenuineIntel" }
+};
+
+static struct cpu_dev cyrix_cpu_dev = {
+ .c_vendor = "Cyrix",
+ .c_ident = { "CyrixInstead" }
+};
+
+static struct cpu_dev umc_cpu_dev = {
+ .c_vendor = "UMC",
+ .c_ident = { "UMC UMC UMC" }
+
+};
+
+static struct cpu_dev nexgen_cpu_dev = {
+ .c_vendor = "Nexgen",
+ .c_ident = { "NexGenDriven" }
+};
+
+static struct cpu_dev centaur_cpu_dev = {
+ .c_vendor = "Centaur",
+ .c_ident = { "CentaurHauls" }
+};
+
+static struct cpu_dev rise_cpu_dev = {
+ .c_vendor = "Rise",
+ .c_ident = { "RiseRiseRise" }
+};
+
+static struct cpu_dev transmeta_cpu_dev = {
+ .c_vendor = "Transmeta",
+ .c_ident = { "GenuineTMx86", "TransmetaCPU" }
+};
+
+void init_cpu_devs(void)
+{
+ cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
+ cpu_devs[X86_VENDOR_CYRIX] = &cyrix_cpu_dev;
+ cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
+ cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev;
+ cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev;
+ cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
+ cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
+ cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
+}
+
+void get_cpu_vendor(struct cpuinfo_x86 *c)
+{
+ char *v = c->x86_vendor_id;
+ int i;
+ init_cpu_devs();
+ for (i = 0; i < X86_VENDOR_NUM; i++) {
+ if (cpu_devs[i]) {
+ if (!strcmp(v,cpu_devs[i]->c_ident[0]) ||
+ (cpu_devs[i]->c_ident[1] &&
+ !strcmp(v,cpu_devs[i]->c_ident[1]))) {
+ c->x86_vendor = i;
+ return;
+ }
+ }
+ }
+
+ c->x86_vendor = X86_VENDOR_UNKNOWN;
+}
+
+int get_model_name(struct cpuinfo_x86 *c)
+{
+ unsigned int *v;
+ char *p, *q;
+
+ if (cpuid_eax(0x80000000) < 0x80000004)
+ return 0;
+
+ v = (unsigned int *) c->x86_model_id;
+ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+ c->x86_model_id[48] = 0;
+
+ /* Intel chips right-justify this string for some dumb reason;
+ undo that brain damage */
+ p = q = &c->x86_model_id[0];
+ while ( *p == ' ' )
+ p++;
+ if ( p != q ) {
+ while ( *p )
+ *q++ = *p++;
+ while ( q <= &c->x86_model_id[48] )
+ *q++ = '\0'; /* Zero-pad the rest */
+ }
+
+ return 1;
+}
+
+void generic_identify(struct cpuinfo_x86 *c)
+{
+ u32 tfms, xlvl;
+ int junk;
+ /* Get vendor name */
+ cpuid(0x00000000, &c->cpuid_level,
+ (int *)&c->x86_vendor_id[0],
+ (int *)&c->x86_vendor_id[8],
+ (int *)&c->x86_vendor_id[4]);
+
+ get_cpu_vendor(c);
+ /* Intel-defined flags: level 0x00000001 */
+ if ( c->cpuid_level >= 0x00000001 ) {
+ u32 capability, excap;
+ cpuid(0x00000001, &tfms, &junk, &excap, &capability);
+ c->x86_capability[0] = capability;
+ c->x86_capability[4] = excap;
+ c->x86 = (tfms >> 8) & 15;
+ c->x86_model = (tfms >> 4) & 15;
+ if (c->x86 == 0xf) {
+ c->x86 += (tfms >> 20) & 0xff;
+ c->x86_model += ((tfms >> 16) & 0xF) << 4;
+ }
+ c->x86_mask = tfms & 15;
+ if (capability & (1<<19))
+ c->x86_cache_alignment = ((junk >> 8) & 0xff) * 8;
+ } else {
+ /* Have CPUID level 0 only - unheard of */
+ c->x86 = 4;
+ }
+
+ /* AMD-defined flags: level 0x80000001 */
+ xlvl = cpuid_eax(0x80000000);
+ if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+ if ( xlvl >= 0x80000001 ) {
+ c->x86_capability[1] = cpuid_edx(0x80000001);
+ c->x86_capability[6] = cpuid_ecx(0x80000001);
+ }
+ if ( xlvl >= 0x80000004 )
+ get_model_name(c); /* Default name */
+ }
+}
+
+/*
+ * Checksum an MP configuration block.
+ */
+
+static int mpf_checksum(unsigned char *mp, int len)
+{
+ int sum = 0;
+
+ while (len--)
+ sum += *mp++;
+
+ return sum & 0xFF;
+}
+
+static int smp_scan_config (unsigned long base, unsigned long length)
+{
+ unsigned long *bp = base;
+ struct intel_mp_floating *mpf;
+
+// printf("Scan SMP from %p for %ld bytes.\n", bp,length);
+ if (sizeof(*mpf) != 16) {
+ printf("Error: MPF size\n");
+ return 0;
+ }
+
+ while (length > 0) {
+ mpf = (struct intel_mp_floating *)bp;
+ if ((*bp == SMP_MAGIC_IDENT) &&
+ (mpf->mpf_length == 1) &&
+ !mpf_checksum((unsigned char *)bp, 16) &&
+ ((mpf->mpf_specification == 1)
+ || (mpf->mpf_specification == 4)) ) {
+ return 1;
+ }
+ bp += 4;
+ length -= 16;
+ }
+ return 0;
+}
+
+int find_smp_config (void)
+{
+// unsigned int address;
+
+ /*
+ * FIXME: Linux assumes you have 640K of base ram..
+ * this continues the error...
+ *
+ * 1) Scan the bottom 1K for a signature
+ * 2) Scan the top 1K of base RAM
+ * 3) Scan the 64K of bios
+ */
+ if (smp_scan_config(0x0,0x400) ||
+ smp_scan_config(639*0x400,0x400) ||
+ smp_scan_config(0xF0000,0x10000))
+ return 1;
+ /*
+ * If it is an SMP machine we should know now, unless the
+ * configuration is in an EISA/MCA bus machine with an
+ * extended bios data area.
+ *
+ * there is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E, calculate and scan it here.
+ *
+ * NOTE! There are Linux loaders that will corrupt the EBDA
+ * area, and as such this kind of SMP config may be less
+ * trustworthy, simply because the SMP table may have been
+ * stomped on during early boot. These loaders are buggy and
+ * should be fixed.
+ *
+ * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
+ */
+
+// address = get_bios_ebda();
+// if (address)
+// smp_scan_config(address, 0x400);
+ return 0;
+}
+
+
+void set_cpu_flags(struct cpuinfo_x86 *c, s_cpu *cpu) {
+cpu->flags.fpu=cpu_has(c, X86_FEATURE_FPU);
+cpu->flags.vme=cpu_has(c, X86_FEATURE_VME);
+cpu->flags.de=cpu_has(c, X86_FEATURE_DE);
+cpu->flags.pse=cpu_has(c, X86_FEATURE_PSE);
+cpu->flags.tsc=cpu_has(c, X86_FEATURE_TSC);
+cpu->flags.msr=cpu_has(c, X86_FEATURE_MSR);
+cpu->flags.pae=cpu_has(c, X86_FEATURE_PAE);
+cpu->flags.mce=cpu_has(c, X86_FEATURE_MCE);
+cpu->flags.cx8=cpu_has(c, X86_FEATURE_CX8);
+cpu->flags.apic=cpu_has(c, X86_FEATURE_APIC);
+cpu->flags.sep=cpu_has(c, X86_FEATURE_SEP);
+cpu->flags.mtrr=cpu_has(c, X86_FEATURE_MTRR);
+cpu->flags.pge=cpu_has(c, X86_FEATURE_PGE);
+cpu->flags.mca=cpu_has(c, X86_FEATURE_MCA);
+cpu->flags.cmov=cpu_has(c, X86_FEATURE_CMOV);
+cpu->flags.pat=cpu_has(c, X86_FEATURE_PAT);
+cpu->flags.pse_36=cpu_has(c, X86_FEATURE_PSE36);
+cpu->flags.psn=cpu_has(c, X86_FEATURE_PN);
+cpu->flags.clflsh=cpu_has(c, X86_FEATURE_CLFLSH);
+cpu->flags.dts=cpu_has(c, X86_FEATURE_DTES);
+cpu->flags.acpi=cpu_has(c, X86_FEATURE_ACPI);
+cpu->flags.mmx=cpu_has(c, X86_FEATURE_MMX);
+cpu->flags.fxsr=cpu_has(c, X86_FEATURE_FXSR);
+cpu->flags.sse=cpu_has(c, X86_FEATURE_XMM);
+cpu->flags.sse2=cpu_has(c, X86_FEATURE_XMM2);
+cpu->flags.ss=cpu_has(c, X86_FEATURE_SELFSNOOP);
+cpu->flags.htt=cpu_has(c, X86_FEATURE_HT);
+cpu->flags.acc=cpu_has(c, X86_FEATURE_ACC);
+cpu->flags.syscall=cpu_has(c, X86_FEATURE_SYSCALL);
+cpu->flags.mp=cpu_has(c, X86_FEATURE_MP);
+cpu->flags.nx=cpu_has(c, X86_FEATURE_NX);
+cpu->flags.mmxext=cpu_has(c, X86_FEATURE_MMXEXT);
+cpu->flags.lm=cpu_has(c, X86_FEATURE_LM);
+cpu->flags.nowext=cpu_has(c, X86_FEATURE_3DNOWEXT);
+cpu->flags.now=cpu_has(c, X86_FEATURE_3DNOW);
+cpu->flags.smp = find_smp_config();
+}
+
+void set_generic_info(struct cpuinfo_x86 *c,s_cpu *cpu) {
+ cpu->family=c->x86;
+ cpu->vendor_id=c->x86_vendor;
+ cpu->model_id=c->x86_model;
+ cpu->stepping=c->x86_mask;
+ strncpy(cpu->vendor,cpu_devs[c->x86_vendor]->c_vendor,CPU_VENDOR_SIZE);
+ strncpy(cpu->model,c->x86_model_id,CPU_MODEL_SIZE);
+}
+
+void detect_cpu(s_cpu *cpu)
+{
+ struct cpuinfo_x86 c;
+ c.x86_cache_alignment = 32;
+ c.x86_cache_size = -1;
+ c.x86_vendor = X86_VENDOR_UNKNOWN;
+ c.cpuid_level = -1; /* CPUID not detected */
+ c.x86_model = c.x86_mask = 0; /* So far unknown... */
+ c.x86_vendor_id[0] = '\0'; /* Unset */
+ c.x86_model_id[0] = '\0'; /* Unset */
+ memset(&c.x86_vendor_id,'\0',CPU_VENDOR_SIZE);
+
+ if (!have_cpuid_p())
+ return;
+
+ generic_identify(&c);
+ set_generic_info(&c,cpu);
+ set_cpu_flags(&c,cpu);
+}
diff --git a/com32/modules/cpuidtest.c b/com32/modules/cpuidtest.c
new file mode 100644
index 00000000..ce96d681
--- /dev/null
+++ b/com32/modules/cpuidtest.c
@@ -0,0 +1,82 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 Erwan Velu - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * cpuidtest.c
+ *
+ * A CPUID demo program using libcom32
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <console.h>
+#include "cpuid.h"
+
+char display_line;
+
+int main(void)
+{
+ s_cpu cpu;
+ openconsole(&dev_stdcon_r, &dev_stdcon_w);
+
+ for (;;) {
+ detect_cpu(&cpu);
+ printf("Vendor = %s\n",cpu.vendor);
+ printf("Model = %s\n",cpu.model);
+ printf("Vendor ID = %d\n",cpu.vendor_id);
+ printf("Family = %d\n",cpu.family);
+ printf("Model ID = %d\n",cpu.model_id);
+ printf("Stepping = %d\n",cpu.stepping);
+ printf("Flags = ");
+ if (cpu.flags.fpu) printf("fpu ");
+ if (cpu.flags.vme) printf("vme ");
+ if (cpu.flags.de) printf("de ");
+ if (cpu.flags.pse) printf("pse ");
+ if (cpu.flags.tsc) printf("tsc ");
+ if (cpu.flags.msr) printf("msr ");
+ if (cpu.flags.pae) printf("pae ");
+ if (cpu.flags.mce) printf("mce ");
+ if (cpu.flags.cx8) printf("cx8 ");
+ if (cpu.flags.apic) printf("apic ");
+ if (cpu.flags.sep) printf("sep ");
+ if (cpu.flags.mtrr) printf("mtrr ");
+ if (cpu.flags.pge) printf("pge ");
+ if (cpu.flags.mca) printf("mca ");
+ if (cpu.flags.cmov) printf("cmov ");
+ if (cpu.flags.pat) printf("pat ");
+ if (cpu.flags.pse_36) printf("pse_36 ");
+ if (cpu.flags.psn) printf("psn ");
+ if (cpu.flags.clflsh) printf("clflsh ");
+ if (cpu.flags.dts) printf("dts ");
+ if (cpu.flags.acpi) printf("acpi ");
+ if (cpu.flags.mmx) printf("mmx ");
+ if (cpu.flags.sse) printf("sse ");
+ if (cpu.flags.sse2) printf("sse2 ");
+ if (cpu.flags.ss) printf("ss ");
+ if (cpu.flags.htt) printf("ht ");
+ if (cpu.flags.acc) printf("acc ");
+ if (cpu.flags.syscall) printf("syscall ");
+ if (cpu.flags.mp) printf("mp ");
+ if (cpu.flags.nx) printf("nx ");
+ if (cpu.flags.mmxext) printf("mmxext ");
+ if (cpu.flags.lm) printf("lm ");
+ if (cpu.flags.nowext) printf("3dnowext ");
+ if (cpu.flags.now) printf("3dnow! ");
+ printf("\n");
+ printf("SMP = ");
+ if (cpu.flags.smp) printf("yes\n");
+ else printf("no\n");
+ break;
+ }
+
+ return 0;
+}