From 1f675cf4298e2cb5dd5bc3be2c3649ac81d4fac6 Mon Sep 17 00:00:00 2001 From: Erwan Velu Date: Mon, 4 Sep 2006 22:34:55 +0200 Subject: [PATCH] Adding a new com32 module to handle cpu information From : Erwan Velu 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 --- com32/include/cpufeature.h | 127 ++++++++++++++++ com32/include/cpuid.h | 228 ++++++++++++++++++++++++++++ com32/modules/Makefile | 5 +- com32/modules/cpuid.c | 371 +++++++++++++++++++++++++++++++++++++++++++++ com32/modules/cpuidtest.c | 82 ++++++++++ 5 files changed, 812 insertions(+), 1 deletion(-) create mode 100644 com32/include/cpufeature.h create mode 100644 com32/include/cpuid.h create mode 100644 com32/modules/cpuid.c create mode 100644 com32/modules/cpuidtest.c diff --git a/com32/include/cpufeature.h b/com32/include/cpufeature.h new file mode 100644 index 0000000..5db863c --- /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 0000000..a1df807 --- /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 fc8c861..efba4c3 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 0000000..acb18bf --- /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 +#include +#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] = ¢aur_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 0000000..ce96d68 --- /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 +#include +#include +#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; +} -- 2.7.4