Goto sanos source index
//
// cpu.c
//
// CPU information
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <os/krnl.h>
struct cpu cpu;
struct cpu_model_info {
int vendor;
int family;
char *model_names[16];
};
static struct cpu_model_info cpu_models[] = {
{CPU_VENDOR_INTEL, 4, {"486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_INTEL, 5, {"Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200", "OverDrive PODP5V83", "Pentium MMX", NULL, NULL, "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_INTEL, 6, {"Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, "Pentium III (Cascades)", NULL, NULL, NULL, NULL}},
{CPU_VENDOR_AMD, 4, {NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB"}},
{CPU_VENDOR_AMD, 5, {"K5/SSA5", "K5", "K5", "K5", NULL, NULL, "K6", "K6", "K6-2", "K6-3", NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_AMD, 6, {"Athlon", "Athlon", "Athlon", NULL, "Athlon", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_UMC, 4, {NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_NEXGEN, 5, {"Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
{CPU_VENDOR_RISE, 5, {"iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL, NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL}}
};
static char *table_lookup_model(struct cpu *c) {
struct cpu_model_info *info = cpu_models;
int i;
if (c->model >= 16) return NULL;
for (i = 0; i < sizeof(cpu_models) / sizeof(struct cpu_model_info); i++) {
if (info->vendor == c->vendor && info->family == c->family) {
return info->model_names[c->model];
}
info++;
}
return NULL;
}
static int eflag_supported(unsigned long flag) {
unsigned long f1, f2;
__asm {
// Save eflags
pushfd
// Get eflags into eax
pushfd
pop eax
// Store eflags in f1
mov f1, eax
// Toggle the flag we are testing
xor eax, flag
// Load eax into eflags
push eax
popfd
// Get eflags into eax
pushfd
pop eax
// Save in f2
mov f2, eax
// Restore eflags
popfd
}
return ((f1 ^ f2) & flag) != 0;
}
static int cpuid_supported() {
return eflag_supported(EFLAGS_ID);
}
void init_cpu() {
unsigned long val[4];
char *vendorname;
// Check for CPUID supported
if (!cpuid_supported()) {
// It must be either an 386 or 486 processor
if (eflag_supported(EFLAGS_AC)) {
cpu.family = CPU_FAMILY_486;
} else {
cpu.family = CPU_FAMILY_386;
}
cpu.vendor = CPU_VENDOR_UNKNOWN;
strcpy(cpu.vendorid, "IntelCompatible");
vendorname = "Intel Compatible";
sprintf(cpu.modelid, "%s %d86", vendorname, cpu.family);
} else {
// Get vendor ID
cpuid(0x00000000, val);
cpu.cpuid_level = val[0];
memcpy(cpu.vendorid + 0, val + 1, 4);
memcpy(cpu.vendorid + 4, val + 3, 4);
memcpy(cpu.vendorid + 8, val + 2, 4);
if (strcmp(cpu.vendorid, "GenuineIntel") == 0) {
cpu.vendor = CPU_VENDOR_INTEL;
vendorname = "Intel";
} else if (strcmp(cpu.vendorid, "AuthenticAMD") == 0) {
cpu.vendor = CPU_VENDOR_AMD;
vendorname = "AMD";
} else if (strcmp(cpu.vendorid, "CyrixInstead") == 0) {
cpu.vendor = CPU_VENDOR_CYRIX;
vendorname = "Cyrix";
} else if (strcmp(cpu.vendorid, "UMC UMC UMC ") == 0) {
cpu.vendor = CPU_VENDOR_UMC;
vendorname = "UMC";
} else if (strcmp(cpu.vendorid, "CentaurHauls") == 0) {
cpu.vendor = CPU_VENDOR_CENTAUR;
vendorname = "Centaur";
} else if (strcmp(cpu.vendorid, "NexGenDriven") == 0) {
cpu.vendor = CPU_VENDOR_NEXGEN;
vendorname = "NexGen";
} else if (strcmp(cpu.vendorid, "GenuineTMx86") == 0 || strcmp(cpu.vendorid, "TransmetaCPU") == 0) {
cpu.vendor = CPU_VENDOR_TRANSMETA;
vendorname = "Transmeta";
} else {
cpu.vendor = CPU_VENDOR_UNKNOWN;
vendorname = cpu.vendorid;
}
// Get model and features
if (cpu.cpuid_level >= 0x00000001) {
cpuid(0x00000001, val);
cpu.family = (val[0] >> 8) & 15;
cpu.model = (val[0] >> 4) & 15;
cpu.stepping = val[0] & 15;
cpu.features = val[3];
}
// SEP CPUID bug: Pentium Pro reports SEP but doesn't have it
if (cpu.family == 6 && cpu.model < 3 && cpu.stepping < 3) cpu.features &= ~CPU_FEATURE_SEP;
// Get brand string
cpuid(0x80000000, val);
if (val[0] > 0x80000000) {
char model[64];
char *p, *q;
int space;
memset(model, 0, 64);
cpuid(0x80000002, (unsigned long *) model);
cpuid(0x80000003, (unsigned long *) (model + 16));
cpuid(0x80000004, (unsigned long *) (model + 32));
// Trim brand string
p = model;
q = cpu.modelid;
space = 0;
while (*p == ' ') p++;
while (*p) {
if (*p == ' ') {
space = 1;
} else {
if (space) *q++ = ' ';
space = 0;
*q++ = *p;
}
p++;
}
*q = 0;
} else {
char *modelid = table_lookup_model(&cpu);
if (modelid) {
sprintf(cpu.modelid, "%s %s", vendorname, modelid);
} else {
sprintf(cpu.modelid, "%s %d86", vendorname, cpu.family);
}
}
}
kprintf(KERN_INFO "cpu: %s family %d model %d stepping %d\n", cpu.modelid, cpu.family, cpu.model, cpu.stepping);
}
int cpu_proc(struct proc_file *pf, void *arg) {
pprintf(pf, "%s family %d model %d stepping %d\n", cpu.modelid, cpu.family, cpu.model, cpu.stepping);
return 0;
}
int cpu_sysinfo(struct cpuinfo *info) {
info->cpu_vendor = cpu.vendor;
info->cpu_family = cpu.family;
info->cpu_model = cpu.model;
info->cpu_stepping = cpu.stepping;
info->cpu_mhz = cpu.mhz;
info->cpu_features = cpu.features;
info->pagesize = PAGESIZE;
strcpy(info->vendorid, cpu.vendorid);
strcpy(info->modelid, cpu.modelid);
return 0;
}
__declspec(naked) unsigned long eflags() {
__asm {
pushfd
pop eax
ret
}
}