📄 setup.c
字号:
/* * linux/arch/i386/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds * * Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean * and Martin Mares, November 1997. * * Force Cyrix 6x86(MX) and M II processors to report MTRR capability * and Cyrix "coma bug" recognition by * Zolt醤 B鰏z鰎m閚yi <zboszor@mail.externet.hu> February 1999. * * Force Centaur C6 processors to report MTRR capability. * Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999. * * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999. * * IDT Winchip tweaks, misc clean ups. * Dave Jones <davej@suse.de>, August 1999 * * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * * Better detection of Centaur/IDT WinChip models. * Bart Hartgers <bart@etpmod.phys.tue.nl>, August 1999. * * Memory region support * David Parsons <orc@pell.chi.il.us>, July-August 1999 * * Cleaned up cache-detection code * Dave Jones <davej@suse.de>, October 1999 * * Added proper L2 cache detection for Coppermine * Dragan Stancevic <visitor@valinux.com>, October 1999 * * Added the original array for capability flags but forgot to credit * myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff * Jauder Ho <jauderho@carumba.com>, January 2000 * * Detection for Celeron coppermine, identify_cpu() overhauled, * and a few other clean ups. * Dave Jones <davej@suse.de>, April 2000 * * Pentium III FXSR, SSE support * General FPU state handling cleanups * Gareth Hughes <gareth@valinux.com>, May 2000 * * Added proper Cascades CPU and L2 cache detection for Cascades * and 8-way type cache happy bunch from Intel:^) * Dragan Stancevic <visitor@valinux.com>, May 2000 * * Forward port AMD Duron errata T13 from 2.2.17pre * Dave Jones <davej@suse.de>, August 2000 * * Forward port lots of fixes/improvements from 2.2.18pre * Cyrix III, Pentium IV support. * Dave Jones <davej@suse.de>, October 2000 * * Massive cleanup of CPU detection and bug handling; * Transmeta CPU detection, * H. Peter Anvin <hpa@zytor.com>, November 2000 *//* * This file handles the architecture-dependent parts of initialization */#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/user.h>#include <linux/a.out.h>#include <linux/tty.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/config.h>#include <linux/init.h>#include <linux/apm_bios.h>#ifdef CONFIG_BLK_DEV_RAM#include <linux/blk.h>#endif#include <linux/highmem.h>#include <linux/bootmem.h>#include <asm/processor.h>#include <linux/console.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/cobalt.h>#include <asm/msr.h>#include <asm/desc.h>#include <asm/e820.h>#include <asm/dma.h>#include <asm/mpspec.h>#include <asm/mmu_context.h>/* * Machine setup.. */char ignore_irq13; /* set if exception 16 works */struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };unsigned long mmu_cr4_features;/* * Bus types .. */#ifdef CONFIG_EISAint EISA_bus;#endifint MCA_bus;/* for MCA, but anyone else can use it if they want */unsigned int machine_id;unsigned int machine_submodel_id;unsigned int BIOS_revision;unsigned int mca_pentium_flag;/* * Setup options */struct drive_info_struct { char dummy[32]; } drive_info;struct screen_info screen_info;struct apm_info apm_info;struct sys_desc_table_struct { unsigned short length; unsigned char table[0];};struct e820map e820;unsigned char aux_device_present;#ifdef CONFIG_BLK_DEV_RAMextern 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_image_start; /* starting block # of image */#endifextern int root_mountflags;extern char _text, _etext, _edata, _end;extern unsigned long cpu_khz;static int disable_x86_serial_nr __initdata = 1;/* * This is set up by the setup-routine at boot-time */#define PARAM ((unsigned char *)empty_zero_page)#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))#define EXT_MEM_K (*(unsigned short *) (PARAM+2))#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))#define E820_MAP_NR (*(char*) (PARAM+E820NR))#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))#define KERNEL_START (*(unsigned long *) (PARAM+0x214))#define INITRD_START (*(unsigned long *) (PARAM+0x218))#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))#define COMMAND_LINE ((char *) (PARAM+2048))#define COMMAND_LINE_SIZE 256#define RAMDISK_IMAGE_START_MASK 0x07FF#define RAMDISK_PROMPT_FLAG 0x8000#define RAMDISK_LOAD_FLAG 0x4000 #ifdef CONFIG_VISWSchar visws_board_type = -1;char visws_board_rev = -1;#define PIIX_PM_START 0x0F80#define SIO_GPIO_START 0x0FC0#define SIO_PM_START 0x0FC8#define PMBASE PIIX_PM_START#define GPIREG0 (PMBASE+0x30)#define GPIREG(x) (GPIREG0+((x)/8))#define PIIX_GPI_BD_ID1 18#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1)#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8)#define SIO_INDEX 0x2e#define SIO_DATA 0x2f#define SIO_DEV_SEL 0x7#define SIO_DEV_ENB 0x30#define SIO_DEV_MSB 0x60#define SIO_DEV_LSB 0x61#define SIO_GP_DEV 0x7#define SIO_GP_BASE SIO_GPIO_START#define SIO_GP_MSB (SIO_GP_BASE>>8)#define SIO_GP_LSB (SIO_GP_BASE&0xff)#define SIO_GP_DATA1 (SIO_GP_BASE+0)#define SIO_PM_DEV 0x8#define SIO_PM_BASE SIO_PM_START#define SIO_PM_MSB (SIO_PM_BASE>>8)#define SIO_PM_LSB (SIO_PM_BASE&0xff)#define SIO_PM_INDEX (SIO_PM_BASE+0)#define SIO_PM_DATA (SIO_PM_BASE+1)#define SIO_PM_FER2 0x1#define SIO_PM_GP_EN 0x80static voidvisws_get_board_type_and_rev(void){ int raw; visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) >> PIIX_GPI_BD_SHIFT;/* * Get Board rev. * First, we have to initialize the 307 part to allow us access * to the GPIO registers. Let's map them at 0x0fc0 which is right * after the PIIX4 PM section. */ outb_p(SIO_DEV_SEL, SIO_INDEX); outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ outb_p(SIO_DEV_MSB, SIO_INDEX); outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ outb_p(SIO_DEV_LSB, SIO_INDEX); outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ outb_p(SIO_DEV_ENB, SIO_INDEX); outb_p(1, SIO_DATA); /* Enable GPIO registers. */ /* * Now, we have to map the power management section to write * a bit which enables access to the GPIO registers. * What lunatic came up with this shit? */ outb_p(SIO_DEV_SEL, SIO_INDEX); outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ outb_p(SIO_DEV_MSB, SIO_INDEX); outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ outb_p(SIO_DEV_LSB, SIO_INDEX); outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ outb_p(SIO_DEV_ENB, SIO_INDEX); outb_p(1, SIO_DATA); /* Enable PM registers. */ /* * Now, write the PM register which enables the GPIO registers. */ outb_p(SIO_PM_FER2, SIO_PM_INDEX); outb_p(SIO_PM_GP_EN, SIO_PM_DATA); /* * Now, initialize the GPIO registers. * We want them all to be inputs which is the * power on default, so let's leave them alone. * So, let's just read the board rev! */ raw = inb_p(SIO_GP_DATA1); raw &= 0x7f; /* 7 bits of valid board revision ID. */ if (visws_board_type == VISWS_320) { if (raw < 0x6) { visws_board_rev = 4; } else if (raw < 0xc) { visws_board_rev = 5; } else { visws_board_rev = 6; } } else if (visws_board_type == VISWS_540) { visws_board_rev = 2; } else { visws_board_rev = raw; } printk("Silicon Graphics %s (rev %d)\n", visws_board_type == VISWS_320 ? "320" : (visws_board_type == VISWS_540 ? "540" : "unknown"), visws_board_rev); }#endifstatic char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE];struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY }, { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, { "fpu", 0xf0, 0xff, IORESOURCE_BUSY }};#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))static struct resource code_resource = { "Kernel code", 0x100000, 0 };static struct resource data_resource = { "Kernel data", 0, 0 };static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };/* System ROM resources */#define MAXROMS 6static struct resource rom_resources[MAXROMS] = { { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY }, { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }};#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)static void __init probe_roms(void){ int roms = 1; unsigned long base; unsigned char *romstart; request_resource(&iomem_resource, rom_resources+0); /* Video ROM is standard at C000:0000 - C7FF:0000, check signature */ for (base = 0xC0000; base < 0xE0000; base += 2048) { romstart = bus_to_virt(base); if (!romsignature(romstart)) continue; request_resource(&iomem_resource, rom_resources + roms); roms++; break; } /* Extension roms at C800:0000 - DFFF:0000 */ for (base = 0xC8000; base < 0xE0000; base += 2048) { unsigned long length; romstart = bus_to_virt(base); if (!romsignature(romstart)) continue; length = romstart[2] * 512; if (length) { unsigned int i; unsigned char chksum; chksum = 0; for (i = 0; i < length; i++) chksum += romstart[i]; /* Good checksum? */ if (!chksum) { rom_resources[roms].start = base; rom_resources[roms].end = base + length - 1; rom_resources[roms].name = "Extension ROM"; rom_resources[roms].flags = IORESOURCE_BUSY; request_resource(&iomem_resource, rom_resources + roms); roms++; if (roms >= MAXROMS) return; } } } /* Final check for motherboard extension rom at E000:0000 */ base = 0xE0000; romstart = bus_to_virt(base); if (romsignature(romstart)) { rom_resources[roms].start = base; rom_resources[roms].end = base + 65535; rom_resources[roms].name = "Extension ROM"; rom_resources[roms].flags = IORESOURCE_BUSY; request_resource(&iomem_resource, rom_resources + roms); }}void __init add_memory_region(unsigned long long start, unsigned long long size, int type){ int x = e820.nr_map; if (x == E820MAX) { printk("Ooops! Too many entries in the memory map!\n"); return; } e820.map[x].addr = start; e820.map[x].size = size; e820.map[x].type = type; e820.nr_map++;} /* add_memory_region */#define E820_DEBUG 1static void __init print_memory_map(char *who){ int i; for (i = 0; i < e820.nr_map; i++) { printk(" %s: %016Lx @ %016Lx ", who, e820.map[i].size, e820.map[i].addr); switch (e820.map[i].type) { case E820_RAM: printk("(usable)\n"); break; case E820_RESERVED: printk("(reserved)\n"); break; case E820_ACPI: printk("(ACPI data)\n"); break; case E820_NVS: printk("(ACPI NVS)\n"); break; default: printk("type %lu\n", e820.map[i].type); break; } }}/* * Copy the BIOS e820 map into a safe place. * * Sanity-check it while we're at it.. * * If we're lucky and live on a modern system, the setup code * will have given us a memory map that we can use to properly * set up memory. If we aren't, we'll fake a memory map. * * We check to see that the memory map contains at least 2 elements * before we'll use it, because the detection code in setup.S may * not be perfect and most every PC known to man has two memory * regions: one from 0 to 640k, and one from 1mb up. (The IBM * thinkpad 560x, for example, does not cooperate with the memory * detection code.) */static int __init copy_e820_map(struct e820entry * biosmap, int nr_map){ /* Only one memory region (or negative)? Ignore it */ if (nr_map < 2) return -1; do { unsigned long long start = biosmap->addr; unsigned long long size = biosmap->size; unsigned long long end = start + size; unsigned long type = biosmap->type; /* Overflow in 64 bits? Ignore the memory map. */ if (start > end) return -1; /* * Some BIOSes claim RAM in the 640k - 1M region. * Not right. Fix it up. */ if (type == E820_RAM) { if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) add_memory_region(start, 0xA0000ULL-start, type); if (end <= 0x100000ULL) continue; start = 0x100000ULL; size = end - start; } } add_memory_region(start, size, type); } while (biosmap++,--nr_map); return 0;}/* * Do NOT EVER look at the BIOS memory size location. * It does not work on many machines. */#define LOWMEMSIZE() (0x9f000)void __init setup_memory_region(void){ char *who = "BIOS-e820"; /* * Try to copy the BIOS-supplied E820-map. * * Otherwise fake a memory map; one section from 0k->640k, * the next section from 1mb->appropriate_mem_k */ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { unsigned long mem_size; /* compare results from other methods and take the greater */ if (ALT_MEM_K < EXT_MEM_K) { mem_size = EXT_MEM_K; who = "BIOS-88"; } else { mem_size = ALT_MEM_K; who = "BIOS-e801"; } e820.nr_map = 0; add_memory_region(0, LOWMEMSIZE(), E820_RAM); add_memory_region(HIGH_MEMORY, (mem_size << 10) - HIGH_MEMORY, E820_RAM); } printk("BIOS-provided physical RAM map:\n"); print_memory_map(who);} /* setup_memory_region */static inline void parse_mem_cmdline (char ** cmdline_p){ char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; int usermem = 0; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; for (;;) { /* * "mem=nopentium" disables the 4MB page tables. * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM * to <mem>, overriding the bios size. * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from * <start> to <start>+<mem>, overriding the bios size. */ if (c == ' ' && !memcmp(from, "mem=", 4)) { if (to != command_line) to--; if (!memcmp(from+4, "nopentium", 9)) { from += 9+4; clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability); } else if (!memcmp(from+4, "exactmap", 8)) { from += 8+4; e820.nr_map = 0; usermem = 1; } else { /* If the user specifies memory size, we * blow away any automatically generated * size */ unsigned long start_at, mem_size; if (usermem == 0) { /* first time in: zap the whitelist * and reinitialize it with the * standard low-memory region. */ e820.nr_map = 0; usermem = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -