/*
|
/*
|
* linux/arch/i386/kernel/setup.c
|
* linux/arch/i386/kernel/setup.c
|
*
|
*
|
* Copyright (C) 1995 Linus Torvalds
|
* Copyright (C) 1995 Linus Torvalds
|
*/
|
*/
|
|
|
/*
|
/*
|
* This file handles the architecture-dependent parts of initialization
|
* This file handles the architecture-dependent parts of initialization
|
*/
|
*/
|
|
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
#include <linux/malloc.h>
|
#include <linux/malloc.h>
|
#include <linux/ldt.h>
|
#include <linux/ldt.h>
|
#include <linux/user.h>
|
#include <linux/user.h>
|
#include <linux/a.out.h>
|
#include <linux/a.out.h>
|
#include <linux/tty.h>
|
#include <linux/tty.h>
|
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
#include <linux/delay.h>
|
#include <linux/delay.h>
|
#include <linux/config.h>
|
#include <linux/config.h>
|
#ifdef CONFIG_APM
|
#ifdef CONFIG_APM
|
#include <linux/apm_bios.h>
|
#include <linux/apm_bios.h>
|
#endif
|
#endif
|
#ifdef CONFIG_BLK_DEV_RAM
|
#ifdef CONFIG_BLK_DEV_RAM
|
#include <linux/blk.h>
|
#include <linux/blk.h>
|
#endif
|
#endif
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/smp.h>
|
#include <asm/smp.h>
|
#include <asm/io.h>
|
#include <asm/io.h>
|
|
|
/*
|
/*
|
* Tell us the machine setup..
|
* Tell us the machine setup..
|
*/
|
*/
|
char hard_math = 0; /* set by kernel/head.S */
|
char hard_math = 0; /* set by kernel/head.S */
|
char x86 = 0; /* set by kernel/head.S to 3..6 */
|
char x86 = 0; /* set by kernel/head.S to 3..6 */
|
char x86_model = 0; /* set by kernel/head.S */
|
char x86_model = 0; /* set by kernel/head.S */
|
char x86_mask = 0; /* set by kernel/head.S */
|
char x86_mask = 0; /* set by kernel/head.S */
|
int x86_capability = 0; /* set by kernel/head.S */
|
int x86_capability = 0; /* set by kernel/head.S */
|
int x86_ext_capability = 0; /* newer CPUs have this */
|
int x86_ext_capability = 0; /* newer CPUs have this */
|
int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */
|
int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */
|
int pentium_f00f_bug = 0; /* set if Pentium(TM) with F00F bug */
|
int pentium_f00f_bug = 0; /* set if Pentium(TM) with F00F bug */
|
int have_cpuid = 0; /* set if CPUID instruction works */
|
int have_cpuid = 0; /* set if CPUID instruction works */
|
int ext_cpuid = 0; /* if != 0, highest available CPUID value */
|
int ext_cpuid = 0; /* if != 0, highest available CPUID value */
|
|
|
char x86_vendor_id[13] = "GenuineIntel";/* default */
|
char x86_vendor_id[13] = "GenuineIntel";/* default */
|
|
|
static char *Cx86_step = "unknown"; /* stepping info for Cyrix CPUs */
|
static char *Cx86_step = "unknown"; /* stepping info for Cyrix CPUs */
|
|
|
static unsigned char Cx86_mult = 0; /* clock multiplier for Cyrix CPUs */
|
static unsigned char Cx86_mult = 0; /* clock multiplier for Cyrix CPUs */
|
|
|
static const char *x86_clkmult[] = {
|
static const char *x86_clkmult[] = {
|
"unknown", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5",
|
"unknown", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5",
|
"6", "6.5", "7", "7.5", "8"
|
"6", "6.5", "7", "7.5", "8"
|
};
|
};
|
|
|
char ignore_irq13 = 0; /* set if exception 16 works */
|
char ignore_irq13 = 0; /* set if exception 16 works */
|
char wp_works_ok = -1; /* set if paging hardware honours WP */
|
char wp_works_ok = -1; /* set if paging hardware honours WP */
|
char hlt_works_ok = 1; /* set if the "hlt" instruction works */
|
char hlt_works_ok = 1; /* set if the "hlt" instruction works */
|
|
|
/*
|
/*
|
* Bus types ..
|
* Bus types ..
|
*/
|
*/
|
int EISA_bus = 0;
|
int EISA_bus = 0;
|
|
|
/*
|
/*
|
* Setup options
|
* Setup options
|
*/
|
*/
|
struct drive_info_struct { char dummy[32]; } drive_info;
|
struct drive_info_struct { char dummy[32]; } drive_info;
|
struct screen_info screen_info;
|
struct screen_info screen_info;
|
#ifdef CONFIG_APM
|
#ifdef CONFIG_APM
|
struct apm_bios_info apm_bios_info;
|
struct apm_bios_info apm_bios_info;
|
#endif
|
#endif
|
|
|
unsigned char aux_device_present;
|
unsigned char aux_device_present;
|
|
|
#ifdef CONFIG_BLK_DEV_RAM
|
#ifdef CONFIG_BLK_DEV_RAM
|
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
|
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
|
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
|
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
|
extern int rd_image_start; /* starting block # of image */
|
extern int rd_image_start; /* starting block # of image */
|
#endif
|
#endif
|
|
|
extern int root_mountflags;
|
extern int root_mountflags;
|
extern int _etext, _edata, _end;
|
extern int _etext, _edata, _end;
|
|
|
extern char empty_zero_page[PAGE_SIZE];
|
extern char empty_zero_page[PAGE_SIZE];
|
|
|
/*
|
/*
|
* This is set up by the setup-routine at boot-time
|
* This is set up by the setup-routine at boot-time
|
*/
|
*/
|
#define PARAM empty_zero_page
|
#define PARAM empty_zero_page
|
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
|
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
|
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
|
#endif
|
#endif
|
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
|
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
|
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
|
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
|
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
|
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
|
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
|
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
|
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
|
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
|
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
|
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
|
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
|
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
|
#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
|
#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
|
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
|
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
|
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
|
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
|
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
|
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
|
#define COMMAND_LINE ((char *) (PARAM+2048))
|
#define COMMAND_LINE ((char *) (PARAM+2048))
|
#define COMMAND_LINE_SIZE 256
|
#define COMMAND_LINE_SIZE 256
|
|
|
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
#define RAMDISK_PROMPT_FLAG 0x8000
|
#define RAMDISK_PROMPT_FLAG 0x8000
|
#define RAMDISK_LOAD_FLAG 0x4000
|
#define RAMDISK_LOAD_FLAG 0x4000
|
|
|
static char command_line[COMMAND_LINE_SIZE] = { 0, };
|
static char command_line[COMMAND_LINE_SIZE] = { 0, };
|
char saved_command_line[COMMAND_LINE_SIZE];
|
char saved_command_line[COMMAND_LINE_SIZE];
|
|
|
void setup_arch(char **cmdline_p,
|
void setup_arch(char **cmdline_p,
|
unsigned long * memory_start_p, unsigned long * memory_end_p)
|
unsigned long * memory_start_p, unsigned long * memory_end_p)
|
{
|
{
|
unsigned long memory_start, memory_end;
|
unsigned long memory_start, memory_end;
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
unsigned long memory_alt_end;
|
unsigned long memory_alt_end;
|
#endif
|
#endif
|
char c = ' ', *to = command_line, *from = COMMAND_LINE;
|
char c = ' ', *to = command_line, *from = COMMAND_LINE;
|
int len = 0;
|
int len = 0;
|
static unsigned char smptrap=0;
|
static unsigned char smptrap=0;
|
|
|
if(smptrap==1)
|
if(smptrap==1)
|
{
|
{
|
return;
|
return;
|
}
|
}
|
smptrap=1;
|
smptrap=1;
|
|
|
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
|
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
|
drive_info = DRIVE_INFO;
|
drive_info = DRIVE_INFO;
|
screen_info = SCREEN_INFO;
|
screen_info = SCREEN_INFO;
|
#ifdef CONFIG_APM
|
#ifdef CONFIG_APM
|
apm_bios_info = APM_BIOS_INFO;
|
apm_bios_info = APM_BIOS_INFO;
|
#endif
|
#endif
|
aux_device_present = AUX_DEVICE_INFO;
|
aux_device_present = AUX_DEVICE_INFO;
|
memory_end = (1<<20) + (EXT_MEM_K<<10);
|
memory_end = (1<<20) + (EXT_MEM_K<<10);
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
|
memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
|
if (memory_alt_end > memory_end) {
|
if (memory_alt_end > memory_end) {
|
printk("Memory: sized by int13 0e801h\n");
|
printk("Memory: sized by int13 0e801h\n");
|
memory_end = memory_alt_end;
|
memory_end = memory_alt_end;
|
}
|
}
|
else
|
else
|
printk("Memory: sized by int13 088h\n");
|
printk("Memory: sized by int13 088h\n");
|
#endif
|
#endif
|
memory_end &= PAGE_MASK;
|
memory_end &= PAGE_MASK;
|
#ifdef CONFIG_BLK_DEV_RAM
|
#ifdef CONFIG_BLK_DEV_RAM
|
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
|
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
|
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
|
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
|
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
|
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
|
#endif
|
#endif
|
#ifdef CONFIG_MAX_16M
|
#ifdef CONFIG_MAX_16M
|
if (memory_end > 16*1024*1024)
|
if (memory_end > 16*1024*1024)
|
memory_end = 16*1024*1024;
|
memory_end = 16*1024*1024;
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* The CONFIG_MAX_MEMSIZE sanity checker.
|
* The CONFIG_MAX_MEMSIZE sanity checker.
|
*/
|
*/
|
|
|
if (memory_end > (CONFIG_MAX_MEMSIZE-128)*1024*1024)
|
if (memory_end > (CONFIG_MAX_MEMSIZE-128)*1024*1024)
|
{
|
{
|
memory_end = (CONFIG_MAX_MEMSIZE-128)*1024*1024;
|
memory_end = (CONFIG_MAX_MEMSIZE-128)*1024*1024;
|
printk(KERN_WARNING "ONLY %dMB RAM will be used, see Documentation/more-than-900MB-RAM.txt!.\n", CONFIG_MAX_MEMSIZE-128);
|
printk(KERN_WARNING "ONLY %dMB RAM will be used, see Documentation/more-than-900MB-RAM.txt!.\n", CONFIG_MAX_MEMSIZE-128);
|
udelay(3*1000*1000);
|
udelay(3*1000*1000);
|
}
|
}
|
|
|
if (!MOUNT_ROOT_RDONLY)
|
if (!MOUNT_ROOT_RDONLY)
|
root_mountflags &= ~MS_RDONLY;
|
root_mountflags &= ~MS_RDONLY;
|
memory_start = (unsigned long) &_end;
|
memory_start = (unsigned long) &_end;
|
init_task.mm->start_code = TASK_SIZE;
|
init_task.mm->start_code = TASK_SIZE;
|
init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
|
init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
|
init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
|
init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
|
init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
|
init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
|
|
|
/* Save unparsed command line copy for /proc/cmdline */
|
/* Save unparsed command line copy for /proc/cmdline */
|
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
|
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
|
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
|
|
for (;;) {
|
for (;;) {
|
/*
|
/*
|
* "mem=nopentium" disables the 4MB page tables.
|
* "mem=nopentium" disables the 4MB page tables.
|
* "mem=XXX[kKmM]" overrides the BIOS-reported
|
* "mem=XXX[kKmM]" overrides the BIOS-reported
|
* memory size
|
* memory size
|
*/
|
*/
|
if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
|
if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
|
if (to != command_line) to--;
|
if (to != command_line) to--;
|
if (!memcmp(from+4, "nopentium", 9)) {
|
if (!memcmp(from+4, "nopentium", 9)) {
|
from += 9+4;
|
from += 9+4;
|
x86_capability &= ~8;
|
x86_capability &= ~8;
|
} else {
|
} else {
|
memory_end = simple_strtoul(from+4, &from, 0);
|
memory_end = simple_strtoul(from+4, &from, 0);
|
if ( *from == 'K' || *from == 'k' ) {
|
if ( *from == 'K' || *from == 'k' ) {
|
memory_end = memory_end << 10;
|
memory_end = memory_end << 10;
|
from++;
|
from++;
|
} else if ( *from == 'M' || *from == 'm' ) {
|
} else if ( *from == 'M' || *from == 'm' ) {
|
memory_end = memory_end << 20;
|
memory_end = memory_end << 20;
|
from++;
|
from++;
|
}
|
}
|
}
|
}
|
}
|
}
|
c = *(from++);
|
c = *(from++);
|
if (!c)
|
if (!c)
|
break;
|
break;
|
if (COMMAND_LINE_SIZE <= ++len)
|
if (COMMAND_LINE_SIZE <= ++len)
|
break;
|
break;
|
*(to++) = c;
|
*(to++) = c;
|
}
|
}
|
*to = '\0';
|
*to = '\0';
|
*cmdline_p = command_line;
|
*cmdline_p = command_line;
|
*memory_start_p = memory_start;
|
*memory_start_p = memory_start;
|
*memory_end_p = memory_end;
|
*memory_end_p = memory_end;
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
#ifdef CONFIG_BLK_DEV_INITRD
|
if (LOADER_TYPE) {
|
if (LOADER_TYPE) {
|
initrd_start = INITRD_START;
|
initrd_start = INITRD_START;
|
initrd_end = INITRD_START+INITRD_SIZE;
|
initrd_end = INITRD_START+INITRD_SIZE;
|
if (initrd_end > memory_end) {
|
if (initrd_end > memory_end) {
|
printk("initrd extends beyond end of memory "
|
printk("initrd extends beyond end of memory "
|
"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
|
"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
|
initrd_end,memory_end);
|
initrd_end,memory_end);
|
initrd_start = 0;
|
initrd_start = 0;
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
|
|
/* request io space for devices used on all i[345]86 PC'S */
|
/* request io space for devices used on all i[345]86 PC'S */
|
request_region(0x00,0x20,"dma1");
|
request_region(0x00,0x20,"dma1");
|
request_region(0x40,0x20,"timer");
|
request_region(0x40,0x20,"timer");
|
request_region(0x80,0x20,"dma page reg");
|
request_region(0x80,0x20,"dma page reg");
|
request_region(0xc0,0x20,"dma2");
|
request_region(0xc0,0x20,"dma2");
|
request_region(0xf0,0x10,"npu");
|
request_region(0xf0,0x10,"npu");
|
}
|
}
|
|
|
static const char * IDTmodel(void)
|
static const char * IDTmodel(void)
|
/* Right now IDT has a single CPU model in production: the C6.
|
/* Right now IDT has a single CPU model in production: the C6.
|
* Adjust this when IDT/Centaur comes out with a new CPU model.
|
* Adjust this when IDT/Centaur comes out with a new CPU model.
|
* Stepping information is correctly reported in x86_mask.
|
* Stepping information is correctly reported in x86_mask.
|
*/
|
*/
|
{
|
{
|
static const char *model[] = {
|
static const char *model[] = {
|
"C6", "C6-3D"
|
"C6", "C6-3D"
|
};
|
};
|
return model[0];
|
return model[0];
|
}
|
}
|
|
|
static const char * Cx86model(void)
|
static const char * Cx86model(void)
|
/* We know our CPU is a Cyrix now (see bugs.h), so we can use the DIR0/DIR1
|
/* We know our CPU is a Cyrix now (see bugs.h), so we can use the DIR0/DIR1
|
* mechanism to figure out the model, bus clock multiplier and stepping.
|
* mechanism to figure out the model, bus clock multiplier and stepping.
|
* For the newest CPUs (GXm and MXi) we use the Extended CPUID function.
|
* For the newest CPUs (GXm and MXi) we use the Extended CPUID function.
|
*/
|
*/
|
{
|
{
|
unsigned char nr6x86 = 0;
|
unsigned char nr6x86 = 0;
|
unsigned char cx_dir0 = 0; /* Model and bus clock multiplier */
|
unsigned char cx_dir0 = 0; /* Model and bus clock multiplier */
|
unsigned char cx_dir1 = 0; /* Stepping info */
|
unsigned char cx_dir1 = 0; /* Stepping info */
|
unsigned int flags;
|
unsigned int flags;
|
static const char *model[] = {
|
static const char *model[] = {
|
"unknown", "Cx486", "5x86", "MediaGX", "6x86", "6x86L", "6x86MX",
|
"unknown", "Cx486", "5x86", "MediaGX", "6x86", "6x86L", "6x86MX",
|
"M II"
|
"M II"
|
};
|
};
|
|
|
if (x86_model == -1) { /* is this an old Cx486 without DIR0/DIR1? */
|
if (x86_model == -1) { /* is this an old Cx486 without DIR0/DIR1? */
|
nr6x86 = 1; /* Cx486 */
|
nr6x86 = 1; /* Cx486 */
|
Cx86_mult = 0; /* unknown multiplier */
|
Cx86_mult = 0; /* unknown multiplier */
|
}
|
}
|
else {
|
else {
|
|
|
/* Get DIR0, DIR1 since all other Cyrix CPUs have them */
|
/* Get DIR0, DIR1 since all other Cyrix CPUs have them */
|
|
|
save_flags(flags);
|
save_flags(flags);
|
cli();
|
cli();
|
cx_dir0 = getCx86(CX86_DIR0); /* we use the access macros */
|
cx_dir0 = getCx86(CX86_DIR0); /* we use the access macros */
|
cx_dir1 = getCx86(CX86_DIR1); /* defined in processor.h */
|
cx_dir1 = getCx86(CX86_DIR1); /* defined in processor.h */
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
/* Now cook; the recipe is by Channing Corn, from Cyrix.
|
/* Now cook; the recipe is by Channing Corn, from Cyrix.
|
* We do the same thing for each generation: we work out
|
* We do the same thing for each generation: we work out
|
* the model, multiplier and stepping.
|
* the model, multiplier and stepping.
|
*/
|
*/
|
|
|
if (cx_dir0 < 0x20) {
|
if (cx_dir0 < 0x20) {
|
nr6x86 = 1; /* Cx486 */
|
nr6x86 = 1; /* Cx486 */
|
Cx86_mult = 0; /* unknown multiplier */
|
Cx86_mult = 0; /* unknown multiplier */
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
}
|
}
|
|
|
if ((cx_dir0 > 0x20) && (cx_dir0 < 0x30)) {
|
if ((cx_dir0 > 0x20) && (cx_dir0 < 0x30)) {
|
nr6x86 = 2; /* 5x86 */
|
nr6x86 = 2; /* 5x86 */
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
}
|
}
|
|
|
if ((cx_dir0 >= 0x30) && (cx_dir0 < 0x38)) {
|
if ((cx_dir0 >= 0x30) && (cx_dir0 < 0x38)) {
|
nr6x86 = ((x86_capability & (1 << 8)) ? 5 : 4); /* 6x86(L) */
|
nr6x86 = ((x86_capability & (1 << 8)) ? 5 : 4); /* 6x86(L) */
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 3), cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 3), cx_dir1 & 0x0f);
|
}
|
}
|
|
|
if ((cx_dir0 >= 0x40) && (cx_dir0 < 0x50)) {
|
if ((cx_dir0 >= 0x40) && (cx_dir0 < 0x50)) {
|
if (x86 == 4) { /* MediaGX */
|
if (x86 == 4) { /* MediaGX */
|
nr6x86 = 3;
|
nr6x86 = 3;
|
Cx86_mult = ((cx_dir0 & 0x01) ? 5 : 7); /* either 3x or 4x */
|
Cx86_mult = ((cx_dir0 & 0x01) ? 5 : 7); /* either 3x or 4x */
|
switch (cx_dir1 >> 4) {
|
switch (cx_dir1 >> 4) {
|
case (0) :
|
case (0) :
|
case (1) :
|
case (1) :
|
sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f);
|
break;
|
break;
|
case (2) :
|
case (2) :
|
sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f);
|
break;
|
break;
|
default :
|
default :
|
break;
|
break;
|
}
|
}
|
} /* endif MediaGX */
|
} /* endif MediaGX */
|
if (x86 == 5) { /* GXm */
|
if (x86 == 5) { /* GXm */
|
char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */
|
char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */
|
ext_cpuid = 0x80000005; /* available */
|
ext_cpuid = 0x80000005; /* available */
|
Cx86_mult = GXm_mult[cx_dir0 & 0x0f];
|
Cx86_mult = GXm_mult[cx_dir0 & 0x0f];
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f);
|
} /* endif GXm */
|
} /* endif GXm */
|
}
|
}
|
|
|
if ((cx_dir0 >= 0x50) && (cx_dir0 < 0x60)) {
|
if ((cx_dir0 >= 0x50) && (cx_dir0 < 0x60)) {
|
nr6x86 = ((cx_dir1 > 7) ? 7 : 6); /* 6x86Mx or M II */
|
nr6x86 = ((cx_dir1 > 7) ? 7 : 6); /* 6x86Mx or M II */
|
Cx86_mult = (cx_dir0 & 0x07) + 2; /* 2 to 5 in 0.5 steps */
|
Cx86_mult = (cx_dir0 & 0x07) + 2; /* 2 to 5 in 0.5 steps */
|
if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10;
|
if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10;
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
}
|
}
|
}
|
}
|
x86_mask = 1; /* we don't use it, but has to be set to something */
|
x86_mask = 1; /* we don't use it, but has to be set to something */
|
return model[nr6x86];
|
return model[nr6x86];
|
}
|
}
|
|
|
struct cpu_model_info {
|
struct cpu_model_info {
|
int cpu_x86;
|
int cpu_x86;
|
char *model_names[16];
|
char *model_names[16];
|
};
|
};
|
|
|
static struct cpu_model_info amd_models[] = {
|
static struct cpu_model_info amd_models[] = {
|
{ 4,
|
{ 4,
|
{ NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
|
{ NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
|
"DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
|
"DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
|
{ 5,
|
{ 5,
|
{ "K5/SSA5 (PR-75, PR-90, PR-100)"}},
|
{ "K5/SSA5 (PR-75, PR-90, PR-100)"}},
|
};
|
};
|
|
|
static const char * AMDmodel(void)
|
static const char * AMDmodel(void)
|
{
|
{
|
const char *p=NULL;
|
const char *p=NULL;
|
int i;
|
int i;
|
|
|
if ((x86_model == 0) || (x86 == 4)) {
|
if ((x86_model == 0) || (x86 == 4)) {
|
for (i=0; i<sizeof(amd_models)/sizeof(struct cpu_model_info); i++)
|
for (i=0; i<sizeof(amd_models)/sizeof(struct cpu_model_info); i++)
|
if (amd_models[i].cpu_x86 == x86) {
|
if (amd_models[i].cpu_x86 == x86) {
|
p = amd_models[i].model_names[(int)x86_model];
|
p = amd_models[i].model_names[(int)x86_model];
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else ext_cpuid = 0x80000005; /* available */
|
else ext_cpuid = 0x80000005; /* available */
|
return p;
|
return p;
|
}
|
}
|
|
|
static struct cpu_model_info intel_models[] = {
|
static struct cpu_model_info intel_models[] = {
|
{ 4,
|
{ 4,
|
{ "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL",
|
{ "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,
|
"486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL,
|
NULL, NULL, NULL, NULL, NULL }},
|
NULL, NULL, NULL, NULL, NULL }},
|
{ 5,
|
{ 5,
|
{ "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
|
{ "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
|
"OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
|
"OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
|
"Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
|
"Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL }},
|
NULL, NULL, NULL, NULL }},
|
{ 6,
|
{ 6,
|
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
|
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
|
NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL, NULL, NULL, NULL, NULL,
|
NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL, NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL }},
|
NULL, NULL, NULL, NULL }},
|
};
|
};
|
|
|
static const char * Intelmodel(void)
|
static const char * Intelmodel(void)
|
{
|
{
|
const char *p = "386 SX/DX"; /* default to a 386 */
|
const char *p = "386 SX/DX"; /* default to a 386 */
|
int i;
|
int i;
|
|
|
/*
|
/*
|
* Old 486SX has no CPU ID. Set the model to 2 for this
|
* Old 486SX has no CPU ID. Set the model to 2 for this
|
* case.
|
* case.
|
*/
|
*/
|
|
|
if( x86==4 && x86_model == 0 && hard_math == 0)
|
if( x86==4 && x86_model == 0 && hard_math == 0)
|
x86_model = 2;
|
x86_model = 2;
|
|
|
for (i=0; i<sizeof(intel_models)/sizeof(struct cpu_model_info); i++)
|
for (i=0; i<sizeof(intel_models)/sizeof(struct cpu_model_info); i++)
|
if (intel_models[i].cpu_x86 == x86) {
|
if (intel_models[i].cpu_x86 == x86) {
|
p = intel_models[i].model_names[(int)x86_model];
|
p = intel_models[i].model_names[(int)x86_model];
|
break;
|
break;
|
}
|
}
|
|
|
|
|
return p;
|
return p;
|
}
|
}
|
|
|
/* Recent Intel CPUs have an EEPROM and a ROM with CPU information. We'll use
|
/* Recent Intel CPUs have an EEPROM and a ROM with CPU information. We'll use
|
* this information in future versions of this code.
|
* this information in future versions of this code.
|
* AMD and more recently Cyrix have decided to standardize on an extended
|
* AMD and more recently Cyrix have decided to standardize on an extended
|
* cpuid mechanism for their CPUs.
|
* cpuid mechanism for their CPUs.
|
*/
|
*/
|
|
|
static const char * get_cpu_mkt_name(void)
|
static const char * get_cpu_mkt_name(void)
|
{
|
{
|
static char mktbuf[48];
|
static char mktbuf[48];
|
int dummy;
|
int dummy;
|
unsigned int *v;
|
unsigned int *v;
|
v = (unsigned int *) mktbuf;
|
v = (unsigned int *) mktbuf;
|
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); /* name, flags */
|
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); /* name, flags */
|
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
|
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
|
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
|
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
|
cpuid(0x80000001, &dummy, &dummy, &dummy, &x86_ext_capability);
|
cpuid(0x80000001, &dummy, &dummy, &dummy, &x86_ext_capability);
|
return mktbuf;
|
return mktbuf;
|
}
|
}
|
|
|
static const char * getmodel(void)
|
static const char * getmodel(void)
|
/* Default is Intel. We disregard Nexgen processors. */
|
/* Default is Intel. We disregard Nexgen processors. */
|
{
|
{
|
const char *p = NULL;
|
const char *p = NULL;
|
if (strcmp(x86_vendor_id, "AuthenticAMD") == 0) /* AuthenticAMD */
|
if (strcmp(x86_vendor_id, "AuthenticAMD") == 0) /* AuthenticAMD */
|
p = AMDmodel();
|
p = AMDmodel();
|
else if (strcmp(x86_vendor_id, "CyrixInstead") == 0) /* CyrixInstead */
|
else if (strcmp(x86_vendor_id, "CyrixInstead") == 0) /* CyrixInstead */
|
p = Cx86model();
|
p = Cx86model();
|
else if (strcmp(x86_vendor_id, "CentaurHauls") == 0) /* CentaurHauls */
|
else if (strcmp(x86_vendor_id, "CentaurHauls") == 0) /* CentaurHauls */
|
p = IDTmodel();
|
p = IDTmodel();
|
/* This isnt quite right */
|
/* This isnt quite right */
|
else if (strcmp(x86_vendor_id, "UMC UMC UMC ") == 0) /* UMC */
|
else if (strcmp(x86_vendor_id, "UMC UMC UMC ") == 0) /* UMC */
|
p = Intelmodel();
|
p = Intelmodel();
|
else /* default - this could be anyone */
|
else /* default - this could be anyone */
|
p = Intelmodel();
|
p = Intelmodel();
|
if (ext_cpuid)
|
if (ext_cpuid)
|
return get_cpu_mkt_name();
|
return get_cpu_mkt_name();
|
else
|
else
|
return p;
|
return p;
|
}
|
}
|
|
|
int get_cpuinfo(char * buffer)
|
int get_cpuinfo(char * buffer)
|
{
|
{
|
int i, len = 0;
|
int i, len = 0;
|
static const char *x86_cap_flags[] = {
|
static const char *x86_cap_flags[] = {
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
"cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
|
"cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
|
"16", "17", "18", "19", "20", "21", "22", "mmx",
|
"16", "17", "18", "19", "20", "21", "22", "mmx",
|
"24", "25", "26", "27", "28", "29", "30", "31"
|
"24", "25", "26", "27", "28", "29", "30", "31"
|
};
|
};
|
static const char *x86_ext_cap_flags[] = {
|
static const char *x86_ext_cap_flags[] = {
|
"fpu","vme", "de", "pse", "tsc", "msr", "6", "mce",
|
"fpu","vme", "de", "pse", "tsc", "msr", "6", "mce",
|
"cx8", "9", "10", "syscr", "12", "pge", "14", "cmov",
|
"cx8", "9", "10", "syscr", "12", "pge", "14", "cmov",
|
"fpcmov", "17", "psn", "19", "20", "21", "22", "mmx",
|
"fpcmov", "17", "psn", "19", "20", "21", "22", "mmx",
|
"emmx", "25", "26", "27", "28", "29", "30", "3dnow"
|
"emmx", "25", "26", "27", "28", "29", "30", "3dnow"
|
};
|
};
|
|
|
#ifdef __SMP__
|
#ifdef __SMP__
|
int n;
|
int n;
|
|
|
#define CD(X) (cpu_data[n].X)
|
#define CD(X) (cpu_data[n].X)
|
/* SMP has the wrong name for loops_per_sec */
|
/* SMP has the wrong name for loops_per_sec */
|
#define loops_per_sec udelay_val
|
#define loops_per_sec udelay_val
|
#define CPUN n
|
#define CPUN n
|
|
|
for ( n = 0 ; n < 32 ; n++ ) {
|
for ( n = 0 ; n < 32 ; n++ ) {
|
if ( cpu_present_map & (1<<n) ) {
|
if ( cpu_present_map & (1<<n) ) {
|
if (len) buffer[len++] = '\n';
|
if (len) buffer[len++] = '\n';
|
|
|
#else
|
#else
|
#define CD(X) (X)
|
#define CD(X) (X)
|
#define CPUN 0
|
#define CPUN 0
|
#endif
|
#endif
|
|
|
len += sprintf(buffer+len,"processor\t: %d\n"
|
len += sprintf(buffer+len,"processor\t: %d\n"
|
"cpu\t\t: %c86\n"
|
"cpu\t\t: %c86\n"
|
"model\t\t: %s",
|
"model\t\t: %s",
|
CPUN,
|
CPUN,
|
CD(x86)+'0',
|
CD(x86)+'0',
|
getmodel());
|
getmodel());
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"\nvendor_id\t: %s\n",
|
"\nvendor_id\t: %s\n",
|
x86_vendor_id);
|
x86_vendor_id);
|
|
|
if (CD(x86_mask) || have_cpuid)
|
if (CD(x86_mask) || have_cpuid)
|
if ((strncmp(x86_vendor_id, "Au", 2) == 0)
|
if ((strncmp(x86_vendor_id, "Au", 2) == 0)
|
&& (x86_model >= 6)) {
|
&& (x86_model >= 6)) {
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"stepping\t: %c\n",
|
"stepping\t: %c\n",
|
x86_mask + 'A');
|
x86_mask + 'A');
|
}
|
}
|
else if (strncmp(x86_vendor_id, "Cy", 2) == 0) {
|
else if (strncmp(x86_vendor_id, "Cy", 2) == 0) {
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"stepping\t: %s, core/bus clock ratio: %sx\n",
|
"stepping\t: %s, core/bus clock ratio: %sx\n",
|
Cx86_step, x86_clkmult[Cx86_mult]);
|
Cx86_step, x86_clkmult[Cx86_mult]);
|
}
|
}
|
else {
|
else {
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"stepping\t: %d\n",
|
"stepping\t: %d\n",
|
CD(x86_mask));
|
CD(x86_mask));
|
}
|
}
|
else
|
else
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"stepping\t: unknown\n");
|
"stepping\t: unknown\n");
|
|
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"fdiv_bug\t: %s\n"
|
"fdiv_bug\t: %s\n"
|
"hlt_bug\t\t: %s\n"
|
"hlt_bug\t\t: %s\n"
|
"f00f_bug\t: %s\n"
|
"f00f_bug\t: %s\n"
|
"fpu\t\t: %s\n"
|
"fpu\t\t: %s\n"
|
"fpu_exception\t: %s\n"
|
"fpu_exception\t: %s\n"
|
"cpuid\t\t: %s\n"
|
"cpuid\t\t: %s\n"
|
"wp\t\t: %s\n"
|
"wp\t\t: %s\n"
|
"flags\t\t:",
|
"flags\t\t:",
|
CD(fdiv_bug) ? "yes" : "no",
|
CD(fdiv_bug) ? "yes" : "no",
|
CD(hlt_works_ok) ? "no" : "yes",
|
CD(hlt_works_ok) ? "no" : "yes",
|
pentium_f00f_bug ? "yes" : "no",
|
pentium_f00f_bug ? "yes" : "no",
|
CD(hard_math) ? "yes" : "no",
|
CD(hard_math) ? "yes" : "no",
|
(CD(hard_math) && ignore_irq13)
|
(CD(hard_math) && ignore_irq13)
|
? "yes" : "no",
|
? "yes" : "no",
|
CD(have_cpuid) ? "yes" : "no",
|
CD(have_cpuid) ? "yes" : "no",
|
CD(wp_works_ok) ? "yes" : "no");
|
CD(wp_works_ok) ? "yes" : "no");
|
|
|
for ( i = 0 ; i < 32 ; i++ ) {
|
for ( i = 0 ; i < 32 ; i++ ) {
|
if ( CD(x86_capability) & (1 << i) ) {
|
if ( CD(x86_capability) & (1 << i) ) {
|
len += sprintf(buffer+len, " %s",
|
len += sprintf(buffer+len, " %s",
|
x86_cap_flags[i]);
|
x86_cap_flags[i]);
|
}
|
}
|
else if ( CD(x86_ext_capability) & (1 << i) ) {
|
else if ( CD(x86_ext_capability) & (1 << i) ) {
|
len += sprintf(buffer+len, " %s",
|
len += sprintf(buffer+len, " %s",
|
x86_ext_cap_flags[i]);
|
x86_ext_cap_flags[i]);
|
}
|
}
|
}
|
}
|
len += sprintf(buffer+len,
|
len += sprintf(buffer+len,
|
"\nbogomips\t: %lu.%02lu\n",
|
"\nbogomips\t: %lu.%02lu\n",
|
CD(loops_per_sec+2500)/500000,
|
CD(loops_per_sec+2500)/500000,
|
(CD(loops_per_sec+2500)/5000) % 100);
|
(CD(loops_per_sec+2500)/5000) % 100);
|
#ifdef __SMP__
|
#ifdef __SMP__
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
return len;
|
return len;
|
}
|
}
|
|
|