📄 setup.c
字号:
/* * linux/arch/i386/kernel/setup.c * * Copyright (C) 1995 Linus Torvalds * * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * * Memory region support * David Parsons <orc@pell.chi.il.us>, July-August 1999 * * Added E820 sanitization routine (removes overlapping memory regions); * Brian Moyle <bmoyle@mvista.com>, February 2001 * * Moved CPU detection code to cpu/${cpu}.c * Patrick Mochel <mochel@osdl.org>, March 2002 * * Provisions for empty E820 memory regions (reported by certain BIOSes). * Alex Achenbach <xela@slit.de>, December 2002. * *//* * This file handles the architecture-dependent parts of initialization */#include <linux/config.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/mmzone.h>#include <linux/tty.h>#include <linux/ioport.h>#include <linux/acpi.h>#include <linux/apm_bios.h>#include <linux/initrd.h>#include <linux/bootmem.h>#include <linux/seq_file.h>#include <linux/console.h>#include <linux/mca.h>#include <linux/root_dev.h>#include <linux/highmem.h>#include <linux/module.h>#include <linux/efi.h>#include <linux/init.h>#include <linux/edd.h>#include <linux/nodemask.h>#include <linux/kexec.h>#include <linux/crash_dump.h>#include <video/edid.h>#include <asm/apic.h>#include <asm/e820.h>#include <asm/mpspec.h>#include <asm/setup.h>#include <asm/arch_hooks.h>#include <asm/sections.h>#include <asm/io_apic.h>#include <asm/ist.h>#include <asm/io.h>#include "setup_arch_pre.h"#include <bios_ebda.h>/* Forward Declaration. */void __init find_max_pfn(void);/* This value is set up by the early boot code to point to the value immediately after the boot time page tables. It contains a *physical* address, and must not be in the .bss segment! */unsigned long init_pg_tables_end __initdata = ~0UL;int disable_pse __devinitdata = 0;/* * Machine setup.. */#ifdef CONFIG_EFIint efi_enabled = 0;EXPORT_SYMBOL(efi_enabled);#endif/* cpu data as detected by the assembly code in head.S */struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };/* common cpu data for all cpus */struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };EXPORT_SYMBOL(boot_cpu_data);unsigned long mmu_cr4_features;#ifdef CONFIG_ACPI int acpi_disabled = 0;#else int acpi_disabled = 1;#endifEXPORT_SYMBOL(acpi_disabled);#ifdef CONFIG_ACPIint __initdata acpi_force = 0;extern acpi_interrupt_flags acpi_sci_flags;#endif/* for MCA, but anyone else can use it if they want */unsigned int machine_id;#ifdef CONFIG_MCAEXPORT_SYMBOL(machine_id);#endifunsigned int machine_submodel_id;unsigned int BIOS_revision;unsigned int mca_pentium_flag;/* For PCI or other memory-mapped resources */unsigned long pci_mem_start = 0x10000000;#ifdef CONFIG_PCIEXPORT_SYMBOL(pci_mem_start);#endif/* Boot loader ID as an integer, for the benefit of proc_dointvec */int bootloader_type;/* user-defined highmem size */static unsigned int highmem_pages = -1;/* * Setup options */struct drive_info_struct { char dummy[32]; } drive_info;#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)EXPORT_SYMBOL(drive_info);#endifstruct screen_info screen_info;EXPORT_SYMBOL(screen_info);struct apm_info apm_info;EXPORT_SYMBOL(apm_info);struct sys_desc_table_struct { unsigned short length; unsigned char table[0];};struct edid_info edid_info;EXPORT_SYMBOL_GPL(edid_info);struct ist_info ist_info;#if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)EXPORT_SYMBOL(ist_info);#endifstruct e820map e820;extern void early_cpu_init(void);extern void dmi_scan_machine(void);extern void generic_apic_probe(char *);extern int root_mountflags;unsigned long saved_videomode;#define RAMDISK_IMAGE_START_MASK 0x07FF#define RAMDISK_PROMPT_FLAG 0x8000#define RAMDISK_LOAD_FLAG 0x4000 static char command_line[COMMAND_LINE_SIZE];unsigned char __initdata boot_params[PARAM_SIZE];static struct resource data_resource = { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};static struct resource code_resource = { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};static struct resource system_rom_resource = { .name = "System ROM", .start = 0xf0000, .end = 0xfffff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource extension_rom_resource = { .name = "Extension ROM", .start = 0xe0000, .end = 0xeffff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource adapter_rom_resources[] = { { .name = "Adapter ROM", .start = 0xc8000, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM}, { .name = "Adapter ROM", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM} };#define ADAPTER_ROM_RESOURCES \ (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])static struct resource video_rom_resource = { .name = "Video ROM", .start = 0xc0000, .end = 0xc7fff, .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM};static struct resource video_ram_resource = { .name = "Video RAM area", .start = 0xa0000, .end = 0xbffff, .flags = IORESOURCE_BUSY | IORESOURCE_MEM};static struct resource standard_io_resources[] = { { .name = "dma1", .start = 0x0000, .end = 0x001f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "pic1", .start = 0x0020, .end = 0x0021, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "timer0", .start = 0x0040, .end = 0x0043, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "timer1", .start = 0x0050, .end = 0x0053, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "keyboard", .start = 0x0060, .end = 0x006f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "dma page reg", .start = 0x0080, .end = 0x008f, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "pic2", .start = 0x00a0, .end = 0x00a1, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "dma2", .start = 0x00c0, .end = 0x00df, .flags = IORESOURCE_BUSY | IORESOURCE_IO}, { .name = "fpu", .start = 0x00f0, .end = 0x00ff, .flags = IORESOURCE_BUSY | IORESOURCE_IO} };#define STANDARD_IO_RESOURCES \ (sizeof standard_io_resources / sizeof standard_io_resources[0])#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)static int __init romchecksum(unsigned char *rom, unsigned long length){ unsigned char *p, sum = 0; for (p = rom; p < rom + length; p++) sum += *p; return sum == 0;}static void __init probe_roms(void){ unsigned long start, length, upper; unsigned char *rom; int i; /* video rom */ upper = adapter_rom_resources[0].start; for (start = video_rom_resource.start; start < upper; start += 2048) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; video_rom_resource.start = start; /* 0 < length <= 0x7f * 512, historically */ length = rom[2] * 512; /* if checksum okay, trust length byte */ if (length && romchecksum(rom, length)) video_rom_resource.end = start + length - 1; request_resource(&iomem_resource, &video_rom_resource); break; } start = (video_rom_resource.end + 1 + 2047) & ~2047UL; if (start < upper) start = upper; /* system rom */ request_resource(&iomem_resource, &system_rom_resource); upper = system_rom_resource.start; /* check for extension rom (ignore length byte!) */ rom = isa_bus_to_virt(extension_rom_resource.start); if (romsignature(rom)) { length = extension_rom_resource.end - extension_rom_resource.start + 1; if (romchecksum(rom, length)) { request_resource(&iomem_resource, &extension_rom_resource); upper = extension_rom_resource.start; } } /* check for adapter roms on 2k boundaries */ for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) { rom = isa_bus_to_virt(start); if (!romsignature(rom)) continue; /* 0 < length <= 0x7f * 512, historically */ length = rom[2] * 512; /* but accept any length that fits if checksum okay */ if (!length || start + length > upper || !romchecksum(rom, length)) continue; adapter_rom_resources[i].start = start; adapter_rom_resources[i].end = start + length - 1; request_resource(&iomem_resource, &adapter_rom_resources[i]); start = adapter_rom_resources[i++].end & ~2047UL; }}static void __init limit_regions(unsigned long long size){ unsigned long long current_addr = 0; int i; if (efi_enabled) { efi_memory_desc_t *md; void *p; for (p = memmap.map, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) { md = p; current_addr = md->phys_addr + (md->num_pages << 12); if (md->type == EFI_CONVENTIONAL_MEMORY) { if (current_addr >= size) { md->num_pages -= (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); memmap.nr_map = i + 1; return; } } } } for (i = 0; i < e820.nr_map; i++) { current_addr = e820.map[i].addr + e820.map[i].size; if (current_addr < size) continue; if (e820.map[i].type != E820_RAM) continue; if (e820.map[i].addr >= size) { /* * This region starts past the end of the * requested size, skip it completely. */ e820.nr_map = i; } else { e820.nr_map = i + 1; e820.map[i].size -= current_addr - size; } return; }}static void __init add_memory_region(unsigned long long start, unsigned long long size, int type){ int x; if (!efi_enabled) { x = e820.nr_map; if (x == E820MAX) { printk(KERN_ERR "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].addr, e820.map[i].addr + e820.map[i].size); 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; } }}/* * Sanitize the BIOS e820 map. * * Some e820 responses include overlapping entries. The following * replaces the original e820 map with a new one, removing overlaps. * */struct change_member { struct e820entry *pbios; /* pointer to original bios entry */ unsigned long long addr; /* address for this change point */};static struct change_member change_point_list[2*E820MAX] __initdata;static struct change_member *change_point[2*E820MAX] __initdata;static struct e820entry *overlap_list[E820MAX] __initdata;static struct e820entry new_bios[E820MAX] __initdata;static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map){ struct change_member *change_tmp; unsigned long current_type, last_type; unsigned long long last_addr; int chgidx, still_changing; int overlap_entries; int new_bios_entry; int old_nr, new_nr, chg_nr; int i; /* Visually we're performing the following (1,2,3,4 = memory types)... Sample memory map (w/overlaps): ____22__________________ ______________________4_ ____1111________________ _44_____________________ 11111111________________ ____________________33__ ___________44___________ __________33333_________ ______________22________ ___________________2222_ _________111111111______ _____________________11_ _________________4______ Sanitized equivalent (no overlap): 1_______________________ _44_____________________ ___1____________________ ____22__________________ ______11________________ _________1______________ __________3_____________ ___________44___________ _____________33_________ _______________2________ ________________1_______ _________________4______ ___________________2____ ____________________33__ ______________________4_ */ /* if there's only one memory region, don't bother */ if (*pnr_map < 2) return -1; old_nr = *pnr_map; /* bail out if we find any unreasonable addresses in bios map */ for (i=0; i<old_nr; i++) if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) return -1; /* create pointers for initial change-point information (for sorting) */ for (i=0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; /* record all known change-points (starting and ending addresses), omitting those that are for empty memory regions */ chgidx = 0; for (i=0; i < old_nr; i++) { if (biosmap[i].size != 0) { change_point[chgidx]->addr = biosmap[i].addr; change_point[chgidx++]->pbios = &biosmap[i]; change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; change_point[chgidx++]->pbios = &biosmap[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -